* [PATCH v8 00/12] Add DisplayPort support for QCS615 platform
@ 2025-12-15 12:41 Xiangxu Yin via B4 Relay
2025-12-15 12:41 ` [PATCH v8 01/12] dt-bindings: phy: Add QMP USB3+DP PHY for QCS615 Xiangxu Yin via B4 Relay
` (11 more replies)
0 siblings, 12 replies; 13+ messages in thread
From: Xiangxu Yin via B4 Relay @ 2025-12-15 12:41 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, fange.zhang,
yongxing.mou, li.liu, tingwei.zhang, Dmitry Baryshkov,
Bjorn Andersson, Konrad Dybcio, Xiangxu Yin, Konrad Dybcio
This series aims to extend the USB-C PHY to support DP mode and enable
DisplayPort on the Qualcomm QCS615 platform.
The devicetree modification for DisplayPort on QCS615 will be provided
in a future patch.
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
Changes in v8:
- Fix `--strict` nits: indent alignment in v7[04/14]; extra blank line in v7[06/14]
- Link to v7: https://lore.kernel.org/r/20250926-add-displayport-support-for-qcs615-platform-v7-0-dc5edaac6c2b@oss.qualcomm.com
Changes in v7:
- Fix QSERDES_V2_TX_LANE_MODE_1 configuration from COM init table to configure_dp_tx().
- Link to v6: https://lore.kernel.org/r/20250925-add-displayport-support-for-qcs615-platform-v6-0-419fe5963819@oss.qualcomm.com
Changes in v6:
- Move usb3dpphy_reset_l definition to the patch adding compatible and related config data. [Dmitry]
- Add NOTE about SW_PORTSELECT/orientation handling. [Dmitry]
- Use C99-style loop variable declaration in msm_dp_link_lane_map. [Rob]
- Update commit msg with issue description for [05/14, 06/14, 07/14,12/14].
- Link to v5: https://lore.kernel.org/r/20250919-add-displayport-support-for-qcs615-platform-v5-0-eae6681f4002@oss.qualcomm.com
Changes in v5:
- Add new patch to introduce QSERDES v2 COM/TXRX register headers.
- Restore legacy reset & clock register logic. [Dmitry]
- Update phy_xlate() to return ERR_PTR(-ENODEV) when dp_phy is NULL. [Dmitry]
- Rename helper from qmp_check_mutex_phy() to qmp_usbc_check_phy_status(). [Dmitry]
- Drop storing struct device *dev in dp_link as it is only used once. [Dmitry]
- Add robust lane mapping: default 1:1, complete partial configs. [Dmitry]
- Reorganize sub-patches v5[07/14, 08/14, 11/14, 12/14] as suggested.
- Link to v4: https://lore.kernel.org/all/20250911-add-displayport-support-for-qcs615-platform-v4-0-2702bdda14ed@oss.qualcomm.com/
Changes in v4:
- Drop patch v3[01/14 & 13/14], will sutbmit new patchsets based mst dt binding series.
- Update maintainer of qcom,qcs615-qmp-usb3dp-phy.yaml to myself.
- Add missing aux and pipe clocks. [Dmitry]
- Drop second TCSR phandle; register offsets are described directly. [Dmitry]
- Add USBC PHY series related init_load_uA configs. [Dmitry]
- Drop v3[04/14] qmp_phy_usbc_type define and use dp_serdes offsets to confirm DP capability [Dmitry]
- Reorganize sub-patches as suggested.
- Link to v3: https://lore.kernel.org/all/20250820-add-displayport-support-for-qcs615-platform-v3-0-a43bd25ec39c@oss.qualcomm.com/
Changes in v3:
- Renamed qcom,qcs615-qmp-dp-phy.yaml in v2 to qcom,qcs615-qmp-dp-phy.yaml in v3 for QCS615 USB3+DP PHY.
- Updated patch v3[02/14] to revise binding title, description, and property order. [Krzysztof]
- Updated commit messages in patch v3[01/14] and [13/14] to reflect the DTSI rename and clarify compatibility. [Krzysztof]
- Added USB3+DP mode implementation in patches v3 [003–012], organized in logical chunks. [Dmitry]
- Dropped patch v2[03/13] to maintain full backward compatibility with USBC.
- Link to v2: https://lore.kernel.org/all/20250722-add-displayport-support-for-qcs615-platform-v2-0-42b4037171f8@oss.qualcomm.com/
Changes in v2:
- Add new binding qcom,qcs615-qmp-dp-phy.yaml for QCS615 standalone DP
- Split DP PHY driver into patches 4-11 by logical chunks [Dmitry]
- Update DP PHY configuration flow to align with QMP Combo PHY implementation [Dmitry]
- Update all hex values to lowercase [Dmitry]
- Remove redundant comments in DP PHY driver [Krzysztof]
- Remove invalid USBC type define [Dmitry]
- Move lane_map, max_dp_lanes, max_dp_link_rate parsing logic to dp_link [Dmitry]
- Add TCSR-based mutex logic for DP and USB PHY coexistence [Dmitry]
- Drop patches 6–8 and remove related binding properties as rejected upstream
- Link to v1: https://lore.kernel.org/all/20241129-add-displayport-support-for-qcs615-platform-v1-0-09a4338d93ef@quicinc.com/
---
Xiangxu Yin (12):
dt-bindings: phy: Add QMP USB3+DP PHY for QCS615
phy: qcom: qmp-usbc: Rename USB-specific ops to prepare for DP support
phy: qcom: qmp-usbc: Add DP-related fields for USB/DP switchable PHY
phy: qcom: qmp-usbc: Add regulator init_load support
phy: qcom: qmp-usbc: Move reset config into PHY cfg
phy: qcom: qmp-usbc: add DP link and vco_div clocks for DP PHY
phy: qcom: qmp-usbc: Move USB-only init to usb_power_on
phy: qcom: qmp-usbc: Add TCSR parsing and PHY mode setting
phy: qcom: qmp-usbc: Add DP PHY ops for USB/DP switchable Type-C PHYs
phy: qcom: qmp-usbc: Add USB/DP exclude handling
phy: qcom: qmp: Add DP v2 PHY register definitions
phy: qcom: qmp-usbc: Add QCS615 USB/DP PHY config and DP mode support
.../bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml | 111 ++
drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h | 21 +
drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h | 106 ++
.../phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h | 68 ++
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 1071 ++++++++++++++++++--
drivers/phy/qualcomm/phy-qcom-qmp.h | 3 +
6 files changed, 1289 insertions(+), 91 deletions(-)
---
base-commit: 4a5663c04bb679631985a15efab774da58c37815
change-id: 20250919-add-displayport-support-for-qcs615-platform-f885597b3573
Best regards,
--
Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v8 01/12] dt-bindings: phy: Add QMP USB3+DP PHY for QCS615
2025-12-15 12:41 [PATCH v8 00/12] Add DisplayPort support for QCS615 platform Xiangxu Yin via B4 Relay
@ 2025-12-15 12:41 ` Xiangxu Yin via B4 Relay
2025-12-15 12:41 ` [PATCH v8 02/12] phy: qcom: qmp-usbc: Rename USB-specific ops to prepare for DP support Xiangxu Yin via B4 Relay
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Xiangxu Yin via B4 Relay @ 2025-12-15 12:41 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, fange.zhang,
yongxing.mou, li.liu, tingwei.zhang, Dmitry Baryshkov,
Bjorn Andersson, Konrad Dybcio, Xiangxu Yin
From: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
Add device tree binding documentation for the Qualcomm QMP USB3+DP PHY
on QCS615 Platform. This PHY supports both USB3 and DP functionality
over USB-C, with PHY mode switching capability. It does not support
combo mode.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
.../bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml | 111 +++++++++++++++++++++
1 file changed, 111 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml
new file mode 100644
index 000000000000..efb465c71c1b
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml
@@ -0,0 +1,111 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/qcom,qcs615-qmp-usb3dp-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QMP USB3-DP PHY controller (DP, QCS615)
+
+maintainers:
+ - Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
+
+description:
+ The QMP PHY controller supports physical layer functionality for both USB3
+ and DisplayPort over USB-C. While it enables mode switching between USB3 and
+ DisplayPort, but does not support combo mode.
+
+properties:
+ compatible:
+ enum:
+ - qcom,qcs615-qmp-usb3-dp-phy
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 4
+
+ clock-names:
+ items:
+ - const: aux
+ - const: ref
+ - const: cfg_ahb
+ - const: pipe
+
+ resets:
+ maxItems: 2
+
+ reset-names:
+ items:
+ - const: phy_phy
+ - const: dp_phy
+
+ vdda-phy-supply: true
+
+ vdda-pll-supply: true
+
+ "#clock-cells":
+ const: 1
+ description:
+ See include/dt-bindings/phy/phy-qcom-qmp.h
+
+ "#phy-cells":
+ const: 1
+ description:
+ See include/dt-bindings/phy/phy-qcom-qmp.h
+
+ qcom,tcsr-reg:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ - items:
+ - description: phandle to TCSR hardware block
+ - description: offset of the VLS CLAMP register
+ - description: offset of the PHY mode register
+ description: Clamp and PHY mode register present in the TCSR
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - vdda-phy-supply
+ - vdda-pll-supply
+ - "#clock-cells"
+ - "#phy-cells"
+ - qcom,tcsr-reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,qcs615-gcc.h>
+ #include <dt-bindings/clock/qcom,rpmh.h>
+
+ phy@88e8000 {
+ compatible = "qcom,qcs615-qmp-usb3-dp-phy";
+ reg = <0x88e8000 0x2000>;
+
+ clocks = <&gcc GCC_USB2_SEC_PHY_AUX_CLK>,
+ <&gcc GCC_USB3_SEC_CLKREF_CLK>,
+ <&gcc GCC_AHB2PHY_WEST_CLK>,
+ <&gcc GCC_USB2_SEC_PHY_PIPE_CLK>;
+ clock-names = "aux",
+ "ref",
+ "cfg_ahb",
+ "pipe";
+
+ resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>,
+ <&gcc GCC_USB3_DP_PHY_SEC_BCR>;
+ reset-names = "phy_phy",
+ "dp_phy";
+
+ vdda-phy-supply = <&vreg_l5a>;
+ vdda-pll-supply = <&vreg_l12a>;
+
+ #clock-cells = <1>;
+ #phy-cells = <1>;
+
+ qcom,tcsr-reg = <&tcsr 0xbff0 0xb24c>;
+ };
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v8 02/12] phy: qcom: qmp-usbc: Rename USB-specific ops to prepare for DP support
2025-12-15 12:41 [PATCH v8 00/12] Add DisplayPort support for QCS615 platform Xiangxu Yin via B4 Relay
2025-12-15 12:41 ` [PATCH v8 01/12] dt-bindings: phy: Add QMP USB3+DP PHY for QCS615 Xiangxu Yin via B4 Relay
@ 2025-12-15 12:41 ` Xiangxu Yin via B4 Relay
2025-12-15 12:41 ` [PATCH v8 03/12] phy: qcom: qmp-usbc: Add DP-related fields for USB/DP switchable PHY Xiangxu Yin via B4 Relay
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Xiangxu Yin via B4 Relay @ 2025-12-15 12:41 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, fange.zhang,
yongxing.mou, li.liu, tingwei.zhang, Dmitry Baryshkov,
Bjorn Andersson, Konrad Dybcio, Xiangxu Yin
From: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
To support following DisplayPort (DP) mode over the Type-C PHY, rename
USB-specific functions and ops to clearly separate them from common or
DP-related logic.
This is a preparatory cleanup to enable USB + DP dual mode.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 55 ++++++++++++++++----------------
1 file changed, 27 insertions(+), 28 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index 5e7fcb26744a..62920dd2aed3 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -342,11 +342,10 @@ struct qmp_usbc {
struct mutex phy_mutex;
+ struct phy *usb_phy;
enum phy_mode mode;
unsigned int usb_init_count;
- struct phy *phy;
-
struct clk_fixed_rate pipe_clk_fixed;
struct typec_switch_dev *sw;
@@ -454,7 +453,7 @@ static const struct qmp_phy_cfg sdm660_usb3phy_cfg = {
.regs = qmp_v3_usb3phy_regs_layout_qcm2290,
};
-static int qmp_usbc_init(struct phy *phy)
+static int qmp_usbc_com_init(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -504,7 +503,7 @@ static int qmp_usbc_init(struct phy *phy)
return ret;
}
-static int qmp_usbc_exit(struct phy *phy)
+static int qmp_usbc_com_exit(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -518,7 +517,7 @@ static int qmp_usbc_exit(struct phy *phy)
return 0;
}
-static int qmp_usbc_power_on(struct phy *phy)
+static int qmp_usbc_usb_power_on(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -566,7 +565,7 @@ static int qmp_usbc_power_on(struct phy *phy)
return ret;
}
-static int qmp_usbc_power_off(struct phy *phy)
+static int qmp_usbc_usb_power_off(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -587,20 +586,20 @@ static int qmp_usbc_power_off(struct phy *phy)
return 0;
}
-static int qmp_usbc_enable(struct phy *phy)
+static int qmp_usbc_usb_enable(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
int ret;
mutex_lock(&qmp->phy_mutex);
- ret = qmp_usbc_init(phy);
+ ret = qmp_usbc_com_init(phy);
if (ret)
goto out_unlock;
- ret = qmp_usbc_power_on(phy);
+ ret = qmp_usbc_usb_power_on(phy);
if (ret) {
- qmp_usbc_exit(phy);
+ qmp_usbc_com_exit(phy);
goto out_unlock;
}
@@ -611,19 +610,19 @@ static int qmp_usbc_enable(struct phy *phy)
return ret;
}
-static int qmp_usbc_disable(struct phy *phy)
+static int qmp_usbc_usb_disable(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
int ret;
qmp->usb_init_count--;
- ret = qmp_usbc_power_off(phy);
+ ret = qmp_usbc_usb_power_off(phy);
if (ret)
return ret;
- return qmp_usbc_exit(phy);
+ return qmp_usbc_com_exit(phy);
}
-static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+static int qmp_usbc_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
@@ -632,10 +631,10 @@ static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode)
return 0;
}
-static const struct phy_ops qmp_usbc_phy_ops = {
- .init = qmp_usbc_enable,
- .exit = qmp_usbc_disable,
- .set_mode = qmp_usbc_set_mode,
+static const struct phy_ops qmp_usbc_usb_phy_ops = {
+ .init = qmp_usbc_usb_enable,
+ .exit = qmp_usbc_usb_disable,
+ .set_mode = qmp_usbc_usb_set_mode,
.owner = THIS_MODULE,
};
@@ -690,7 +689,7 @@ static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev)
dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode);
- if (!qmp->phy->init_count) {
+ if (!qmp->usb_init_count) {
dev_vdbg(dev, "PHY not initialized, bailing out\n");
return 0;
}
@@ -710,7 +709,7 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev)
dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode);
- if (!qmp->phy->init_count) {
+ if (!qmp->usb_init_count) {
dev_vdbg(dev, "PHY not initialized, bailing out\n");
return 0;
}
@@ -865,11 +864,11 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw,
qmp->orientation = orientation;
if (qmp->usb_init_count) {
- qmp_usbc_power_off(qmp->phy);
- qmp_usbc_exit(qmp->phy);
+ qmp_usbc_usb_power_off(qmp->usb_phy);
+ qmp_usbc_com_exit(qmp->usb_phy);
- qmp_usbc_init(qmp->phy);
- qmp_usbc_power_on(qmp->phy);
+ qmp_usbc_com_init(qmp->usb_phy);
+ qmp_usbc_usb_power_on(qmp->usb_phy);
}
mutex_unlock(&qmp->phy_mutex);
@@ -1097,14 +1096,14 @@ static int qmp_usbc_probe(struct platform_device *pdev)
if (ret)
goto err_node_put;
- qmp->phy = devm_phy_create(dev, np, &qmp_usbc_phy_ops);
- if (IS_ERR(qmp->phy)) {
- ret = PTR_ERR(qmp->phy);
+ qmp->usb_phy = devm_phy_create(dev, np, &qmp_usbc_usb_phy_ops);
+ if (IS_ERR(qmp->usb_phy)) {
+ ret = PTR_ERR(qmp->usb_phy);
dev_err(dev, "failed to create PHY: %d\n", ret);
goto err_node_put;
}
- phy_set_drvdata(qmp->phy, qmp);
+ phy_set_drvdata(qmp->usb_phy, qmp);
of_node_put(np);
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v8 03/12] phy: qcom: qmp-usbc: Add DP-related fields for USB/DP switchable PHY
2025-12-15 12:41 [PATCH v8 00/12] Add DisplayPort support for QCS615 platform Xiangxu Yin via B4 Relay
2025-12-15 12:41 ` [PATCH v8 01/12] dt-bindings: phy: Add QMP USB3+DP PHY for QCS615 Xiangxu Yin via B4 Relay
2025-12-15 12:41 ` [PATCH v8 02/12] phy: qcom: qmp-usbc: Rename USB-specific ops to prepare for DP support Xiangxu Yin via B4 Relay
@ 2025-12-15 12:41 ` Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 04/12] phy: qcom: qmp-usbc: Add regulator init_load support Xiangxu Yin via B4 Relay
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Xiangxu Yin via B4 Relay @ 2025-12-15 12:41 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, fange.zhang,
yongxing.mou, li.liu, tingwei.zhang, Dmitry Baryshkov,
Bjorn Andersson, Konrad Dybcio, Xiangxu Yin
From: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
Extend qmp_usbc_offsets and qmp_phy_cfg with DP-specific fields,
including register offsets, init tables, and callback hooks. Also
update qmp_usbc struct to track DP-related resources and state.
This enables support for USB/DP switchable Type-C PHYs that operate
in either mode.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 54 +++++++++++++++++++++++++++-----
1 file changed, 46 insertions(+), 8 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index 62920dd2aed3..de28c3464a40 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -293,13 +293,18 @@ struct qmp_usbc_offsets {
/* for PHYs with >= 2 lanes */
u16 tx2;
u16 rx2;
+
+ u16 dp_serdes;
+ u16 dp_txa;
+ u16 dp_txb;
+ u16 dp_dp_phy;
};
-/* struct qmp_phy_cfg - per-PHY initialization config */
+struct qmp_usbc;
struct qmp_phy_cfg {
const struct qmp_usbc_offsets *offsets;
- /* Init sequence for PHY blocks - serdes, tx, rx, pcs */
+ /* Init sequence for USB PHY blocks - serdes, tx, rx, pcs */
const struct qmp_phy_init_tbl *serdes_tbl;
int serdes_tbl_num;
const struct qmp_phy_init_tbl *tx_tbl;
@@ -309,6 +314,27 @@ struct qmp_phy_cfg {
const struct qmp_phy_init_tbl *pcs_tbl;
int pcs_tbl_num;
+ /* Init sequence for DP PHY blocks - serdes, tx, rbr, hbr, hbr2 */
+ const struct qmp_phy_init_tbl *dp_serdes_tbl;
+ int dp_serdes_tbl_num;
+ const struct qmp_phy_init_tbl *dp_tx_tbl;
+ int dp_tx_tbl_num;
+ const struct qmp_phy_init_tbl *serdes_tbl_rbr;
+ int serdes_tbl_rbr_num;
+ const struct qmp_phy_init_tbl *serdes_tbl_hbr;
+ int serdes_tbl_hbr_num;
+ const struct qmp_phy_init_tbl *serdes_tbl_hbr2;
+ int serdes_tbl_hbr2_num;
+
+ const u8 (*swing_tbl)[4][4];
+ const u8 (*pre_emphasis_tbl)[4][4];
+
+ /* DP PHY callbacks */
+ void (*dp_aux_init)(struct qmp_usbc *qmp);
+ void (*configure_dp_tx)(struct qmp_usbc *qmp);
+ int (*configure_dp_phy)(struct qmp_usbc *qmp);
+ int (*calibrate_dp_phy)(struct qmp_usbc *qmp);
+
/* regulators to be requested */
const char * const *vreg_list;
int num_vregs;
@@ -329,24 +355,36 @@ struct qmp_usbc {
void __iomem *rx;
void __iomem *tx2;
void __iomem *rx2;
-
- struct regmap *tcsr_map;
- u32 vls_clamp_reg;
+ void __iomem *dp_dp_phy;
+ void __iomem *dp_tx;
+ void __iomem *dp_tx2;
+ void __iomem *dp_serdes;
struct clk *pipe_clk;
+ struct clk_fixed_rate pipe_clk_fixed;
+
+ struct clk_hw dp_link_hw;
+ struct clk_hw dp_pixel_hw;
struct clk_bulk_data *clks;
int num_clks;
int num_resets;
struct reset_control_bulk_data *resets;
struct regulator_bulk_data *vregs;
+ struct regmap *tcsr_map;
+ u32 vls_clamp_reg;
+ u32 dp_phy_mode_reg;
+
struct mutex phy_mutex;
struct phy *usb_phy;
enum phy_mode mode;
unsigned int usb_init_count;
- struct clk_fixed_rate pipe_clk_fixed;
+ struct phy *dp_phy;
+ unsigned int dp_aux_cfg;
+ struct phy_configure_opts_dp dp_opts;
+ unsigned int dp_init_count;
struct typec_switch_dev *sw;
enum typec_orientation orientation;
@@ -689,7 +727,7 @@ static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev)
dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode);
- if (!qmp->usb_init_count) {
+ if (!qmp->usb_init_count && !qmp->dp_init_count) {
dev_vdbg(dev, "PHY not initialized, bailing out\n");
return 0;
}
@@ -709,7 +747,7 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev)
dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode);
- if (!qmp->usb_init_count) {
+ if (!qmp->usb_init_count && !qmp->dp_init_count) {
dev_vdbg(dev, "PHY not initialized, bailing out\n");
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v8 04/12] phy: qcom: qmp-usbc: Add regulator init_load support
2025-12-15 12:41 [PATCH v8 00/12] Add DisplayPort support for QCS615 platform Xiangxu Yin via B4 Relay
` (2 preceding siblings ...)
2025-12-15 12:41 ` [PATCH v8 03/12] phy: qcom: qmp-usbc: Add DP-related fields for USB/DP switchable PHY Xiangxu Yin via B4 Relay
@ 2025-12-15 12:42 ` Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 05/12] phy: qcom: qmp-usbc: Move reset config into PHY cfg Xiangxu Yin via B4 Relay
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Xiangxu Yin via B4 Relay @ 2025-12-15 12:42 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, fange.zhang,
yongxing.mou, li.liu, tingwei.zhang, Dmitry Baryshkov,
Bjorn Andersson, Konrad Dybcio, Xiangxu Yin
From: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
QMP USBC PHY drivers previously did not set init_load_uA for regulators,
which could result in incorrect vote levels. This patch introduces
regulator definitions with proper init_load_uA values based on each
chip's power grid design.
QCS615 USB3 PHY was previously reusing qcm2290_usb3phy_cfg, but its
regulator requirements differ. A new qcs615_usb3phy_cfg is added to
reflect the correct settings.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 68 ++++++++++++++++++--------------
1 file changed, 39 insertions(+), 29 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index de28c3464a40..2c998803fcda 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -336,7 +336,7 @@ struct qmp_phy_cfg {
int (*calibrate_dp_phy)(struct qmp_usbc *qmp);
/* regulators to be requested */
- const char * const *vreg_list;
+ const struct regulator_bulk_data *vreg_list;
int num_vregs;
/* array of registers with different offsets */
@@ -428,9 +428,19 @@ static const char * const usb3phy_reset_l[] = {
"phy_phy", "phy",
};
-/* list of regulators */
-static const char * const qmp_phy_vreg_l[] = {
- "vdda-phy", "vdda-pll",
+static const struct regulator_bulk_data qmp_phy_msm8998_vreg_l[] = {
+ { .supply = "vdda-phy", .init_load_uA = 68600 },
+ { .supply = "vdda-pll", .init_load_uA = 14200 },
+};
+
+static const struct regulator_bulk_data qmp_phy_sm2290_vreg_l[] = {
+ { .supply = "vdda-phy", .init_load_uA = 66100 },
+ { .supply = "vdda-pll", .init_load_uA = 13300 },
+};
+
+static const struct regulator_bulk_data qmp_phy_qcs615_vreg_l[] = {
+ { .supply = "vdda-phy", .init_load_uA = 50000 },
+ { .supply = "vdda-pll", .init_load_uA = 20000 },
};
static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {
@@ -454,8 +464,8 @@ static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
.rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl),
.pcs_tbl = msm8998_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl),
- .vreg_list = qmp_phy_vreg_l,
- .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .vreg_list = qmp_phy_msm8998_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout,
};
@@ -470,8 +480,8 @@ static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = {
.rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl),
.pcs_tbl = qcm2290_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl),
- .vreg_list = qmp_phy_vreg_l,
- .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .vreg_list = qmp_phy_sm2290_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_sm2290_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout_qcm2290,
};
@@ -486,8 +496,24 @@ static const struct qmp_phy_cfg sdm660_usb3phy_cfg = {
.rx_tbl_num = ARRAY_SIZE(sdm660_usb3_rx_tbl),
.pcs_tbl = qcm2290_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl),
- .vreg_list = qmp_phy_vreg_l,
- .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .vreg_list = qmp_phy_msm8998_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l),
+ .regs = qmp_v3_usb3phy_regs_layout_qcm2290,
+};
+
+static const struct qmp_phy_cfg qcs615_usb3phy_cfg = {
+ .offsets = &qmp_usbc_offsets_v3_qcm2290,
+
+ .serdes_tbl = qcm2290_usb3_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
+ .tx_tbl = qcm2290_usb3_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl),
+ .rx_tbl = qcm2290_usb3_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl),
+ .pcs_tbl = qcm2290_usb3_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl),
+ .vreg_list = qmp_phy_qcs615_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_qcs615_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout_qcm2290,
};
@@ -773,23 +799,6 @@ static const struct dev_pm_ops qmp_usbc_pm_ops = {
qmp_usbc_runtime_resume, NULL)
};
-static int qmp_usbc_vreg_init(struct qmp_usbc *qmp)
-{
- const struct qmp_phy_cfg *cfg = qmp->cfg;
- struct device *dev = qmp->dev;
- int num = cfg->num_vregs;
- int i;
-
- qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL);
- if (!qmp->vregs)
- return -ENOMEM;
-
- for (i = 0; i < num; i++)
- qmp->vregs[i].supply = cfg->vreg_list[i];
-
- return devm_regulator_bulk_get(dev, num, qmp->vregs);
-}
-
static int qmp_usbc_reset_init(struct qmp_usbc *qmp,
const char *const *reset_list,
int num_resets)
@@ -1097,7 +1106,8 @@ static int qmp_usbc_probe(struct platform_device *pdev)
mutex_init(&qmp->phy_mutex);
- ret = qmp_usbc_vreg_init(qmp);
+ ret = devm_regulator_bulk_get_const(qmp->dev, qmp->cfg->num_vregs,
+ qmp->cfg->vreg_list, &qmp->vregs);
if (ret)
return ret;
@@ -1163,7 +1173,7 @@ static const struct of_device_id qmp_usbc_of_match_table[] = {
.data = &qcm2290_usb3phy_cfg,
}, {
.compatible = "qcom,qcs615-qmp-usb3-phy",
- .data = &qcm2290_usb3phy_cfg,
+ .data = &qcs615_usb3phy_cfg,
}, {
.compatible = "qcom,sdm660-qmp-usb3-phy",
.data = &sdm660_usb3phy_cfg,
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v8 05/12] phy: qcom: qmp-usbc: Move reset config into PHY cfg
2025-12-15 12:41 [PATCH v8 00/12] Add DisplayPort support for QCS615 platform Xiangxu Yin via B4 Relay
` (3 preceding siblings ...)
2025-12-15 12:42 ` [PATCH v8 04/12] phy: qcom: qmp-usbc: Add regulator init_load support Xiangxu Yin via B4 Relay
@ 2025-12-15 12:42 ` Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 06/12] phy: qcom: qmp-usbc: add DP link and vco_div clocks for DP PHY Xiangxu Yin via B4 Relay
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Xiangxu Yin via B4 Relay @ 2025-12-15 12:42 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, fange.zhang,
yongxing.mou, li.liu, tingwei.zhang, Dmitry Baryshkov,
Bjorn Andersson, Konrad Dybcio, Xiangxu Yin
From: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
The original reset list only works for USB-only PHYs. USB3DP PHYs require
different reset names such as "dp_phy", so they need a separate list.
Moving reset configuration into qmp_phy_cfg allows per-PHY customization
without adding special-case logic in DT parsing. The legacy DT path keeps
using the old hardcoded list, while non-legacy paths use cfg->reset_list.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index 2c998803fcda..cff148dc9f01 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -335,7 +335,8 @@ struct qmp_phy_cfg {
int (*configure_dp_phy)(struct qmp_usbc *qmp);
int (*calibrate_dp_phy)(struct qmp_usbc *qmp);
- /* regulators to be requested */
+ const char * const *reset_list;
+ int num_resets;
const struct regulator_bulk_data *vreg_list;
int num_vregs;
@@ -464,6 +465,8 @@ static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
.rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl),
.pcs_tbl = msm8998_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl),
+ .reset_list = usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(usb3phy_reset_l),
.vreg_list = qmp_phy_msm8998_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout,
@@ -480,6 +483,8 @@ static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = {
.rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl),
.pcs_tbl = qcm2290_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl),
+ .reset_list = usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(usb3phy_reset_l),
.vreg_list = qmp_phy_sm2290_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_sm2290_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout_qcm2290,
@@ -496,6 +501,8 @@ static const struct qmp_phy_cfg sdm660_usb3phy_cfg = {
.rx_tbl_num = ARRAY_SIZE(sdm660_usb3_rx_tbl),
.pcs_tbl = qcm2290_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl),
+ .reset_list = usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(usb3phy_reset_l),
.vreg_list = qmp_phy_msm8998_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout_qcm2290,
@@ -512,6 +519,8 @@ static const struct qmp_phy_cfg qcs615_usb3phy_cfg = {
.rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl),
.pcs_tbl = qcm2290_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl),
+ .reset_list = usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(usb3phy_reset_l),
.vreg_list = qmp_phy_qcs615_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_qcs615_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout_qcm2290,
@@ -1051,8 +1060,7 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
"failed to get pipe clock\n");
}
- ret = qmp_usbc_reset_init(qmp, usb3phy_reset_l,
- ARRAY_SIZE(usb3phy_reset_l));
+ ret = qmp_usbc_reset_init(qmp, cfg->reset_list, cfg->num_resets);
if (ret)
return ret;
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v8 06/12] phy: qcom: qmp-usbc: add DP link and vco_div clocks for DP PHY
2025-12-15 12:41 [PATCH v8 00/12] Add DisplayPort support for QCS615 platform Xiangxu Yin via B4 Relay
` (4 preceding siblings ...)
2025-12-15 12:42 ` [PATCH v8 05/12] phy: qcom: qmp-usbc: Move reset config into PHY cfg Xiangxu Yin via B4 Relay
@ 2025-12-15 12:42 ` Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 07/12] phy: qcom: qmp-usbc: Move USB-only init to usb_power_on Xiangxu Yin via B4 Relay
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Xiangxu Yin via B4 Relay @ 2025-12-15 12:42 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, fange.zhang,
yongxing.mou, li.liu, tingwei.zhang, Dmitry Baryshkov,
Bjorn Andersson, Konrad Dybcio, Xiangxu Yin
From: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
USB3DP PHY requires link and vco_div clocks when operating in DP mode.
Extend qmp_usbc_register_clocks and the clock provider logic to register
these clocks along with the existing pipe clock, to support both USB and
DP configurations.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 209 ++++++++++++++++++++++++++++++-
1 file changed, 203 insertions(+), 6 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index cff148dc9f01..a6431e6d5586 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/usb/typec.h>
#include <linux/usb/typec_mux.h>
+#include <dt-bindings/phy/phy-qcom-qmp.h>
#include "phy-qcom-qmp-common.h"
@@ -851,9 +852,23 @@ static int qmp_usbc_clk_init(struct qmp_usbc *qmp)
return devm_clk_bulk_get_optional(dev, num, qmp->clks);
}
-static void phy_clk_release_provider(void *res)
+static struct clk_hw *qmp_usbc_clks_hw_get(struct of_phandle_args *clkspec, void *data)
{
- of_clk_del_provider(res);
+ struct qmp_usbc *qmp = data;
+
+ if (clkspec->args_count == 0)
+ return &qmp->pipe_clk_fixed.hw;
+
+ switch (clkspec->args[0]) {
+ case QMP_USB43DP_USB3_PIPE_CLK:
+ return &qmp->pipe_clk_fixed.hw;
+ case QMP_USB43DP_DP_LINK_CLK:
+ return &qmp->dp_link_hw;
+ case QMP_USB43DP_DP_VCO_DIV_CLK:
+ return &qmp->dp_pixel_hw;
+ }
+
+ return ERR_PTR(-EINVAL);
}
/*
@@ -878,12 +893,14 @@ static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np)
{
struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed;
struct clk_init_data init = { };
+ char name[64];
int ret;
ret = of_property_read_string(np, "clock-output-names", &init.name);
if (ret) {
- dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np);
- return ret;
+ /* Clock name is not mandatory. */
+ snprintf(name, sizeof(name), "%s::pipe_clk", dev_name(qmp->dev));
+ init.name = name;
}
init.ops = &clk_fixed_rate_ops;
@@ -892,10 +909,183 @@ static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np)
fixed->fixed_rate = 125000000;
fixed->hw.init = &init;
- ret = devm_clk_hw_register(qmp->dev, &fixed->hw);
+ return devm_clk_hw_register(qmp->dev, &fixed->hw);
+}
+
+/*
+ * Display Port PLL driver block diagram for branch clocks
+ *
+ * +------------------------------+
+ * | DP_VCO_CLK |
+ * | |
+ * | +-------------------+ |
+ * | | (DP PLL/VCO) | |
+ * | +---------+---------+ |
+ * | v |
+ * | +----------+-----------+ |
+ * | | hsclk_divsel_clk_src | |
+ * | +----------+-----------+ |
+ * +------------------------------+
+ * |
+ * +---------<---------v------------>----------+
+ * | |
+ * +--------v----------------+ |
+ * | dp_phy_pll_link_clk | |
+ * | link_clk | |
+ * +--------+----------------+ |
+ * | |
+ * | |
+ * v v
+ * Input to DISPCC block |
+ * for link clk, crypto clk |
+ * and interface clock |
+ * |
+ * |
+ * +--------<------------+-----------------+---<---+
+ * | | |
+ * +----v---------+ +--------v-----+ +--------v------+
+ * | vco_divided | | vco_divided | | vco_divided |
+ * | _clk_src | | _clk_src | | _clk_src |
+ * | | | | | |
+ * |divsel_six | | divsel_two | | divsel_four |
+ * +-------+------+ +-----+--------+ +--------+------+
+ * | | |
+ * v---->----------v-------------<------v
+ * |
+ * +----------+-----------------+
+ * | dp_phy_pll_vco_div_clk |
+ * +---------+------------------+
+ * |
+ * v
+ * Input to DISPCC block
+ * for DP pixel clock
+ *
+ */
+static int qmp_dp_pixel_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ switch (req->rate) {
+ case 1620000000UL / 2:
+ case 2700000000UL / 2:
+ /* 5.4 is same link rate as 2.7GHz, i.e. div 4 */
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static unsigned long qmp_dp_pixel_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ const struct qmp_usbc *qmp;
+ const struct phy_configure_opts_dp *dp_opts;
+
+ qmp = container_of(hw, struct qmp_usbc, dp_pixel_hw);
+
+ dp_opts = &qmp->dp_opts;
+
+ switch (dp_opts->link_rate) {
+ case 1620:
+ return 1620000000UL / 2;
+ case 2700:
+ return 2700000000UL / 2;
+ case 5400:
+ return 5400000000UL / 4;
+ default:
+ return 0;
+ }
+}
+
+static const struct clk_ops qmp_dp_pixel_clk_ops = {
+ .determine_rate = qmp_dp_pixel_clk_determine_rate,
+ .recalc_rate = qmp_dp_pixel_clk_recalc_rate,
+};
+
+static int qmp_dp_link_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ switch (req->rate) {
+ case 162000000:
+ case 270000000:
+ case 540000000:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static unsigned long qmp_dp_link_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ const struct qmp_usbc *qmp;
+ const struct phy_configure_opts_dp *dp_opts;
+
+ qmp = container_of(hw, struct qmp_usbc, dp_link_hw);
+ dp_opts = &qmp->dp_opts;
+
+ switch (dp_opts->link_rate) {
+ case 1620:
+ case 2700:
+ case 5400:
+ return dp_opts->link_rate * 100000;
+ default:
+ return 0;
+ }
+}
+
+static const struct clk_ops qmp_dp_link_clk_ops = {
+ .determine_rate = qmp_dp_link_clk_determine_rate,
+ .recalc_rate = qmp_dp_link_clk_recalc_rate,
+};
+
+static int phy_dp_clks_register(struct qmp_usbc *qmp, struct device_node *np)
+{
+ struct clk_init_data init = { };
+ char name[64];
+ int ret;
+
+ snprintf(name, sizeof(name), "%s::link_clk", dev_name(qmp->dev));
+ init.ops = &qmp_dp_link_clk_ops;
+ init.name = name;
+ qmp->dp_link_hw.init = &init;
+ ret = devm_clk_hw_register(qmp->dev, &qmp->dp_link_hw);
+ if (ret < 0) {
+ dev_err(qmp->dev, "link clk reg fail ret=%d\n", ret);
+ return ret;
+ }
+
+ snprintf(name, sizeof(name), "%s::vco_div_clk", dev_name(qmp->dev));
+ init.ops = &qmp_dp_pixel_clk_ops;
+ init.name = name;
+ qmp->dp_pixel_hw.init = &init;
+ ret = devm_clk_hw_register(qmp->dev, &qmp->dp_pixel_hw);
+ if (ret) {
+ dev_err(qmp->dev, "pxl clk reg fail ret=%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void phy_clk_release_provider(void *res)
+{
+ of_clk_del_provider(res);
+}
+
+static int qmp_usbc_register_clocks(struct qmp_usbc *qmp, struct device_node *np)
+{
+ struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed;
+ int ret;
+
+ ret = phy_pipe_clk_register(qmp, np);
if (ret)
return ret;
+ if (qmp->dp_serdes != 0) {
+ ret = phy_dp_clks_register(qmp, np);
+ if (ret)
+ return ret;
+ }
+
+ if (np == qmp->dev->of_node)
+ return devm_of_clk_add_hw_provider(qmp->dev, qmp_usbc_clks_hw_get, qmp);
+
ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &fixed->hw);
if (ret)
return ret;
@@ -1040,6 +1230,13 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
if (IS_ERR(base))
return PTR_ERR(base);
+ if (offs->dp_serdes != 0) {
+ qmp->dp_serdes = base + offs->dp_serdes;
+ qmp->dp_tx = base + offs->dp_txa;
+ qmp->dp_tx2 = base + offs->dp_txb;
+ qmp->dp_dp_phy = base + offs->dp_dp_phy;
+ }
+
qmp->serdes = base + offs->serdes;
qmp->pcs = base + offs->pcs;
if (offs->pcs_misc)
@@ -1148,7 +1345,7 @@ static int qmp_usbc_probe(struct platform_device *pdev)
*/
pm_runtime_forbid(dev);
- ret = phy_pipe_clk_register(qmp, np);
+ ret = qmp_usbc_register_clocks(qmp, np);
if (ret)
goto err_node_put;
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v8 07/12] phy: qcom: qmp-usbc: Move USB-only init to usb_power_on
2025-12-15 12:41 [PATCH v8 00/12] Add DisplayPort support for QCS615 platform Xiangxu Yin via B4 Relay
` (5 preceding siblings ...)
2025-12-15 12:42 ` [PATCH v8 06/12] phy: qcom: qmp-usbc: add DP link and vco_div clocks for DP PHY Xiangxu Yin via B4 Relay
@ 2025-12-15 12:42 ` Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 08/12] phy: qcom: qmp-usbc: Add TCSR parsing and PHY mode setting Xiangxu Yin via B4 Relay
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Xiangxu Yin via B4 Relay @ 2025-12-15 12:42 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, fange.zhang,
yongxing.mou, li.liu, tingwei.zhang, Dmitry Baryshkov,
Bjorn Andersson, Konrad Dybcio, Xiangxu Yin
From: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
The current implementation programs USB-specific registers in
qmp_usbc_com_init(), which is shared by both USB and DP modes. This
causes unnecessary configuration when the PHY is used for DP.
Move USB-only register setup from com_init to qmp_usbc_usb_power_on,
so it runs only for USB mode.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index a6431e6d5586..c8e0f9574ba6 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -30,6 +30,8 @@
#include "phy-qcom-qmp-pcs-misc-v3.h"
#define PHY_INIT_COMPLETE_TIMEOUT 10000
+#define SW_PORTSELECT_VAL BIT(0)
+#define SW_PORTSELECT_MUX BIT(1)
/* set of registers with offsets different per-PHY */
enum qphy_reg_layout {
@@ -531,8 +533,6 @@ static int qmp_usbc_com_init(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
const struct qmp_phy_cfg *cfg = qmp->cfg;
- void __iomem *pcs = qmp->pcs;
- u32 val = 0;
int ret;
ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
@@ -557,16 +557,6 @@ static int qmp_usbc_com_init(struct phy *phy)
if (ret)
goto err_assert_reset;
- qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN);
-
-#define SW_PORTSELECT_VAL BIT(0)
-#define SW_PORTSELECT_MUX BIT(1)
- /* Use software based port select and switch on typec orientation */
- val = SW_PORTSELECT_MUX;
- if (qmp->orientation == TYPEC_ORIENTATION_REVERSE)
- val |= SW_PORTSELECT_VAL;
- writel(val, qmp->pcs_misc);
-
return 0;
err_assert_reset:
@@ -599,6 +589,14 @@ static int qmp_usbc_usb_power_on(struct phy *phy)
unsigned int val;
int ret;
+ qphy_setbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN);
+
+ /* Use software based port select and switch on typec orientation */
+ val = SW_PORTSELECT_MUX;
+ if (qmp->orientation == TYPEC_ORIENTATION_REVERSE)
+ val |= SW_PORTSELECT_VAL;
+ writel(val, qmp->pcs_misc);
+
qmp_configure(qmp->dev, qmp->serdes, cfg->serdes_tbl,
cfg->serdes_tbl_num);
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v8 08/12] phy: qcom: qmp-usbc: Add TCSR parsing and PHY mode setting
2025-12-15 12:41 [PATCH v8 00/12] Add DisplayPort support for QCS615 platform Xiangxu Yin via B4 Relay
` (6 preceding siblings ...)
2025-12-15 12:42 ` [PATCH v8 07/12] phy: qcom: qmp-usbc: Move USB-only init to usb_power_on Xiangxu Yin via B4 Relay
@ 2025-12-15 12:42 ` Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 09/12] phy: qcom: qmp-usbc: Add DP PHY ops for USB/DP switchable Type-C PHYs Xiangxu Yin via B4 Relay
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Xiangxu Yin via B4 Relay @ 2025-12-15 12:42 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, fange.zhang,
yongxing.mou, li.liu, tingwei.zhang, Dmitry Baryshkov,
Bjorn Andersson, Konrad Dybcio, Xiangxu Yin
From: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
Extend TCSR parsing to read optional dp_phy_mode_reg and add
qmp_usbc_set_phy_mode() to switch between USB and DP modes when
supported.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index c8e0f9574ba6..0a634ec4029a 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -529,6 +529,12 @@ static const struct qmp_phy_cfg qcs615_usb3phy_cfg = {
.regs = qmp_v3_usb3phy_regs_layout_qcm2290,
};
+static void qmp_usbc_set_phy_mode(struct qmp_usbc *qmp, bool is_dp)
+{
+ if (qmp->tcsr_map && qmp->dp_phy_mode_reg)
+ regmap_write(qmp->tcsr_map, qmp->dp_phy_mode_reg, is_dp);
+}
+
static int qmp_usbc_com_init(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
@@ -669,6 +675,8 @@ static int qmp_usbc_usb_enable(struct phy *phy)
if (ret)
goto out_unlock;
+ qmp_usbc_set_phy_mode(qmp, false);
+
ret = qmp_usbc_usb_power_on(phy);
if (ret) {
qmp_usbc_com_exit(phy);
@@ -1112,6 +1120,7 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw,
qmp_usbc_com_exit(qmp->usb_phy);
qmp_usbc_com_init(qmp->usb_phy);
+ qmp_usbc_set_phy_mode(qmp, false);
qmp_usbc_usb_power_on(qmp->usb_phy);
}
@@ -1262,15 +1271,16 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
return 0;
}
-static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp)
+static int qmp_usbc_parse_tcsr(struct qmp_usbc *qmp)
{
struct of_phandle_args tcsr_args;
struct device *dev = qmp->dev;
- int ret;
+ int ret, args_count;
- /* for backwards compatibility ignore if there is no property */
- ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,tcsr-reg", 1, 0,
- &tcsr_args);
+ args_count = of_property_count_u32_elems(dev->of_node, "qcom,tcsr-reg");
+ args_count = args_count - 1;
+ ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,tcsr-reg",
+ args_count, 0, &tcsr_args);
if (ret == -ENOENT)
return 0;
else if (ret < 0)
@@ -1283,6 +1293,9 @@ static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp)
qmp->vls_clamp_reg = tcsr_args.args[0];
+ if (args_count > 1)
+ qmp->dp_phy_mode_reg = tcsr_args.args[1];
+
return 0;
}
@@ -1318,7 +1331,7 @@ static int qmp_usbc_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = qmp_usbc_parse_vls_clamp(qmp);
+ ret = qmp_usbc_parse_tcsr(qmp);
if (ret)
return ret;
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v8 09/12] phy: qcom: qmp-usbc: Add DP PHY ops for USB/DP switchable Type-C PHYs
2025-12-15 12:41 [PATCH v8 00/12] Add DisplayPort support for QCS615 platform Xiangxu Yin via B4 Relay
` (7 preceding siblings ...)
2025-12-15 12:42 ` [PATCH v8 08/12] phy: qcom: qmp-usbc: Add TCSR parsing and PHY mode setting Xiangxu Yin via B4 Relay
@ 2025-12-15 12:42 ` Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 10/12] phy: qcom: qmp-usbc: Add USB/DP exclude handling Xiangxu Yin via B4 Relay
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Xiangxu Yin via B4 Relay @ 2025-12-15 12:42 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, fange.zhang,
yongxing.mou, li.liu, tingwei.zhang, Dmitry Baryshkov,
Bjorn Andersson, Konrad Dybcio, Xiangxu Yin
From: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
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>
---
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 194 ++++++++++++++++++++++++++++++-
1 file changed, 193 insertions(+), 1 deletion(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index 0a634ec4029a..1ac755825313 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -29,6 +29,8 @@
#include "phy-qcom-qmp.h"
#include "phy-qcom-qmp-pcs-misc-v3.h"
+#include "phy-qcom-qmp-dp-phy.h"
+
#define PHY_INIT_COMPLETE_TIMEOUT 10000
#define SW_PORTSELECT_VAL BIT(0)
#define SW_PORTSELECT_MUX BIT(1)
@@ -711,6 +713,159 @@ 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;
+
+ qmp_usbc_set_phy_mode(qmp, true);
+
+ 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,
@@ -718,6 +873,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;
@@ -1299,6 +1464,23 @@ static int qmp_usbc_parse_tcsr(struct qmp_usbc *qmp)
return 0;
}
+static struct phy *qmp_usbc_phy_xlate(struct device *dev, const struct of_phandle_args *args)
+{
+ struct qmp_usbc *qmp = dev_get_drvdata(dev);
+
+ if (args->args_count == 0)
+ return qmp->usb_phy;
+
+ switch (args->args[0]) {
+ case QMP_USB43DP_USB3_PHY:
+ return qmp->usb_phy;
+ case QMP_USB43DP_DP_PHY:
+ return qmp->dp_phy ?: ERR_PTR(-ENODEV);
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
static int qmp_usbc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1369,9 +1551,19 @@ static int qmp_usbc_probe(struct platform_device *pdev)
phy_set_drvdata(qmp->usb_phy, qmp);
+ if (qmp->dp_serdes != 0) {
+ qmp->dp_phy = devm_phy_create(dev, np, &qmp_usbc_dp_phy_ops);
+ if (IS_ERR(qmp->dp_phy)) {
+ ret = PTR_ERR(qmp->dp_phy);
+ dev_err(dev, "failed to create PHY: %d\n", ret);
+ goto err_node_put;
+ }
+ phy_set_drvdata(qmp->dp_phy, qmp);
+ }
+
of_node_put(np);
- phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ phy_provider = devm_of_phy_provider_register(dev, qmp_usbc_phy_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v8 10/12] phy: qcom: qmp-usbc: Add USB/DP exclude handling
2025-12-15 12:41 [PATCH v8 00/12] Add DisplayPort support for QCS615 platform Xiangxu Yin via B4 Relay
` (8 preceding siblings ...)
2025-12-15 12:42 ` [PATCH v8 09/12] phy: qcom: qmp-usbc: Add DP PHY ops for USB/DP switchable Type-C PHYs Xiangxu Yin via B4 Relay
@ 2025-12-15 12:42 ` Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 11/12] phy: qcom: qmp: Add DP v2 PHY register definitions Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 12/12] phy: qcom: qmp-usbc: Add QCS615 USB/DP PHY config and DP mode support Xiangxu Yin via B4 Relay
11 siblings, 0 replies; 13+ messages in thread
From: Xiangxu Yin via B4 Relay @ 2025-12-15 12:42 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, fange.zhang,
yongxing.mou, li.liu, tingwei.zhang, Dmitry Baryshkov,
Bjorn Andersson, Konrad Dybcio, Xiangxu Yin, Konrad Dybcio
From: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
When both USB and DP PHY modes are enabled simultaneously on the same
QMP USBC PHY, it can lead to hardware misconfiguration and undefined
behavior. This happens because the PHY resources are not designed to
operate in both modes at the same time.
To prevent this, introduce a mutual exclusion check between USB and DP
PHY modes.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index 1ac755825313..b1a2380401ff 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -666,6 +666,19 @@ static int qmp_usbc_usb_power_off(struct phy *phy)
return 0;
}
+static int qmp_usbc_check_phy_status(struct qmp_usbc *qmp, bool is_dp)
+{
+ if ((is_dp && qmp->usb_init_count) ||
+ (!is_dp && qmp->dp_init_count)) {
+ dev_err(qmp->dev,
+ "PHY is configured for %s, can not enable %s\n",
+ is_dp ? "USB" : "DP", is_dp ? "DP" : "USB");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
static int qmp_usbc_usb_enable(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
@@ -673,6 +686,10 @@ static int qmp_usbc_usb_enable(struct phy *phy)
mutex_lock(&qmp->phy_mutex);
+ ret = qmp_usbc_check_phy_status(qmp, false);
+ if (ret)
+ goto out_unlock;
+
ret = qmp_usbc_com_init(phy);
if (ret)
goto out_unlock;
@@ -726,6 +743,10 @@ static int qmp_usbc_dp_enable(struct phy *phy)
mutex_lock(&qmp->phy_mutex);
+ ret = qmp_usbc_check_phy_status(qmp, true);
+ if (ret)
+ goto dp_init_unlock;
+
ret = qmp_usbc_com_init(phy);
if (ret)
goto dp_init_unlock;
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v8 11/12] phy: qcom: qmp: Add DP v2 PHY register definitions
2025-12-15 12:41 [PATCH v8 00/12] Add DisplayPort support for QCS615 platform Xiangxu Yin via B4 Relay
` (9 preceding siblings ...)
2025-12-15 12:42 ` [PATCH v8 10/12] phy: qcom: qmp-usbc: Add USB/DP exclude handling Xiangxu Yin via B4 Relay
@ 2025-12-15 12:42 ` Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 12/12] phy: qcom: qmp-usbc: Add QCS615 USB/DP PHY config and DP mode support Xiangxu Yin via B4 Relay
11 siblings, 0 replies; 13+ messages in thread
From: Xiangxu Yin via B4 Relay @ 2025-12-15 12:42 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, fange.zhang,
yongxing.mou, li.liu, tingwei.zhang, Dmitry Baryshkov,
Bjorn Andersson, Konrad Dybcio, Xiangxu Yin
From: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
Add dedicated headers for DP v2 PHY, including QSERDES COM and TX/RX
register definitions.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h | 21 ++++
drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h | 106 +++++++++++++++++++++
.../phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h | 68 +++++++++++++
drivers/phy/qualcomm/phy-qcom-qmp.h | 3 +
4 files changed, 198 insertions(+)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h
new file mode 100644
index 000000000000..8b9572d3cdeb
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_DP_PHY_V2_H_
+#define QCOM_PHY_QMP_DP_PHY_V2_H_
+
+// /* Only for QMP V2 PHY - DP PHY registers */
+#define QSERDES_V2_DP_PHY_AUX_INTERRUPT_MASK 0x048
+#define QSERDES_V2_DP_PHY_AUX_INTERRUPT_CLEAR 0x04c
+#define QSERDES_V2_DP_PHY_AUX_BIST_CFG 0x050
+
+#define QSERDES_V2_DP_PHY_VCO_DIV 0x068
+#define QSERDES_V2_DP_PHY_TX0_TX1_LANE_CTL 0x06c
+#define QSERDES_V2_DP_PHY_TX2_TX3_LANE_CTL 0x088
+
+#define QSERDES_V2_DP_PHY_SPARE0 0x0ac
+#define QSERDES_V2_DP_PHY_STATUS 0x0c0
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h
new file mode 100644
index 000000000000..3ea1884f35dd
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_COM_V2_H_
+#define QCOM_PHY_QMP_QSERDES_COM_V2_H_
+
+/* Only for QMP V2 PHY - QSERDES COM registers */
+#define QSERDES_V2_COM_ATB_SEL1 0x000
+#define QSERDES_V2_COM_ATB_SEL2 0x004
+#define QSERDES_V2_COM_FREQ_UPDATE 0x008
+#define QSERDES_V2_COM_BG_TIMER 0x00c
+#define QSERDES_V2_COM_SSC_EN_CENTER 0x010
+#define QSERDES_V2_COM_SSC_ADJ_PER1 0x014
+#define QSERDES_V2_COM_SSC_ADJ_PER2 0x018
+#define QSERDES_V2_COM_SSC_PER1 0x01c
+#define QSERDES_V2_COM_SSC_PER2 0x020
+#define QSERDES_V2_COM_SSC_STEP_SIZE1 0x024
+#define QSERDES_V2_COM_SSC_STEP_SIZE2 0x028
+#define QSERDES_V2_COM_POST_DIV 0x02c
+#define QSERDES_V2_COM_POST_DIV_MUX 0x030
+#define QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN 0x034
+#define QSERDES_V2_COM_CLK_ENABLE1 0x038
+#define QSERDES_V2_COM_SYS_CLK_CTRL 0x03c
+#define QSERDES_V2_COM_SYSCLK_BUF_ENABLE 0x040
+#define QSERDES_V2_COM_PLL_EN 0x044
+#define QSERDES_V2_COM_PLL_IVCO 0x048
+#define QSERDES_V2_COM_LOCK_CMP1_MODE0 0x04c
+#define QSERDES_V2_COM_LOCK_CMP2_MODE0 0x050
+#define QSERDES_V2_COM_LOCK_CMP3_MODE0 0x054
+#define QSERDES_V2_COM_LOCK_CMP1_MODE1 0x058
+#define QSERDES_V2_COM_LOCK_CMP2_MODE1 0x05c
+#define QSERDES_V2_COM_LOCK_CMP3_MODE1 0x060
+#define QSERDES_V2_COM_EP_CLOCK_DETECT_CTR 0x068
+#define QSERDES_V2_COM_SYSCLK_DET_COMP_STATUS 0x06c
+#define QSERDES_V2_COM_CLK_EP_DIV 0x074
+#define QSERDES_V2_COM_CP_CTRL_MODE0 0x078
+#define QSERDES_V2_COM_CP_CTRL_MODE1 0x07c
+#define QSERDES_V2_COM_PLL_RCTRL_MODE0 0x084
+#define QSERDES_V2_COM_PLL_RCTRL_MODE1 0x088
+#define QSERDES_V2_COM_PLL_CCTRL_MODE0 0x090
+#define QSERDES_V2_COM_PLL_CCTRL_MODE1 0x094
+#define QSERDES_V2_COM_PLL_CNTRL 0x09c
+#define QSERDES_V2_COM_BIAS_EN_CTRL_BY_PSM 0x0a8
+#define QSERDES_V2_COM_SYSCLK_EN_SEL 0x0ac
+#define QSERDES_V2_COM_CML_SYSCLK_SEL 0x0b0
+#define QSERDES_V2_COM_RESETSM_CNTRL 0x0b4
+#define QSERDES_V2_COM_RESETSM_CNTRL2 0x0b8
+#define QSERDES_V2_COM_LOCK_CMP_EN 0x0c8
+#define QSERDES_V2_COM_LOCK_CMP_CFG 0x0cc
+#define QSERDES_V2_COM_DEC_START_MODE0 0x0d0
+#define QSERDES_V2_COM_DEC_START_MODE1 0x0d4
+#define QSERDES_V2_COM_VCOCAL_DEADMAN_CTRL 0x0d8
+#define QSERDES_V2_COM_DIV_FRAC_START1_MODE0 0x0dc
+#define QSERDES_V2_COM_DIV_FRAC_START2_MODE0 0x0e0
+#define QSERDES_V2_COM_DIV_FRAC_START3_MODE0 0x0e4
+#define QSERDES_V2_COM_DIV_FRAC_START1_MODE1 0x0e8
+#define QSERDES_V2_COM_DIV_FRAC_START2_MODE1 0x0ec
+#define QSERDES_V2_COM_DIV_FRAC_START3_MODE1 0x0f0
+#define QSERDES_V2_COM_VCO_TUNE_MINVAL1 0x0f4
+#define QSERDES_V2_COM_VCO_TUNE_MINVAL2 0x0f8
+#define QSERDES_V2_COM_INTEGLOOP_INITVAL 0x100
+#define QSERDES_V2_COM_INTEGLOOP_EN 0x104
+#define QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0 0x108
+#define QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE0 0x10c
+#define QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE1 0x110
+#define QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE1 0x114
+#define QSERDES_V2_COM_VCO_TUNE_MAXVAL1 0x118
+#define QSERDES_V2_COM_VCO_TUNE_MAXVAL2 0x11c
+#define QSERDES_V2_COM_VCO_TUNE_CTRL 0x124
+#define QSERDES_V2_COM_VCO_TUNE_MAP 0x128
+#define QSERDES_V2_COM_VCO_TUNE1_MODE0 0x12c
+#define QSERDES_V2_COM_VCO_TUNE2_MODE0 0x130
+#define QSERDES_V2_COM_VCO_TUNE1_MODE1 0x134
+#define QSERDES_V2_COM_VCO_TUNE2_MODE1 0x138
+#define QSERDES_V2_COM_VCO_TUNE_INITVAL1 0x13c
+#define QSERDES_V2_COM_VCO_TUNE_INITVAL2 0x140
+#define QSERDES_V2_COM_VCO_TUNE_TIMER1 0x144
+#define QSERDES_V2_COM_VCO_TUNE_TIMER2 0x148
+#define QSERDES_V2_COM_CMN_STATUS 0x15c
+#define QSERDES_V2_COM_RESET_SM_STATUS 0x160
+#define QSERDES_V2_COM_RESTRIM_CODE_STATUS 0x164
+#define QSERDES_V2_COM_PLLCAL_CODE1_STATUS 0x168
+#define QSERDES_V2_COM_PLLCAL_CODE2_STATUS 0x16c
+#define QSERDES_V2_COM_CLK_SELECT 0x174
+#define QSERDES_V2_COM_HSCLK_SEL 0x178
+#define QSERDES_V2_COM_INTEGLOOP_BINCODE_STATUS 0x17c
+#define QSERDES_V2_COM_PLL_ANALOG 0x180
+#define QSERDES_V2_COM_CORECLK_DIV 0x184
+#define QSERDES_V2_COM_SW_RESET 0x188
+#define QSERDES_V2_COM_CORE_CLK_EN 0x18c
+#define QSERDES_V2_COM_C_READY_STATUS 0x190
+#define QSERDES_V2_COM_CMN_CONFIG 0x194
+#define QSERDES_V2_COM_CMN_RATE_OVERRIDE 0x198
+#define QSERDES_V2_COM_SVS_MODE_CLK_SEL 0x19c
+#define QSERDES_V2_COM_DEBUG_BUS0 0x1a0
+#define QSERDES_V2_COM_DEBUG_BUS1 0x1a4
+#define QSERDES_V2_COM_DEBUG_BUS2 0x1a8
+#define QSERDES_V2_COM_DEBUG_BUS3 0x1ac
+#define QSERDES_V2_COM_DEBUG_BUS_SEL 0x1b0
+#define QSERDES_V2_COM_CMN_MISC1 0x1b4
+#define QSERDES_V2_COM_CMN_MISC2 0x1b8
+#define QSERDES_V2_COM_CORECLK_DIV_MODE1 0x1bc
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h
new file mode 100644
index 000000000000..34919720b7bc
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_TXRX_V2_H_
+#define QCOM_PHY_QMP_QSERDES_TXRX_V2_H_
+
+/* Only for QMP V2 PHY - TX registers */
+#define QSERDES_V2_TX_BIST_MODE_LANENO 0x000
+#define QSERDES_V2_TX_CLKBUF_ENABLE 0x008
+#define QSERDES_V2_TX_TX_EMP_POST1_LVL 0x00c
+#define QSERDES_V2_TX_TX_DRV_LVL 0x01c
+#define QSERDES_V2_TX_RESET_TSYNC_EN 0x024
+#define QSERDES_V2_TX_PRE_STALL_LDO_BOOST_EN 0x028
+#define QSERDES_V2_TX_TX_BAND 0x02c
+#define QSERDES_V2_TX_SLEW_CNTL 0x030
+#define QSERDES_V2_TX_INTERFACE_SELECT 0x034
+#define QSERDES_V2_TX_RES_CODE_LANE_TX 0x03c
+#define QSERDES_V2_TX_RES_CODE_LANE_RX 0x040
+#define QSERDES_V2_TX_RES_CODE_LANE_OFFSET_TX 0x044
+#define QSERDES_V2_TX_RES_CODE_LANE_OFFSET_RX 0x048
+#define QSERDES_V2_TX_DEBUG_BUS_SEL 0x058
+#define QSERDES_V2_TX_TRANSCEIVER_BIAS_EN 0x05c
+#define QSERDES_V2_TX_HIGHZ_DRVR_EN 0x060
+#define QSERDES_V2_TX_TX_POL_INV 0x064
+#define QSERDES_V2_TX_PARRATE_REC_DETECT_IDLE_EN 0x068
+#define QSERDES_V2_TX_LANE_MODE_1 0x08c
+#define QSERDES_V2_TX_LANE_MODE_2 0x090
+#define QSERDES_V2_TX_LANE_MODE_3 0x094
+#define QSERDES_V2_TX_RCV_DETECT_LVL_2 0x0a4
+#define QSERDES_V2_TX_TRAN_DRVR_EMP_EN 0x0c0
+#define QSERDES_V2_TX_TX_INTERFACE_MODE 0x0c4
+#define QSERDES_V2_TX_VMODE_CTRL1 0x0f0
+
+/* Only for QMP V2 PHY - RX registers */
+#define QSERDES_V2_RX_UCDR_FO_GAIN 0x008
+#define QSERDES_V2_RX_UCDR_SO_GAIN_HALF 0x00c
+#define QSERDES_V2_RX_UCDR_SO_GAIN 0x014
+#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN_HALF 0x024
+#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN_QUARTER 0x028
+#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN 0x02c
+#define QSERDES_V2_RX_UCDR_FASTLOCK_FO_GAIN 0x030
+#define QSERDES_V2_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034
+#define QSERDES_V2_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c
+#define QSERDES_V2_RX_UCDR_FASTLOCK_COUNT_HIGH 0x040
+#define QSERDES_V2_RX_UCDR_PI_CONTROLS 0x044
+#define QSERDES_V2_RX_RX_TERM_BW 0x07c
+#define QSERDES_V2_RX_VGA_CAL_CNTRL1 0x0bc
+#define QSERDES_V2_RX_VGA_CAL_CNTRL2 0x0c0
+#define QSERDES_V2_RX_RX_EQ_GAIN2_LSB 0x0c8
+#define QSERDES_V2_RX_RX_EQ_GAIN2_MSB 0x0cc
+#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL1 0x0d0
+#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d4
+#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL3 0x0d8
+#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL4 0x0dc
+#define QSERDES_V2_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x0f8
+#define QSERDES_V2_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x0fc
+#define QSERDES_V2_RX_SIGDET_ENABLES 0x100
+#define QSERDES_V2_RX_SIGDET_CNTRL 0x104
+#define QSERDES_V2_RX_SIGDET_LVL 0x108
+#define QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL 0x10c
+#define QSERDES_V2_RX_RX_BAND 0x110
+#define QSERDES_V2_RX_RX_INTERFACE_MODE 0x11c
+#define QSERDES_V2_RX_RX_MODE_00 0x164
+#define QSERDES_V2_RX_RX_MODE_01 0x168
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h
index da2a7ad2cdcc..836a222a2e78 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.h
@@ -9,6 +9,9 @@
#include "phy-qcom-qmp-qserdes-com.h"
#include "phy-qcom-qmp-qserdes-txrx.h"
+#include "phy-qcom-qmp-qserdes-com-v2.h"
+#include "phy-qcom-qmp-qserdes-txrx-v2.h"
+
#include "phy-qcom-qmp-qserdes-com-v3.h"
#include "phy-qcom-qmp-qserdes-txrx-v3.h"
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v8 12/12] phy: qcom: qmp-usbc: Add QCS615 USB/DP PHY config and DP mode support
2025-12-15 12:41 [PATCH v8 00/12] Add DisplayPort support for QCS615 platform Xiangxu Yin via B4 Relay
` (10 preceding siblings ...)
2025-12-15 12:42 ` [PATCH v8 11/12] phy: qcom: qmp: Add DP v2 PHY register definitions Xiangxu Yin via B4 Relay
@ 2025-12-15 12:42 ` Xiangxu Yin via B4 Relay
11 siblings, 0 replies; 13+ messages in thread
From: Xiangxu Yin via B4 Relay @ 2025-12-15 12:42 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, fange.zhang,
yongxing.mou, li.liu, tingwei.zhang, Dmitry Baryshkov,
Bjorn Andersson, Konrad Dybcio, Xiangxu Yin
From: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
Add QCS615-specific configuration for USB/DP PHY, including DP init
routines, voltage swing tables, and platform data. Add compatible
"qcs615-qmp-usb3-dp-phy".
Note: SW_PORTSELECT handling for orientation flip is not implemented
due to QCS615 fixed-orientation design and non-standard lane mapping.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 413 +++++++++++++++++++++++++++++++
1 file changed, 413 insertions(+)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index b1a2380401ff..14feb77789b3 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -30,6 +30,7 @@
#include "phy-qcom-qmp-pcs-misc-v3.h"
#include "phy-qcom-qmp-dp-phy.h"
+#include "phy-qcom-qmp-dp-phy-v2.h"
#define PHY_INIT_COMPLETE_TIMEOUT 10000
#define SW_PORTSELECT_VAL BIT(0)
@@ -289,6 +290,83 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88),
};
+static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x37),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BG_CTRL, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x02),
+};
+
+static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_rbr[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x2c),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x69),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x21),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+};
+
+static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x69),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x38),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+};
+
+static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr2[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x8c),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x70),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+};
+
+static const struct qmp_phy_init_tbl qmp_v2_dp_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TRANSCEIVER_BIAS_EN, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_VMODE_CTRL1, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_PRE_STALL_LDO_BOOST_EN, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_INTERFACE_SELECT, 0x3d),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_CLKBUF_ENABLE, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_RESET_TSYNC_EN, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TRAN_DRVR_EMP_EN, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_INTERFACE_MODE, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_EMP_POST1_LVL, 0x2b),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_DRV_LVL, 0x2f),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_BAND, 0x4),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET_TX, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET_RX, 0x12),
+};
+
struct qmp_usbc_offsets {
u16 serdes;
u16 pcs;
@@ -434,6 +512,10 @@ static const char * const usb3phy_reset_l[] = {
"phy_phy", "phy",
};
+static const char * const usb3dpphy_reset_l[] = {
+ "phy_phy", "dp_phy",
+};
+
static const struct regulator_bulk_data qmp_phy_msm8998_vreg_l[] = {
{ .supply = "vdda-phy", .init_load_uA = 68600 },
{ .supply = "vdda-pll", .init_load_uA = 14200 },
@@ -459,6 +541,34 @@ static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {
.rx2 = 0x800,
};
+static const struct qmp_usbc_offsets qmp_usbc_usb3dp_offsets_qcs615 = {
+ .serdes = 0x0,
+ .pcs = 0xc00,
+ .pcs_misc = 0xa00,
+ .tx = 0x200,
+ .rx = 0x400,
+ .tx2 = 0x600,
+ .rx2 = 0x800,
+ .dp_serdes = 0x1c00,
+ .dp_txa = 0x1400,
+ .dp_txb = 0x1800,
+ .dp_dp_phy = 0x1000,
+};
+
+static const u8 qmp_v2_dp_pre_emphasis_hbr2_rbr[4][4] = {
+ {0x00, 0x0b, 0x12, 0xff},
+ {0x00, 0x0a, 0x12, 0xff},
+ {0x00, 0x0c, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff}
+};
+
+static const u8 qmp_v2_dp_voltage_swing_hbr2_rbr[4][4] = {
+ {0x07, 0x0f, 0x14, 0xff},
+ {0x11, 0x1d, 0x1f, 0xff},
+ {0x18, 0x1f, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff}
+};
+
static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
.offsets = &qmp_usbc_offsets_v3_qcm2290,
@@ -531,6 +641,51 @@ static const struct qmp_phy_cfg qcs615_usb3phy_cfg = {
.regs = qmp_v3_usb3phy_regs_layout_qcm2290,
};
+static void qmp_v2_dp_aux_init(struct qmp_usbc *qmp);
+static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp);
+static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp);
+static int qmp_v2_calibrate_dp_phy(struct qmp_usbc *qmp);
+
+static const struct qmp_phy_cfg qcs615_usb3dp_phy_cfg = {
+ .offsets = &qmp_usbc_usb3dp_offsets_qcs615,
+
+ .serdes_tbl = qcm2290_usb3_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
+ .tx_tbl = qcm2290_usb3_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl),
+ .rx_tbl = qcm2290_usb3_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl),
+ .pcs_tbl = qcm2290_usb3_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl),
+
+ .regs = qmp_v3_usb3phy_regs_layout_qcm2290,
+
+ .dp_serdes_tbl = qmp_v2_dp_serdes_tbl,
+ .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl),
+ .dp_tx_tbl = qmp_v2_dp_tx_tbl,
+ .dp_tx_tbl_num = ARRAY_SIZE(qmp_v2_dp_tx_tbl),
+
+ .serdes_tbl_rbr = qmp_v2_dp_serdes_tbl_rbr,
+ .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_rbr),
+ .serdes_tbl_hbr = qmp_v2_dp_serdes_tbl_hbr,
+ .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_hbr),
+ .serdes_tbl_hbr2 = qmp_v2_dp_serdes_tbl_hbr2,
+ .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_hbr2),
+
+ .swing_tbl = &qmp_v2_dp_voltage_swing_hbr2_rbr,
+ .pre_emphasis_tbl = &qmp_v2_dp_pre_emphasis_hbr2_rbr,
+
+ .dp_aux_init = qmp_v2_dp_aux_init,
+ .configure_dp_tx = qmp_v2_configure_dp_tx,
+ .configure_dp_phy = qmp_v2_configure_dp_phy,
+ .calibrate_dp_phy = qmp_v2_calibrate_dp_phy,
+
+ .reset_list = usb3dpphy_reset_l,
+ .num_resets = ARRAY_SIZE(usb3dpphy_reset_l),
+ .vreg_list = qmp_phy_qcs615_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_qcs615_vreg_l),
+};
+
static void qmp_usbc_set_phy_mode(struct qmp_usbc *qmp, bool is_dp)
{
if (qmp->tcsr_map && qmp->dp_phy_mode_reg)
@@ -589,6 +744,253 @@ static int qmp_usbc_com_exit(struct phy *phy)
return 0;
}
+static void qmp_v2_dp_aux_init(struct qmp_usbc *qmp)
+{
+ writel(DP_PHY_PD_CTL_AUX_PWRDN |
+ DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN |
+ DP_PHY_PD_CTL_PLL_PWRDN,
+ qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+ writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
+ DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN |
+ DP_PHY_PD_CTL_PLL_PWRDN,
+ qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+ writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0);
+ writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1);
+ writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2);
+ writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG3);
+ writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG4);
+ writel(0x26, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG5);
+ writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG6);
+ writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG7);
+ writel(0xbb, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG8);
+ writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG9);
+ qmp->dp_aux_cfg = 0;
+
+ writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK |
+ PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK |
+ PHY_AUX_REQ_ERR_MASK,
+ qmp->dp_dp_phy + QSERDES_V2_DP_PHY_AUX_INTERRUPT_MASK);
+}
+
+static int qmp_v2_configure_dp_swing(struct qmp_usbc *qmp)
+{
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+ void __iomem *tx = qmp->dp_tx;
+ void __iomem *tx2 = qmp->dp_tx2;
+ unsigned int v_level = 0, p_level = 0;
+ u8 voltage_swing_cfg, pre_emphasis_cfg;
+ int i;
+
+ if (dp_opts->lanes > 4) {
+ dev_err(qmp->dev, "Invalid lane_num(%d)\n", dp_opts->lanes);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < dp_opts->lanes; i++) {
+ v_level = max(v_level, dp_opts->voltage[i]);
+ p_level = max(p_level, dp_opts->pre[i]);
+ }
+
+ if (v_level > 4 || p_level > 4) {
+ dev_err(qmp->dev, "Invalid v(%d) | p(%d) level)\n",
+ v_level, p_level);
+ return -EINVAL;
+ }
+
+ voltage_swing_cfg = (*cfg->swing_tbl)[v_level][p_level];
+ pre_emphasis_cfg = (*cfg->pre_emphasis_tbl)[v_level][p_level];
+
+ voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN;
+ pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN;
+
+ if (voltage_swing_cfg == 0xff && pre_emphasis_cfg == 0xff)
+ return -EINVAL;
+
+ writel(voltage_swing_cfg, tx + QSERDES_V2_TX_TX_DRV_LVL);
+ writel(pre_emphasis_cfg, tx + QSERDES_V2_TX_TX_EMP_POST1_LVL);
+ writel(voltage_swing_cfg, tx2 + QSERDES_V2_TX_TX_DRV_LVL);
+ writel(pre_emphasis_cfg, tx2 + QSERDES_V2_TX_TX_EMP_POST1_LVL);
+
+ return 0;
+}
+
+static void qmp_usbc_configure_dp_mode(struct qmp_usbc *qmp)
+{
+ bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
+ u32 val;
+
+ val = DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
+ DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN;
+
+ writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+ if (reverse)
+ writel(0xc9, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE);
+ else
+ writel(0xd9, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE);
+}
+
+static int qmp_usbc_configure_dp_clocks(struct qmp_usbc *qmp)
+{
+ const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+ u32 phy_vco_div;
+ unsigned long pixel_freq;
+
+ switch (dp_opts->link_rate) {
+ case 1620:
+ phy_vco_div = 0x1;
+ pixel_freq = 1620000000UL / 2;
+ break;
+ case 2700:
+ phy_vco_div = 0x1;
+ pixel_freq = 2700000000UL / 2;
+ break;
+ case 5400:
+ phy_vco_div = 0x2;
+ pixel_freq = 5400000000UL / 4;
+ break;
+ default:
+ dev_err(qmp->dev, "link rate:%d not supported\n", dp_opts->link_rate);
+ return -EINVAL;
+ }
+ writel(phy_vco_div, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_VCO_DIV);
+
+ clk_set_rate(qmp->dp_link_hw.clk, dp_opts->link_rate * 100000);
+ clk_set_rate(qmp->dp_pixel_hw.clk, pixel_freq);
+
+ return 0;
+}
+
+static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp)
+{
+ const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+ void __iomem *tx = qmp->dp_tx;
+ void __iomem *tx2 = qmp->dp_tx2;
+
+ /* program default setting first */
+ writel(0x2a, tx + QSERDES_V2_TX_TX_DRV_LVL);
+ writel(0x20, tx + QSERDES_V2_TX_TX_EMP_POST1_LVL);
+ writel(0x2a, tx2 + QSERDES_V2_TX_TX_DRV_LVL);
+ writel(0x20, tx2 + QSERDES_V2_TX_TX_EMP_POST1_LVL);
+
+ if (dp_opts->link_rate >= 2700) {
+ writel(0xc4, tx + QSERDES_V2_TX_LANE_MODE_1);
+ writel(0xc4, tx2 + QSERDES_V2_TX_LANE_MODE_1);
+ } else {
+ writel(0xc6, tx + QSERDES_V2_TX_LANE_MODE_1);
+ writel(0xc6, tx2 + QSERDES_V2_TX_LANE_MODE_1);
+ }
+
+ qmp_v2_configure_dp_swing(qmp);
+}
+
+static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp)
+{
+ u32 status;
+ int ret;
+
+ qmp_usbc_configure_dp_mode(qmp);
+
+ writel(0x05, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_TX0_TX1_LANE_CTL);
+ writel(0x05, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_TX2_TX3_LANE_CTL);
+
+ ret = qmp_usbc_configure_dp_clocks(qmp);
+ if (ret)
+ return ret;
+
+ writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+ writel(0x05, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+ writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+ writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+
+ writel(0x20, qmp->dp_serdes + QSERDES_COM_RESETSM_CNTRL);
+
+ if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_C_READY_STATUS,
+ status,
+ ((status & BIT(0)) > 0),
+ 500,
+ 10000)) {
+ dev_err(qmp->dev, "C_READY not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_CMN_STATUS,
+ status,
+ ((status & BIT(0)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "FREQ_DONE not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_CMN_STATUS,
+ status,
+ ((status & BIT(1)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "PLL_LOCKED not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+
+ if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS,
+ status,
+ ((status & BIT(0)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "TSYNC_DONE not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS,
+ status,
+ ((status & BIT(1)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "PHY_READY not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ writel(0x3f, qmp->dp_tx + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN);
+ writel(0x10, qmp->dp_tx + QSERDES_V2_TX_HIGHZ_DRVR_EN);
+ writel(0x0a, qmp->dp_tx + QSERDES_V2_TX_TX_POL_INV);
+ writel(0x3f, qmp->dp_tx2 + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN);
+ writel(0x10, qmp->dp_tx2 + QSERDES_V2_TX_HIGHZ_DRVR_EN);
+ writel(0x0a, qmp->dp_tx2 + QSERDES_V2_TX_TX_POL_INV);
+
+ writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+ writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+
+ if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS,
+ status,
+ ((status & BIT(1)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "PHY_READY not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int qmp_v2_calibrate_dp_phy(struct qmp_usbc *qmp)
+{
+ static const u8 cfg1_settings[] = {0x13, 0x23, 0x1d};
+ u8 val;
+
+ qmp->dp_aux_cfg++;
+ qmp->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
+ val = cfg1_settings[qmp->dp_aux_cfg];
+
+ writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1);
+
+ return 0;
+}
+
static int qmp_usbc_usb_power_on(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
@@ -855,6 +1257,14 @@ static int qmp_usbc_dp_power_on(struct phy *phy)
void __iomem *tx = qmp->dp_tx;
void __iomem *tx2 = qmp->dp_tx2;
+ /*
+ * FIXME: SW_PORTSELECT handling for DP orientation flip is not implemented.
+ * Expected:
+ * - For standard lane mapping: configure SW_PORTSELECT in QSERDES_DP_PHY_CFG_1.
+ * - For non-standard mapping: pass orientation to dp_ctrl and handle flip
+ * via logical2physical lane remapping.
+ */
+
mutex_lock(&qmp->phy_mutex);
qmp_usbc_dp_serdes_init(qmp);
@@ -1600,6 +2010,9 @@ static const struct of_device_id qmp_usbc_of_match_table[] = {
}, {
.compatible = "qcom,qcm2290-qmp-usb3-phy",
.data = &qcm2290_usb3phy_cfg,
+ }, {
+ .compatible = "qcom,qcs615-qmp-usb3-dp-phy",
+ .data = &qcs615_usb3dp_phy_cfg,
}, {
.compatible = "qcom,qcs615-qmp-usb3-phy",
.data = &qcs615_usb3phy_cfg,
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
end of thread, other threads:[~2025-12-15 12:42 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-15 12:41 [PATCH v8 00/12] Add DisplayPort support for QCS615 platform Xiangxu Yin via B4 Relay
2025-12-15 12:41 ` [PATCH v8 01/12] dt-bindings: phy: Add QMP USB3+DP PHY for QCS615 Xiangxu Yin via B4 Relay
2025-12-15 12:41 ` [PATCH v8 02/12] phy: qcom: qmp-usbc: Rename USB-specific ops to prepare for DP support Xiangxu Yin via B4 Relay
2025-12-15 12:41 ` [PATCH v8 03/12] phy: qcom: qmp-usbc: Add DP-related fields for USB/DP switchable PHY Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 04/12] phy: qcom: qmp-usbc: Add regulator init_load support Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 05/12] phy: qcom: qmp-usbc: Move reset config into PHY cfg Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 06/12] phy: qcom: qmp-usbc: add DP link and vco_div clocks for DP PHY Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 07/12] phy: qcom: qmp-usbc: Move USB-only init to usb_power_on Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 08/12] phy: qcom: qmp-usbc: Add TCSR parsing and PHY mode setting Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 09/12] phy: qcom: qmp-usbc: Add DP PHY ops for USB/DP switchable Type-C PHYs Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 10/12] phy: qcom: qmp-usbc: Add USB/DP exclude handling Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 11/12] phy: qcom: qmp: Add DP v2 PHY register definitions Xiangxu Yin via B4 Relay
2025-12-15 12:42 ` [PATCH v8 12/12] phy: qcom: qmp-usbc: Add QCS615 USB/DP PHY config and DP mode support Xiangxu Yin via B4 Relay
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).