linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] Add DisplayPort support for QCS615 platform
@ 2024-11-29  7:57 Xiangxu Yin
  2024-11-29  7:57 ` [PATCH 1/8] dt-bindings: display/msm: Document DP on QCS615 Xiangxu Yin
                   ` (7 more replies)
  0 siblings, 8 replies; 60+ messages in thread
From: Xiangxu Yin @ 2024-11-29  7:57 UTC (permalink / raw)
  To: Rob Clark, Abhinav Kumar, Dmitry Baryshkov, Sean Paul,
	Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio, Xiangxu Yin

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 <quic_xiangxuy@quicinc.com>
---
Xiangxu Yin (8):
      dt-bindings: display/msm: Document DP on QCS615
      dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: Add DP support for QCS615
      phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
      drm/msm/dp: Add DisplayPort support for QCS615
      drm/msm/dp: Add support for lane mapping configuration
      drm/msm/dp: Add maximum width limitation for modes
      drm/msm/dp: Retry Link Training 2 with lower pattern
      drm/msm/dp: Support external GPIO HPD with 3rd pinctrl chip

 .../bindings/display/msm/dp-controller.yaml        |   13 +
 .../bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml    |   21 +-
 drivers/gpu/drm/msm/dp/dp_catalog.c                |   11 +-
 drivers/gpu/drm/msm/dp/dp_catalog.h                |    2 +-
 drivers/gpu/drm/msm/dp/dp_ctrl.c                   |   36 +-
 drivers/gpu/drm/msm/dp/dp_display.c                |   87 ++
 drivers/gpu/drm/msm/dp/dp_display.h                |    1 +
 drivers/gpu/drm/msm/dp/dp_panel.c                  |   26 +-
 drivers/gpu/drm/msm/dp/dp_panel.h                  |    4 +
 drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h         |    1 +
 drivers/phy/qualcomm/phy-qcom-qmp-usbc.c           | 1453 +++++++++++++++++---
 11 files changed, 1438 insertions(+), 217 deletions(-)
---
base-commit: f486c8aa16b8172f63bddc70116a0c897a7f3f02
change-id: 20241129-add-displayport-support-for-qcs615-platform-f31b6dc83919

Best regards,
-- 
xiangxuy <quic_xiangxuy@quicinc.com>


^ permalink raw reply	[flat|nested] 60+ messages in thread

* [PATCH 1/8] dt-bindings: display/msm: Document DP on QCS615
  2024-11-29  7:57 [PATCH 0/8] Add DisplayPort support for QCS615 platform Xiangxu Yin
@ 2024-11-29  7:57 ` Xiangxu Yin
  2024-11-29  8:11   ` Krzysztof Kozlowski
  2024-11-29  7:57 ` [PATCH 2/8] dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: Add DP support for QCS615 Xiangxu Yin
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-11-29  7:57 UTC (permalink / raw)
  To: Rob Clark, Abhinav Kumar, Dmitry Baryshkov, Sean Paul,
	Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio, Xiangxu Yin

Document the DP hardware found on the Qualcomm QCS615 platform.

Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
---
 .../devicetree/bindings/display/msm/dp-controller.yaml      | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
index a212f335d5ffae545d2e5bacec95299ca45e8405..a609245ae601bdc60b65f19d3e59c559886a969d 100644
--- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
+++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
@@ -26,6 +26,7 @@ properties:
           - qcom,sc8280xp-dp
           - qcom,sc8280xp-edp
           - qcom,sdm845-dp
+          - qcom,sm6150-dp
           - qcom,sm8350-dp
           - qcom,sm8650-dp
       - items:
@@ -109,6 +110,18 @@ properties:
   vdda-1p2-supply:
     deprecated: true
 
+  max-width:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Maximum allowed width for display modes
+    default: 7680
+
+  dp-hpd-gpio:
+    description: External GPIO for controlling HPD when a 3rd pinctrl is used
+    items:
+      - description: phandle to 3rd GPIO controller
+      - description: GPIO pin number
+      - description: Optional GPIO flags
+
   ports:
     $ref: /schemas/graph.yaml#/properties/ports
     properties:

-- 
2.25.1


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH 2/8] dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: Add DP support for QCS615
  2024-11-29  7:57 [PATCH 0/8] Add DisplayPort support for QCS615 platform Xiangxu Yin
  2024-11-29  7:57 ` [PATCH 1/8] dt-bindings: display/msm: Document DP on QCS615 Xiangxu Yin
@ 2024-11-29  7:57 ` Xiangxu Yin
  2024-11-29  8:14   ` Krzysztof Kozlowski
  2024-11-29  7:57 ` [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615 Xiangxu Yin
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-11-29  7:57 UTC (permalink / raw)
  To: Rob Clark, Abhinav Kumar, Dmitry Baryshkov, Sean Paul,
	Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio, Xiangxu Yin

Declare the DP QMP PHY present on the Qualcomm QCS615 platforms.

Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
---
 .../bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml     | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml
index 1636285fbe535c430fdf792b33a5e9c523de323b..eb21cfe734526fce670c540212a607a016cedf2c 100644
--- a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml
@@ -18,6 +18,7 @@ properties:
     enum:
       - qcom,msm8998-qmp-usb3-phy
       - qcom,qcm2290-qmp-usb3-phy
+      - qcom,qcs615-qmp-dp-phy
       - qcom,qcs615-qmp-usb3-phy
       - qcom,sdm660-qmp-usb3-phy
       - qcom,sm6115-qmp-usb3-phy
@@ -47,7 +48,7 @@ properties:
     const: 0
 
   clock-output-names:
-    maxItems: 1
+    maxItems: 2
 
   "#phy-cells":
     const: 0
@@ -62,7 +63,8 @@ properties:
     items:
       - items:
           - description: phandle to TCSR hardware block
-          - description: offset of the VLS CLAMP register
+          - description: offset of the VLS CLAMP register in USB mode
+                         and offset of the DP Phy mode register in DP mode
     description: Clamp register present in the TCSR
 
   ports:
@@ -128,6 +130,21 @@ allOf:
             - const: com_aux
             - const: pipe
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,qcs615-qmp-dp-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 2
+        clock-names:
+          items:
+            - const: cfg_ahb
+            - const: ref
+
 additionalProperties: false
 
 examples:

-- 
2.25.1


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-11-29  7:57 [PATCH 0/8] Add DisplayPort support for QCS615 platform Xiangxu Yin
  2024-11-29  7:57 ` [PATCH 1/8] dt-bindings: display/msm: Document DP on QCS615 Xiangxu Yin
  2024-11-29  7:57 ` [PATCH 2/8] dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: Add DP support for QCS615 Xiangxu Yin
@ 2024-11-29  7:57 ` Xiangxu Yin
  2024-11-29  8:18   ` Krzysztof Kozlowski
                     ` (2 more replies)
  2024-11-29  7:57 ` [PATCH 4/8] drm/msm/dp: Add DisplayPort support for QCS615 Xiangxu Yin
                   ` (4 subsequent siblings)
  7 siblings, 3 replies; 60+ messages in thread
From: Xiangxu Yin @ 2024-11-29  7:57 UTC (permalink / raw)
  To: Rob Clark, Abhinav Kumar, Dmitry Baryshkov, Sean Paul,
	Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio, Xiangxu Yin

Extended DP support for QCS615 USB or DP phy. Differentiated between
USBC and DP PHY using the match table’s type, dynamically generating
different types of cfg and layout attributes during initialization based
on this type. Static variables are stored in cfg, while parsed values
are organized into the layout structure.

Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
---
 drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h |    1 +
 drivers/phy/qualcomm/phy-qcom-qmp-usbc.c   | 1453 ++++++++++++++++++++++++----
 2 files changed, 1254 insertions(+), 200 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h
index 0ebd405bcaf0cac8215550bfc9b226f30cc43a59..59885616405f878885d0837838a0bac1899fb69f 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h
@@ -25,6 +25,7 @@
 #define QSERDES_DP_PHY_AUX_CFG7				0x03c
 #define QSERDES_DP_PHY_AUX_CFG8				0x040
 #define QSERDES_DP_PHY_AUX_CFG9				0x044
+#define QSERDES_DP_PHY_VCO_DIV				0x068
 
 /* QSERDES COM_BIAS_EN_CLKBUFLR_EN bits */
 # define QSERDES_V3_COM_BIAS_EN				0x0001
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index cf12a6f12134dc77ff032f967b2efa43e3de4b21..7fece9d7dc959ed5a7c62077d8552324c3734859 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -22,13 +22,20 @@
 #include <linux/slab.h>
 #include <linux/usb/typec.h>
 #include <linux/usb/typec_mux.h>
+#include <dt-bindings/phy/phy-qcom-qmp.h>
+#include <drm/bridge/aux-bridge.h>
 
 #include "phy-qcom-qmp-common.h"
 
 #include "phy-qcom-qmp.h"
 #include "phy-qcom-qmp-pcs-misc-v3.h"
 
+#include "phy-qcom-qmp-dp-phy.h"
+#include "phy-qcom-qmp-dp-phy-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 {
@@ -284,7 +291,26 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = {
 	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88),
 };
 
-struct qmp_usbc_offsets {
+enum qmp_phy_usbc_type {
+	QMP_PHY_USBC_INVALID,
+	QMP_PHY_USBC_USB,
+	QMP_PHY_USBC_DP,
+};
+
+/* list of regulators */
+struct qmp_regulator_data {
+	const char *name;
+	unsigned int enable_load;
+};
+
+struct dev_cfg {
+	int type;
+	const void *cfg;
+};
+
+struct qmp_usbc;
+
+struct qmp_usbc_usb_offsets {
 	u16 serdes;
 	u16 pcs;
 	u16 pcs_misc;
@@ -295,9 +321,9 @@ struct qmp_usbc_offsets {
 	u16 rx2;
 };
 
-/* struct qmp_phy_cfg - per-PHY initialization config */
-struct qmp_phy_cfg {
-	const struct qmp_usbc_offsets *offsets;
+/* struct qmp_phy_usb_cfg - per-usb PHY initialization config */
+struct qmp_phy_usb_cfg {
+	const struct qmp_usbc_usb_offsets *offsets;
 
 	/* Init sequence for PHY blocks - serdes, tx, rx, pcs */
 	const struct qmp_phy_init_tbl *serdes_tbl;
@@ -317,11 +343,7 @@ struct qmp_phy_cfg {
 	const unsigned int *regs;
 };
 
-struct qmp_usbc {
-	struct device *dev;
-
-	const struct qmp_phy_cfg *cfg;
-
+struct qmp_phy_usb_layout {
 	void __iomem *serdes;
 	void __iomem *pcs;
 	void __iomem *pcs_misc;
@@ -329,28 +351,67 @@ struct qmp_usbc {
 	void __iomem *rx;
 	void __iomem *tx2;
 	void __iomem *rx2;
-
 	struct regmap *tcsr_map;
 	u32 vls_clamp_reg;
-
+	enum phy_mode mode;
+	struct typec_switch_dev *sw;
 	struct clk *pipe_clk;
+	struct clk_fixed_rate pipe_clk_fixed;
+};
+
+struct qmp_usbc_dp_offsets {
+	u16 dp_serdes;
+	u16 dp_txa;
+	u16 dp_txb;
+	u16 dp_phy;
+};
+
+/* struct qmp_phy_dp_cfg - per-dp PHY initialization config */
+struct qmp_phy_dp_cfg {
+	const struct qmp_usbc_dp_offsets *offsets;
+
+	/* DP PHY swing and pre_emphasis tables */
+	const u8 (*swing_tbl)[4][4];
+	const u8 (*pre_emphasis_tbl)[4][4];
+
+	// /* DP PHY callbacks */
+	int (*dp_aux_init)(struct qmp_usbc *qmp);
+	int (*configure_dp_serdes)(struct qmp_usbc *qmp);
+	int (*configure_dp_voltages)(struct qmp_usbc *qmp);
+	int (*configure_dp_phy)(struct qmp_usbc *qmp);
+	int (*calibrate_dp_phy)(struct qmp_usbc *qmp);
+
+	const struct qmp_regulator_data *vreg_list;
+	int num_vregs;
+};
+
+struct qmp_phy_dp_layout {
+	void __iomem *dp_phy;
+	void __iomem *dp_tx;
+	void __iomem *dp_tx2;
+	void __iomem *dp_serdes;
+	struct regmap *tcsr_map;
+	u32 dp_phy_mode;
+	unsigned int dp_aux_cfg;
+	struct phy_configure_opts_dp dp_opts;
+	struct clk_hw dp_link_hw;
+	struct clk_hw dp_pixel_hw;
+};
+
+struct qmp_usbc {
+	struct device *dev;
+	int type;
 	struct clk_bulk_data *clks;
 	int num_clks;
 	int num_resets;
 	struct reset_control_bulk_data *resets;
 	struct regulator_bulk_data *vregs;
-
 	struct mutex phy_mutex;
-
-	enum phy_mode mode;
-	unsigned int usb_init_count;
-
 	struct phy *phy;
-
-	struct clk_fixed_rate pipe_clk_fixed;
-
-	struct typec_switch_dev *sw;
 	enum typec_orientation orientation;
+	unsigned int init_count;
+	const void *cfg;
+	void *layout;
 };
 
 static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -391,12 +452,21 @@ static const char * const usb3phy_reset_l[] = {
 	"phy_phy", "phy",
 };
 
+static const char * const dp_usb3phy_reset_l[] = {
+	"phy",
+};
+
 /* list of regulators */
-static const char * const qmp_phy_vreg_l[] = {
+static const char * const qmp_phy_usb_vreg_l[] = {
 	"vdda-phy", "vdda-pll",
 };
 
-static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {
+static struct qmp_regulator_data qmp_phy_dp_vreg_l[] = {
+	{ .name = "vdda-phy", .enable_load = 21800 },
+	{ .name = "vdda-pll", .enable_load = 36000 },
+};
+
+static const struct qmp_usbc_usb_offsets qmp_usbc_usb_offsets_v3_qcm2290 = {
 	.serdes		= 0x0,
 	.pcs		= 0xc00,
 	.pcs_misc	= 0xa00,
@@ -406,8 +476,15 @@ static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {
 	.rx2		= 0x800,
 };
 
-static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
-	.offsets		= &qmp_usbc_offsets_v3_qcm2290,
+static const struct qmp_usbc_dp_offsets qmp_usbc_dp_offsets_qcs615 = {
+	.dp_serdes	= 0x0C00,
+	.dp_txa		= 0x0400,
+	.dp_txb		= 0x0800,
+	.dp_phy		= 0x0000,
+};
+
+static const struct qmp_phy_usb_cfg msm8998_usb3phy_cfg = {
+	.offsets		= &qmp_usbc_usb_offsets_v3_qcm2290,
 
 	.serdes_tbl             = msm8998_usb3_serdes_tbl,
 	.serdes_tbl_num         = ARRAY_SIZE(msm8998_usb3_serdes_tbl),
@@ -417,13 +494,13 @@ 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_usb_vreg_l,
+	.num_vregs              = ARRAY_SIZE(qmp_phy_usb_vreg_l),
 	.regs                   = qmp_v3_usb3phy_regs_layout,
 };
 
-static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = {
-	.offsets		= &qmp_usbc_offsets_v3_qcm2290,
+static const struct qmp_phy_usb_cfg qcm2290_usb3phy_cfg = {
+	.offsets		= &qmp_usbc_usb_offsets_v3_qcm2290,
 
 	.serdes_tbl		= qcm2290_usb3_serdes_tbl,
 	.serdes_tbl_num		= ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
@@ -433,13 +510,13 @@ 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_usb_vreg_l,
+	.num_vregs		= ARRAY_SIZE(qmp_phy_usb_vreg_l),
 	.regs			= qmp_v3_usb3phy_regs_layout_qcm2290,
 };
 
-static const struct qmp_phy_cfg sdm660_usb3phy_cfg = {
-	.offsets		= &qmp_usbc_offsets_v3_qcm2290,
+static const struct qmp_phy_usb_cfg sdm660_usb3phy_cfg = {
+	.offsets		= &qmp_usbc_usb_offsets_v3_qcm2290,
 
 	.serdes_tbl		= qcm2290_usb3_serdes_tbl,
 	.serdes_tbl_num		= ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
@@ -449,20 +526,352 @@ 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_usb_vreg_l,
+	.num_vregs		= ARRAY_SIZE(qmp_phy_usb_vreg_l),
 	.regs			= qmp_v3_usb3phy_regs_layout_qcm2290,
 };
 
-static int qmp_usbc_init(struct phy *phy)
+static const u8 qmp_dp_pre_emphasis_hbr2_rbr[4][4] = {
+	{0x00, 0x0B, 0x12, 0xFF},       /* pe0, 0 db */
+	{0x00, 0x0A, 0x12, 0xFF},       /* pe1, 3.5 db */
+	{0x00, 0x0C, 0xFF, 0xFF},       /* pe2, 6.0 db */
+	{0xFF, 0xFF, 0xFF, 0xFF}        /* pe3, 9.5 db */
+};
+
+static const u8 qmp_dp_voltage_swing_hbr2_rbr[4][4] = {
+	{0x07, 0x0F, 0x14, 0xFF}, /* sw0, 0.4v  */
+	{0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */
+	{0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */
+	{0xFF, 0xFF, 0xFF, 0xFF}  /* sw1, 1.2 v, optional */
+};
+
+static int qcs615_qmp_dp_aux_init(struct qmp_usbc *qmp);
+static int qcs615_qmp_configure_dp_serdes(struct qmp_usbc *qmp);
+static int qcs615_qmp_configure_dp_voltages(struct qmp_usbc *qmp);
+static int qcs615_qmp_configure_dp_phy(struct qmp_usbc *qmp);
+static int qcs615_qmp_calibrate_dp_phy(struct qmp_usbc *qmp);
+
+static void qmp_usbc_check_dp_phy(struct qmp_usbc *qmp, const char *pos);
+
+static const struct qmp_phy_dp_cfg qcs615_dpphy_cfg = {
+	.offsets		= &qmp_usbc_dp_offsets_qcs615,
+
+	.swing_tbl		= &qmp_dp_voltage_swing_hbr2_rbr,
+	.pre_emphasis_tbl	= &qmp_dp_pre_emphasis_hbr2_rbr,
+
+	.dp_aux_init		= qcs615_qmp_dp_aux_init,
+	.configure_dp_serdes	= qcs615_qmp_configure_dp_serdes,
+	.configure_dp_voltages	= qcs615_qmp_configure_dp_voltages,
+	.configure_dp_phy   = qcs615_qmp_configure_dp_phy,
+	.calibrate_dp_phy	= qcs615_qmp_calibrate_dp_phy,
+
+	.vreg_list		= qmp_phy_dp_vreg_l,
+	.num_vregs		= ARRAY_SIZE(qmp_phy_dp_vreg_l),
+};
+
+#define to_usb_cfg(x) ((struct qmp_phy_usb_cfg *)(x->cfg))
+#define to_dp_cfg(x) ((struct qmp_phy_dp_cfg *)(x->cfg))
+#define to_usb_layout(x) ((struct qmp_phy_usb_layout *)(x->layout))
+#define to_dp_layout(x) ((struct qmp_phy_dp_layout *)(x->layout))
+
+static int qcs615_qmp_dp_aux_init(struct qmp_usbc *qmp)
+{
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+
+	regmap_write(layout->tcsr_map, layout->dp_phy_mode, 0x1);
+
+	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,
+	       layout->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,
+	       layout->dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+	writel(0x00, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG0);
+	writel(0x13, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG1);
+	writel(0x00, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG2);
+	writel(0x00, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG3);
+	writel(0x0a, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG4);
+	writel(0x26, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG5);
+	writel(0x0a, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG6);
+	writel(0x03, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG7);
+	writel(0xbb, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG8);
+	writel(0x03, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG9);
+	layout->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,
+	       layout->dp_phy + QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK);
+	return 0;
+}
+
+static int qcs615_qmp_configure_dp_serdes(struct qmp_usbc *qmp)
+{
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+	void __iomem *serdes = layout->dp_serdes;
+	const struct phy_configure_opts_dp *dp_opts = &layout->dp_opts;
+	u8 hsclk_sel;
+	u8 dec_start_mode0;
+	u8 div_frac_start1_mode0;
+	u8 div_frac_start2_mode0;
+	u8 div_frac_start3_mode0;
+	u8 lock_cmp1_mode0;
+	u8 lock_cmp2_mode0;
+	u8 lock_cmp3_mode0;
+
+	switch (dp_opts->link_rate) {
+	case 1620:
+		hsclk_sel = 0x2c;
+		dec_start_mode0 = 0x69;
+		div_frac_start1_mode0 = 0x00;
+		div_frac_start2_mode0 = 0x80;
+		div_frac_start3_mode0 = 0x07;
+		lock_cmp1_mode0 = 0xbf;
+		lock_cmp2_mode0 = 0x21;
+		lock_cmp3_mode0 = 0x00;
+		break;
+	case 2700:
+		hsclk_sel = 0x24;
+		dec_start_mode0 = 0x69;
+		div_frac_start1_mode0 = 0x00;
+		div_frac_start2_mode0 = 0x80;
+		div_frac_start3_mode0 = 0x07;
+		lock_cmp1_mode0 = 0x3f;
+		lock_cmp2_mode0 = 0x38;
+		lock_cmp3_mode0 = 0x00;
+		break;
+	case 5400:
+		hsclk_sel = 0x20;
+		dec_start_mode0 = 0x8c;
+		div_frac_start1_mode0 = 0x00;
+		div_frac_start2_mode0 = 0x00;
+		div_frac_start3_mode0 = 0x0a;
+		lock_cmp1_mode0 = 0x7f;
+		lock_cmp2_mode0 = 0x70;
+		lock_cmp3_mode0 = 0x00;
+		break;
+	default:
+		/* Other link rates aren't supported */
+		return -EINVAL;
+	}
+
+	writel(0x01, serdes + QSERDES_COM_SVS_MODE_CLK_SEL);
+	writel(0x37, serdes + QSERDES_COM_SYSCLK_EN_SEL);
+	writel(0x00, serdes + QSERDES_COM_CLK_SELECT);
+	writel(0x06, serdes + QSERDES_COM_SYS_CLK_CTRL);
+	writel(0x3f, serdes + QSERDES_COM_BIAS_EN_CLKBUFLR_EN);
+	writel(0x0e, serdes + QSERDES_COM_CLK_ENABLE1);
+	writel(0x0f, serdes + QSERDES_COM_BG_CTRL);
+	writel(0x06, serdes + QSERDES_COM_SYSCLK_BUF_ENABLE);
+	writel(0x30, serdes + QSERDES_COM_CLK_SELECT);
+	writel(0x0f, serdes + QSERDES_COM_PLL_IVCO);
+	writel(0x28, serdes + QSERDES_COM_PLL_CCTRL_MODE0);
+	writel(0x16, serdes + QSERDES_COM_PLL_RCTRL_MODE0);
+	writel(0x0b, serdes + QSERDES_COM_CP_CTRL_MODE0);
+
+	writel(hsclk_sel, serdes + QSERDES_COM_HSCLK_SEL);
+	writel(dec_start_mode0, serdes + QSERDES_COM_DEC_START_MODE0);
+	writel(div_frac_start1_mode0, serdes + QSERDES_COM_DIV_FRAC_START1_MODE0);
+	writel(div_frac_start2_mode0, serdes + QSERDES_COM_DIV_FRAC_START2_MODE0);
+	writel(div_frac_start3_mode0, serdes + QSERDES_COM_DIV_FRAC_START3_MODE0);
+	writel(lock_cmp1_mode0, serdes + QSERDES_COM_LOCK_CMP1_MODE0);
+	writel(lock_cmp2_mode0, serdes + QSERDES_COM_LOCK_CMP2_MODE0);
+	writel(lock_cmp3_mode0, serdes + QSERDES_COM_LOCK_CMP3_MODE0);
+
+	writel(0x40, serdes + QSERDES_COM_INTEGLOOP_GAIN0_MODE0);
+	writel(0x00, serdes + QSERDES_COM_INTEGLOOP_GAIN1_MODE0);
+	writel(0x00, serdes + QSERDES_COM_VCO_TUNE_MAP);
+	writel(0x08, serdes + QSERDES_COM_BG_TIMER);
+	writel(0x05, serdes + QSERDES_COM_CORECLK_DIV);
+	writel(0x00, serdes + QSERDES_COM_VCO_TUNE_CTRL);
+	writel(0x00, serdes + QSERDES_COM_VCO_TUNE1_MODE0);
+	writel(0x00, serdes + QSERDES_COM_VCO_TUNE2_MODE0);
+	writel(0x00, serdes + QSERDES_COM_VCO_TUNE_CTRL);
+
+	writel(0x0f, serdes + QSERDES_COM_CORE_CLK_EN);
+
+	return 0;
+}
+
+static int qcs615_qmp_configure_dp_voltages(struct qmp_usbc *qmp)
+{
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+	struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
+	const struct phy_configure_opts_dp *dp_opts = &layout->dp_opts;
+	void __iomem *tx = layout->dp_tx;
+	void __iomem *tx2 = layout->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) || (pre_emphasis_cfg > 4)) {
+		dev_err(qmp->dev, "Invalid v(%d) | p(%d) level)\n",
+			v_level, pre_emphasis_cfg);
+		return -EINVAL;
+	}
+
+	voltage_swing_cfg = (*cfg->swing_tbl)[v_level][p_level];
+	pre_emphasis_cfg = (*cfg->pre_emphasis_tbl)[v_level][p_level];
+
+	/* Enable MUX to use Cursor values from these registers */
+	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;
+
+	/* program default setting first */
+	writel(0x2A, tx + QSERDES_V3_TX_TX_DRV_LVL);
+	writel(0x20, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
+	writel(0x2A, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
+	writel(0x20, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
+
+	writel(voltage_swing_cfg, tx + QSERDES_V3_TX_TX_DRV_LVL);
+	writel(pre_emphasis_cfg, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
+	writel(voltage_swing_cfg, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
+	writel(pre_emphasis_cfg, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
+
+	return 0;
+}
+
+static int qcs615_qmp_configure_dp_phy(struct qmp_usbc *qmp)
+{
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+	u32 status;
+
+	writel(0x01, layout->dp_phy + QSERDES_DP_PHY_CFG);
+	writel(0x05, layout->dp_phy + QSERDES_DP_PHY_CFG);
+	writel(0x01, layout->dp_phy + QSERDES_DP_PHY_CFG);
+	writel(0x09, layout->dp_phy + QSERDES_DP_PHY_CFG);
+
+	writel(0x20, layout->dp_serdes + QSERDES_COM_RESETSM_CNTRL);
+
+	// C_READY
+	if (readl_poll_timeout(layout->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;
+	}
+
+	// FREQ_DONE
+	if (readl_poll_timeout(layout->dp_serdes + QSERDES_COM_CMN_STATUS,
+			status,
+			((status & BIT(0)) > 0),
+			500,
+			10000)){
+		dev_err(qmp->dev, "FREQ_DONE not ready\n");
+		return -ETIMEDOUT;
+	}
+
+	// PLL_LOCKED
+	if (readl_poll_timeout(layout->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, layout->dp_phy + QSERDES_DP_PHY_CFG);
+	udelay(10);
+
+	// TSYNC_DONE
+	if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS,
+			status,
+			((status & BIT(0)) > 0),
+			500,
+			10000)){
+		dev_err(qmp->dev, "TSYNC_DONE not ready\n");
+		return -ETIMEDOUT;
+	}
+
+	// PHY_READY
+	if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS,
+			status,
+			((status & BIT(1)) > 0),
+			500,
+			10000)){
+		dev_err(qmp->dev, "PHY_READY not ready\n");
+		return -ETIMEDOUT;
+	}
+
+	writel(0x3f, layout->dp_tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
+	writel(0x10, layout->dp_tx + QSERDES_V3_TX_HIGHZ_DRVR_EN);
+	writel(0x0a, layout->dp_tx + QSERDES_V3_TX_TX_POL_INV);
+	writel(0x3f, layout->dp_tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
+	writel(0x10, layout->dp_tx2 + QSERDES_V3_TX_HIGHZ_DRVR_EN);
+	writel(0x0a, layout->dp_tx2 + QSERDES_V3_TX_TX_POL_INV);
+
+	writel(0x18, layout->dp_phy + QSERDES_DP_PHY_CFG);
+	writel(0x19, layout->dp_phy + QSERDES_DP_PHY_CFG);
+
+	if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_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 qcs615_qmp_calibrate_dp_phy(struct qmp_usbc *qmp)
+{
+	static const u8 cfg1_settings[] = {0x13, 0x23, 0x1d};
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+	u8 val;
+
+	layout->dp_aux_cfg++;
+	layout->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
+	val = cfg1_settings[layout->dp_aux_cfg];
+
+	writel(val, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG1);
+
+	qmp_usbc_check_dp_phy(qmp, "pos_calibrate");
+
+	return 0;
+}
+
+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;
+	int num_vregs;
 	u32 val = 0;
 	int ret;
+	unsigned int reg_pwr_dn;
 
-	ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
+	if (qmp->type == QMP_PHY_USBC_USB) {
+		struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
+
+		num_vregs = cfg->num_vregs;
+		reg_pwr_dn = cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL];
+	} else {
+		struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
+
+		num_vregs = cfg->num_vregs;
+	}
+
+	ret = regulator_bulk_enable(num_vregs, qmp->vregs);
 	if (ret) {
 		dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
 		return ret;
@@ -484,73 +893,85 @@ static int qmp_usbc_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);
+
+	if (qmp->type == QMP_PHY_USBC_USB) {
+		struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
+
+		qphy_setbits(layout->pcs, reg_pwr_dn, SW_PWRDN);
+		writel(val, layout->pcs_misc);
+	}
 
 	return 0;
 
 err_assert_reset:
 	reset_control_bulk_assert(qmp->num_resets, qmp->resets);
 err_disable_regulators:
-	regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
+	regulator_bulk_disable(num_vregs, qmp->vregs);
 
 	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;
+	int num_vregs;
 
 	reset_control_bulk_assert(qmp->num_resets, qmp->resets);
 
 	clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
 
-	regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
+	if (qmp->type == QMP_PHY_USBC_USB) {
+		struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
+
+		num_vregs = cfg->num_vregs;
+	} else {
+		struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
+
+		num_vregs = cfg->num_vregs;
+	}
+	regulator_bulk_disable(num_vregs, qmp->vregs);
 
 	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;
+	const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
+	struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
 	void __iomem *status;
 	unsigned int val;
 	int ret;
 
-	qmp_configure(qmp->dev, qmp->serdes, cfg->serdes_tbl,
+	qmp_configure(qmp->dev, layout->serdes, cfg->serdes_tbl,
 		      cfg->serdes_tbl_num);
 
-	ret = clk_prepare_enable(qmp->pipe_clk);
+	ret = clk_prepare_enable(layout->pipe_clk);
 	if (ret) {
 		dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret);
 		return ret;
 	}
 
 	/* Tx, Rx, and PCS configurations */
-	qmp_configure_lane(qmp->dev, qmp->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
-	qmp_configure_lane(qmp->dev, qmp->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
+	qmp_configure_lane(qmp->dev, layout->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
+	qmp_configure_lane(qmp->dev, layout->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
 
-	qmp_configure_lane(qmp->dev, qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);
-	qmp_configure_lane(qmp->dev, qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
+	qmp_configure_lane(qmp->dev, layout->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);
+	qmp_configure_lane(qmp->dev, layout->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
 
-	qmp_configure(qmp->dev, qmp->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
+	qmp_configure(qmp->dev, layout->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
 
 	/* Pull PHY out of reset state */
-	qphy_clrbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
+	qphy_clrbits(layout->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
 	/* start SerDes and Phy-Coding-Sublayer */
-	qphy_setbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START);
+	qphy_setbits(layout->pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START);
 
-	status = qmp->pcs + cfg->regs[QPHY_PCS_STATUS];
+	status = layout->pcs + cfg->regs[QPHY_PCS_STATUS];
 	ret = readl_poll_timeout(status, val, !(val & PHYSTATUS), 200,
 				 PHY_INIT_COMPLETE_TIMEOUT);
 	if (ret) {
@@ -561,92 +982,348 @@ static int qmp_usbc_power_on(struct phy *phy)
 	return 0;
 
 err_disable_pipe_clk:
-	clk_disable_unprepare(qmp->pipe_clk);
+	clk_disable_unprepare(layout->pipe_clk);
 
 	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;
+	const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
+	struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
 
-	clk_disable_unprepare(qmp->pipe_clk);
+	clk_disable_unprepare(layout->pipe_clk);
 
 	/* PHY reset */
-	qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
+	qphy_setbits(layout->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
 	/* stop SerDes and Phy-Coding-Sublayer */
-	qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL],
+	qphy_clrbits(layout->pcs, cfg->regs[QPHY_START_CTRL],
 			SERDES_START | PCS_START);
 
 	/* Put PHY into POWER DOWN state: active low */
-	qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
+	qphy_clrbits(layout->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
 			SW_PWRDN);
 
 	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;
 	}
 
-	qmp->usb_init_count++;
+	qmp->init_count++;
 out_unlock:
 	mutex_unlock(&qmp->phy_mutex);
 
 	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);
+	qmp->init_count--;
+	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_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+	struct qmp_usbc *qmp = phy_get_drvdata(phy);
+	struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
+
+	layout->mode = mode;
+
+	return 0;
+}
+
+static int qmp_usbc_dp_init(struct phy *phy)
+{
+	struct qmp_usbc *qmp = phy_get_drvdata(phy);
+	const struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
+	int ret;
+
+	if (qmp->init_count) {
+		dev_err(qmp->dev, "type(%d) inited(%d)\n", qmp->type, qmp->init_count);
+		return 0;
+	}
+
+	mutex_lock(&qmp->phy_mutex);
+
+	ret = qmp_usbc_com_init(phy);
+	if (ret) {
+		dev_err(qmp->dev, "type(%d) com_init fail\n", qmp->type);
+		goto dp_init_unlock;
+	}
+
+	cfg->dp_aux_init(qmp);
+
+	qmp->init_count++;
+
+dp_init_unlock:
+	mutex_unlock(&qmp->phy_mutex);
+	return ret;
+}
+
+static int qmp_usbc_dp_exit(struct phy *phy)
+{
+	struct qmp_usbc *qmp = phy_get_drvdata(phy);
+
+	mutex_lock(&qmp->phy_mutex);
+
+	qmp_usbc_com_exit(phy);
+
+	qmp->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);
+	struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+	int ret;
+
+	mutex_lock(&qmp->phy_mutex);
+
+	memcpy(&layout->dp_opts, dp_opts, sizeof(*dp_opts));
+	if (layout->dp_opts.set_voltages) {
+		ret = cfg->configure_dp_voltages(qmp);
+		if (ret) {
+			dev_err(qmp->dev, "type(%d) err(%d)\n", qmp->type, ret);
+			mutex_unlock(&qmp->phy_mutex);
+			return ret;
+		}
+
+		layout->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);
+	struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
+	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, "type(%d) err(%d)\n", qmp->type, ret);
+			mutex_unlock(&qmp->phy_mutex);
+			return ret;
+		}
+	}
+
+	mutex_unlock(&qmp->phy_mutex);
+	return 0;
 }
 
-static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+static int qmp_usbc_configure_dp_clocks(struct qmp_usbc *qmp)
+{
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+	const struct phy_configure_opts_dp *dp_opts = &layout->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;
+	case 8100:
+		phy_vco_div = 0x0;
+		pixel_freq = 8100000000UL / 6;
+		break;
+	default:
+		/* Other link rates aren't supported */
+		return -EINVAL;
+	}
+	writel(phy_vco_div, layout->dp_phy + QSERDES_DP_PHY_VCO_DIV);
+
+	clk_set_rate(layout->dp_link_hw.clk, dp_opts->link_rate * 100000);
+	clk_set_rate(layout->dp_pixel_hw.clk, pixel_freq);
+
+	return 0;
+}
+
+static void qmp_usbc_check_dp_phy(struct qmp_usbc *qmp, const char *pos)
+{
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+	u8 c_ready, cmn_status, phy_status;
+
+	c_ready = readl(layout->dp_serdes + QSERDES_COM_C_READY_STATUS);
+	cmn_status = readl(layout->dp_serdes + QSERDES_COM_CMN_STATUS);
+	phy_status = readl(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS);
+
+	dev_dbg(qmp->dev, "pos(%s) c_ready(0x%x) cmn_status(0x%x) phy_status(0x%x)\n",
+		pos, c_ready, cmn_status, phy_status);
+}
+
+static int qmp_usbc_dp_power_on(struct phy *phy)
+{
+	struct qmp_usbc *qmp = phy_get_drvdata(phy);
+	const struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+	const struct phy_configure_opts_dp *dp_opts = &layout->dp_opts;
+	bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
+	void __iomem *tx = layout->dp_tx;
+	void __iomem *tx2 = layout->dp_tx2;
+	u8 lane_mode_1;
+	int ret = 0;
+
+	mutex_lock(&qmp->phy_mutex);
+
+	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,
+		layout->dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+	ret = cfg->configure_dp_serdes(qmp);
+	if (ret) {
+		dev_err(qmp->dev, "failed to config pll\n");
+		goto power_on_unlock;
+	}
+
+	if (dp_opts->link_rate >= 2700)
+		lane_mode_1 = 0xc4;
+	else
+		lane_mode_1 = 0xc6;
+
+	writel(lane_mode_1, tx + QSERDES_V3_TX_LANE_MODE_1);
+	writel(lane_mode_1, tx2 + QSERDES_V3_TX_LANE_MODE_1);
+
+	if (reverse)
+		writel(0xc9, layout->dp_phy + QSERDES_DP_PHY_MODE);
+	else
+		writel(0xd9, layout->dp_phy + QSERDES_DP_PHY_MODE);
+
+	writel(0x05, layout->dp_phy + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL);
+	writel(0x05, layout->dp_phy + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL);
+
+	writel(0x1a, tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
+	writel(0x40, tx + QSERDES_V3_TX_VMODE_CTRL1);
+	writel(0x30, tx + QSERDES_V3_TX_PRE_STALL_LDO_BOOST_EN);
+	writel(0x3d, tx + QSERDES_V3_TX_INTERFACE_SELECT);
+	writel(0x0f, tx + QSERDES_V3_TX_CLKBUF_ENABLE);
+	writel(0x03, tx + QSERDES_V3_TX_RESET_TSYNC_EN);
+	writel(0x03, tx + QSERDES_V3_TX_TRAN_DRVR_EMP_EN);
+	writel(0x00, tx + QSERDES_V3_TX_PARRATE_REC_DETECT_IDLE_EN);
+	writel(0x00, tx + QSERDES_V3_TX_TX_INTERFACE_MODE);
+	writel(0x2b, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
+	writel(0x2f, tx + QSERDES_V3_TX_TX_DRV_LVL);
+	writel(0x04, tx + QSERDES_V3_TX_TX_BAND);
+	writel(0x12, tx + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX);
+	writel(0x12, tx + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX);
+
+	writel(0x1a, tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
+	writel(0x40, tx2 + QSERDES_V3_TX_VMODE_CTRL1);
+	writel(0x30, tx2 + QSERDES_V3_TX_PRE_STALL_LDO_BOOST_EN);
+	writel(0x3d, tx2 + QSERDES_V3_TX_INTERFACE_SELECT);
+	writel(0x0f, tx2 + QSERDES_V3_TX_CLKBUF_ENABLE);
+	writel(0x03, tx2 + QSERDES_V3_TX_RESET_TSYNC_EN);
+	writel(0x03, tx2 + QSERDES_V3_TX_TRAN_DRVR_EMP_EN);
+	writel(0x00, tx2 + QSERDES_V3_TX_PARRATE_REC_DETECT_IDLE_EN);
+	writel(0x00, tx2 + QSERDES_V3_TX_TX_INTERFACE_MODE);
+	writel(0x2b, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
+	writel(0x2f, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
+	writel(0x04, tx2 + QSERDES_V3_TX_TX_BAND);
+	writel(0x12, tx2 + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX);
+	writel(0x12, tx2 + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX);
+
+	writel(0x02, layout->dp_serdes + QSERDES_COM_CMN_CONFIG);
+	qmp_usbc_configure_dp_clocks(qmp);
+
+	ret = cfg->configure_dp_phy(qmp);
+	if (ret) {
+		dev_err(qmp->dev, "failed to config dp phy\n");
+		goto power_on_unlock;
+	}
+
+	qmp_usbc_check_dp_phy(qmp, "usbc_dp_power_on_finish");
+
+power_on_unlock:
+	mutex_unlock(&qmp->phy_mutex);
+
+	return ret;
+}
+
+static int qmp_usbc_dp_power_off(struct phy *phy)
 {
 	struct qmp_usbc *qmp = phy_get_drvdata(phy);
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+
+	mutex_lock(&qmp->phy_mutex);
 
-	qmp->mode = mode;
+	/* Assert DP PHY power down */
+	writel(DP_PHY_PD_CTL_PSR_PWRDN, layout->dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+	mutex_unlock(&qmp->phy_mutex);
 
 	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,
+};
+
+static const struct phy_ops qmp_usbc_dp_phy_ops = {
+	.init		= qmp_usbc_dp_init,
+	.exit		= qmp_usbc_dp_exit,
+	.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;
-	void __iomem *pcs = qmp->pcs;
+	const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
+	struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
+	void __iomem *pcs = layout->pcs;
 	u32 intr_mask;
 
-	if (qmp->mode == PHY_MODE_USB_HOST_SS ||
-	    qmp->mode == PHY_MODE_USB_DEVICE_SS)
+	if (layout->mode == PHY_MODE_USB_HOST_SS ||
+	    layout->mode == PHY_MODE_USB_DEVICE_SS)
 		intr_mask = ARCVR_DTCT_EN | ALFPS_DTCT_EN;
 	else
 		intr_mask = ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL;
@@ -663,18 +1340,19 @@ static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp)
 	qphy_setbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask);
 
 	/* Enable i/o clamp_n for autonomous mode */
-	if (qmp->tcsr_map && qmp->vls_clamp_reg)
-		regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 1);
+	if (layout->tcsr_map && layout->vls_clamp_reg)
+		regmap_write(layout->tcsr_map, layout->vls_clamp_reg, 1);
 }
 
 static void qmp_usbc_disable_autonomous_mode(struct qmp_usbc *qmp)
 {
-	const struct qmp_phy_cfg *cfg = qmp->cfg;
-	void __iomem *pcs = qmp->pcs;
+	const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
+	struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
+	void __iomem *pcs = layout->pcs;
 
 	/* Disable i/o clamp_n on resume for normal mode */
-	if (qmp->tcsr_map && qmp->vls_clamp_reg)
-		regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 0);
+	if (layout->tcsr_map && layout->vls_clamp_reg)
+		regmap_write(layout->tcsr_map, layout->vls_clamp_reg, 0);
 
 	qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL],
 		     ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL | ALFPS_DTCT_EN);
@@ -688,16 +1366,19 @@ static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev)
 {
 	struct qmp_usbc *qmp = dev_get_drvdata(dev);
 
-	dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode);
-
 	if (!qmp->phy->init_count) {
 		dev_vdbg(dev, "PHY not initialized, bailing out\n");
 		return 0;
 	}
 
-	qmp_usbc_enable_autonomous_mode(qmp);
+	if (qmp->type == QMP_PHY_USBC_USB) {
+		struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
+
+		dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", layout->mode);
+		qmp_usbc_enable_autonomous_mode(qmp);
+		clk_disable_unprepare(layout->pipe_clk);
+	}
 
-	clk_disable_unprepare(qmp->pipe_clk);
 	clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
 
 	return 0;
@@ -708,8 +1389,6 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev)
 	struct qmp_usbc *qmp = dev_get_drvdata(dev);
 	int ret = 0;
 
-	dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode);
-
 	if (!qmp->phy->init_count) {
 		dev_vdbg(dev, "PHY not initialized, bailing out\n");
 		return 0;
@@ -719,14 +1398,19 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev)
 	if (ret)
 		return ret;
 
-	ret = clk_prepare_enable(qmp->pipe_clk);
-	if (ret) {
-		dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);
-		clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
-		return ret;
-	}
+	if (qmp->type == QMP_PHY_USBC_USB) {
+		struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
 
-	qmp_usbc_disable_autonomous_mode(qmp);
+		dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", layout->mode);
+		ret = clk_prepare_enable(layout->pipe_clk);
+		if (ret) {
+			dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);
+			clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
+			return ret;
+		}
+
+		qmp_usbc_disable_autonomous_mode(qmp);
+	}
 
 	return 0;
 }
@@ -738,19 +1422,54 @@ static const struct dev_pm_ops qmp_usbc_pm_ops = {
 
 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;
+	int ret, i;
 
-	qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL);
-	if (!qmp->vregs)
-		return -ENOMEM;
+	if (qmp->type == QMP_PHY_USBC_USB) {
+		struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
+		int num = cfg->num_vregs;
 
-	for (i = 0; i < num; i++)
-		qmp->vregs[i].supply = cfg->vreg_list[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);
+		ret = devm_regulator_bulk_get(dev, num, qmp->vregs);
+		if (ret) {
+			dev_err(dev, "failed at devm_regulator_bulk_get\n");
+			return ret;
+		}
+	} else {
+		struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
+		int num = cfg->num_vregs;
+
+		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].name;
+
+		ret = devm_regulator_bulk_get(dev, num, qmp->vregs);
+		if (ret) {
+			dev_err(dev, "failed at devm_regulator_bulk_get\n");
+			return ret;
+		}
+
+		for (i = 0; i < num; i++) {
+			ret = regulator_set_load(qmp->vregs[i].consumer,
+						cfg->vreg_list[i].enable_load);
+			if (ret) {
+				dev_err(dev, "failed to set load at %s\n",
+					qmp->vregs[i].supply);
+				return ret;
+			}
+		}
+	}
+
+	return 0;
 }
 
 static int qmp_usbc_reset_init(struct qmp_usbc *qmp,
@@ -821,7 +1540,9 @@ static void phy_clk_release_provider(void *res)
  */
 static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np)
 {
-	struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed;
+	struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
+
+	struct clk_fixed_rate *fixed = &layout->pipe_clk_fixed;
 	struct clk_init_data init = { };
 	int ret;
 
@@ -864,12 +1585,12 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw,
 	mutex_lock(&qmp->phy_mutex);
 	qmp->orientation = orientation;
 
-	if (qmp->usb_init_count) {
-		qmp_usbc_power_off(qmp->phy);
-		qmp_usbc_exit(qmp->phy);
+	if (qmp->init_count) {
+		qmp_usbc_usb_power_off(qmp->phy);
+		qmp_usbc_com_exit(qmp->phy);
 
-		qmp_usbc_init(qmp->phy);
-		qmp_usbc_power_on(qmp->phy);
+		qmp_usbc_com_init(qmp->phy);
+		qmp_usbc_usb_power_on(qmp->phy);
 	}
 
 	mutex_unlock(&qmp->phy_mutex);
@@ -880,22 +1601,24 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw,
 static void qmp_usbc_typec_unregister(void *data)
 {
 	struct qmp_usbc *qmp = data;
+	struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
 
-	typec_switch_unregister(qmp->sw);
+	typec_switch_unregister(layout->sw);
 }
 
 static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp)
 {
 	struct typec_switch_desc sw_desc = {};
 	struct device *dev = qmp->dev;
+	struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
 
 	sw_desc.drvdata = qmp;
 	sw_desc.fwnode = dev->fwnode;
 	sw_desc.set = qmp_usbc_typec_switch_set;
-	qmp->sw = typec_switch_register(dev, &sw_desc);
-	if (IS_ERR(qmp->sw)) {
-		dev_err(dev, "Unable to register typec switch: %pe\n", qmp->sw);
-		return PTR_ERR(qmp->sw);
+	layout->sw = typec_switch_register(dev, &sw_desc);
+	if (IS_ERR(layout->sw)) {
+		dev_err(dev, "Unable to register typec switch: %pe\n", layout->sw);
+		return PTR_ERR(layout->sw);
 	}
 
 	return devm_add_action_or_reset(dev, qmp_usbc_typec_unregister, qmp);
@@ -907,15 +1630,16 @@ static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp)
 }
 #endif
 
-static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np)
+static int qmp_usbc_parse_usb_dt_legacy(struct qmp_usbc *qmp, struct device_node *np)
 {
 	struct platform_device *pdev = to_platform_device(qmp->dev);
 	struct device *dev = qmp->dev;
+	struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
 	int ret;
 
-	qmp->serdes = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(qmp->serdes))
-		return PTR_ERR(qmp->serdes);
+	layout->serdes = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(layout->serdes))
+		return PTR_ERR(layout->serdes);
 
 	/*
 	 * Get memory resources for the PHY:
@@ -923,35 +1647,35 @@ static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np
 	 * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5
 	 * For single lane PHYs: pcs_misc (optional) -> 3.
 	 */
-	qmp->tx = devm_of_iomap(dev, np, 0, NULL);
-	if (IS_ERR(qmp->tx))
-		return PTR_ERR(qmp->tx);
+	layout->tx = devm_of_iomap(dev, np, 0, NULL);
+	if (IS_ERR(layout->tx))
+		return PTR_ERR(layout->tx);
 
-	qmp->rx = devm_of_iomap(dev, np, 1, NULL);
-	if (IS_ERR(qmp->rx))
-		return PTR_ERR(qmp->rx);
+	layout->rx = devm_of_iomap(dev, np, 1, NULL);
+	if (IS_ERR(layout->rx))
+		return PTR_ERR(layout->rx);
 
-	qmp->pcs = devm_of_iomap(dev, np, 2, NULL);
-	if (IS_ERR(qmp->pcs))
-		return PTR_ERR(qmp->pcs);
+	layout->pcs = devm_of_iomap(dev, np, 2, NULL);
+	if (IS_ERR(layout->pcs))
+		return PTR_ERR(layout->pcs);
 
-	qmp->tx2 = devm_of_iomap(dev, np, 3, NULL);
-	if (IS_ERR(qmp->tx2))
-		return PTR_ERR(qmp->tx2);
+	layout->tx2 = devm_of_iomap(dev, np, 3, NULL);
+	if (IS_ERR(layout->tx2))
+		return PTR_ERR(layout->tx2);
 
-	qmp->rx2 = devm_of_iomap(dev, np, 4, NULL);
-	if (IS_ERR(qmp->rx2))
-		return PTR_ERR(qmp->rx2);
+	layout->rx2 = devm_of_iomap(dev, np, 4, NULL);
+	if (IS_ERR(layout->rx2))
+		return PTR_ERR(layout->rx2);
 
-	qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
-	if (IS_ERR(qmp->pcs_misc)) {
+	layout->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
+	if (IS_ERR(layout->pcs_misc)) {
 		dev_vdbg(dev, "PHY pcs_misc-reg not used\n");
-		qmp->pcs_misc = NULL;
+		layout->pcs_misc = NULL;
 	}
 
-	qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
-	if (IS_ERR(qmp->pipe_clk)) {
-		return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
+	layout->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
+	if (IS_ERR(layout->pipe_clk)) {
+		return dev_err_probe(dev, PTR_ERR(layout->pipe_clk),
 				     "failed to get pipe clock\n");
 	}
 
@@ -969,11 +1693,12 @@ static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np
 	return 0;
 }
 
-static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
+static int qmp_usbc_parse_usb_dt(struct qmp_usbc *qmp)
 {
 	struct platform_device *pdev = to_platform_device(qmp->dev);
-	const struct qmp_phy_cfg *cfg = qmp->cfg;
-	const struct qmp_usbc_offsets *offs = cfg->offsets;
+	const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
+	const struct qmp_usbc_usb_offsets *offs = cfg->offsets;
+	struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
 	struct device *dev = qmp->dev;
 	void __iomem *base;
 	int ret;
@@ -985,23 +1710,23 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
-	qmp->serdes = base + offs->serdes;
-	qmp->pcs = base + offs->pcs;
+	layout->serdes = base + offs->serdes;
+	layout->pcs = base + offs->pcs;
 	if (offs->pcs_misc)
-		qmp->pcs_misc = base + offs->pcs_misc;
-	qmp->tx = base + offs->tx;
-	qmp->rx = base + offs->rx;
+		layout->pcs_misc = base + offs->pcs_misc;
+	layout->tx = base + offs->tx;
+	layout->rx = base + offs->rx;
 
-	qmp->tx2 = base + offs->tx2;
-	qmp->rx2 = base + offs->rx2;
+	layout->tx2 = base + offs->tx2;
+	layout->rx2 = base + offs->rx2;
 
 	ret = qmp_usbc_clk_init(qmp);
 	if (ret)
 		return ret;
 
-	qmp->pipe_clk = devm_clk_get(dev, "pipe");
-	if (IS_ERR(qmp->pipe_clk)) {
-		return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
+	layout->pipe_clk = devm_clk_get(dev, "pipe");
+	if (IS_ERR(layout->pipe_clk)) {
+		return dev_err_probe(dev, PTR_ERR(layout->pipe_clk),
 				     "failed to get pipe clock\n");
 	}
 
@@ -1013,10 +1738,11 @@ 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_usb_vls_clamp(struct qmp_usbc *qmp)
 {
 	struct of_phandle_args tcsr_args;
 	struct device *dev = qmp->dev;
+	struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
 	int ret;
 
 	/*  for backwards compatibility ignore if there is no property */
@@ -1027,22 +1753,280 @@ static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp)
 	else if (ret < 0)
 		return dev_err_probe(dev, ret, "Failed to parse qcom,tcsr-reg\n");
 
-	qmp->tcsr_map = syscon_node_to_regmap(tcsr_args.np);
+	layout->tcsr_map = syscon_node_to_regmap(tcsr_args.np);
 	of_node_put(tcsr_args.np);
-	if (IS_ERR(qmp->tcsr_map))
-		return PTR_ERR(qmp->tcsr_map);
+	if (IS_ERR(layout->tcsr_map))
+		return PTR_ERR(layout->tcsr_map);
 
-	qmp->vls_clamp_reg = tcsr_args.args[0];
+	layout->vls_clamp_reg = tcsr_args.args[0];
 
 	return 0;
 }
 
+static int qmp_usbc_parse_dp_phy_mode(struct qmp_usbc *qmp)
+{
+	struct of_phandle_args tcsr_args;
+	struct device *dev = qmp->dev;
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+	int ret;
+
+	/*  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);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to parse qcom,tcsr-reg\n");
+
+	layout->tcsr_map = syscon_node_to_regmap(tcsr_args.np);
+	of_node_put(tcsr_args.np);
+	if (IS_ERR(layout->tcsr_map))
+		return PTR_ERR(layout->tcsr_map);
+
+	layout->dp_phy_mode = tcsr_args.args[0];
+
+	return 0;
+}
+
+static int qmp_usbc_parse_dp_dt(struct qmp_usbc *qmp)
+{
+	struct platform_device *pdev = to_platform_device(qmp->dev);
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+	struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
+	const struct qmp_usbc_dp_offsets *offs = cfg->offsets;
+	struct device *dev = qmp->dev;
+	void __iomem *base;
+	int ret;
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base)) {
+		dev_err(dev, "get resource fail, ret:%d\n", ret);
+		return PTR_ERR(base);
+	}
+
+	layout->dp_serdes = base + offs->dp_serdes;
+	layout->dp_tx = base + offs->dp_txa;
+	layout->dp_tx2 = base + offs->dp_txb;
+	layout->dp_phy = base + offs->dp_phy;
+
+	ret = qmp_usbc_clk_init(qmp);
+	if (ret) {
+		dev_err(dev, "clk init fail, ret:%d\n", ret);
+		return ret;
+	}
+
+	ret = qmp_usbc_reset_init(qmp, dp_usb3phy_reset_l,
+				 ARRAY_SIZE(dp_usb3phy_reset_l));
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * 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 and 8.1 GHz are same link rate as 2.7GHz, i.e. div 4 and div 6 */
+		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;
+	struct qmp_phy_dp_layout *layout;
+	const struct phy_configure_opts_dp *dp_opts;
+
+	layout = container_of(hw, struct qmp_phy_dp_layout, dp_pixel_hw);
+
+	dp_opts = &layout->dp_opts;
+
+	switch (dp_opts->link_rate) {
+	case 1620:
+		return 1620000000UL / 2;
+	case 2700:
+		return 2700000000UL / 2;
+	case 5400:
+		return 5400000000UL / 4;
+	case 8100:
+		return 8100000000UL / 6;
+	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:
+	case 810000000:
+		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_combo *qmp;
+	struct qmp_phy_dp_layout *layout;
+	const struct phy_configure_opts_dp *dp_opts;
+
+	layout = container_of(hw, struct qmp_phy_dp_layout, dp_link_hw);
+	dp_opts = &layout->dp_opts;
+
+	switch (dp_opts->link_rate) {
+	case 1620:
+	case 2700:
+	case 5400:
+	case 8100:
+		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 = { };
+	int ret = 0;
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+
+	ret = of_property_read_string_index(np, "clock-output-names", 0, &init.name);
+	if (ret < 0) {
+		dev_err(qmp->dev, "%pOFn: No link clock-output-names\n", np);
+		return ret;
+	}
+
+	init.ops = &qmp_dp_link_clk_ops;
+	layout->dp_link_hw.init = &init;
+	ret = devm_clk_hw_register(qmp->dev, &layout->dp_link_hw);
+	if (ret < 0) {
+		dev_err(qmp->dev, "link clk reg fail ret=%d\n", ret);
+		return ret;
+	}
+
+	ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
+	if (ret) {
+		dev_err(qmp->dev, "%pOFn: No div clock-output-names\n", np);
+		return ret;
+	}
+
+	init.ops = &qmp_dp_pixel_clk_ops;
+	layout->dp_pixel_hw.init = &init;
+	ret = devm_clk_hw_register(qmp->dev, &layout->dp_pixel_hw);
+	if (ret) {
+		dev_err(qmp->dev, "pxl clk reg fail ret=%d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct clk_hw *qmp_dp_clks_hw_get(struct of_phandle_args *clkspec, void *data)
+{
+	struct qmp_usbc *qmp = data;
+	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
+
+	switch (clkspec->args[0]) {
+	case QMP_USB43DP_DP_LINK_CLK:
+		return &layout->dp_link_hw;
+	case QMP_USB43DP_DP_VCO_DIV_CLK:
+		return &layout->dp_pixel_hw;
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+static int qmp_dp_register_clocks(struct qmp_usbc *qmp, struct device_node *dp_np)
+{
+	int ret;
+
+	ret = phy_dp_clks_register(qmp, dp_np);
+	if (ret) {
+		dev_err(qmp->dev, "dp clk reg fail ret:%d\n", ret);
+		return ret;
+	}
+
+	ret = of_clk_add_hw_provider(dp_np, qmp_dp_clks_hw_get, qmp);
+	if (ret) {
+		dev_err(qmp->dev, "add provider fail ret:%d\n", ret);
+		return ret;
+	}
+
+	return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, dp_np);
+}
+
 static int qmp_usbc_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct phy_provider *phy_provider;
 	struct device_node *np;
 	struct qmp_usbc *qmp;
+	const struct dev_cfg *data_cfg;
 	int ret;
 
 	qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL);
@@ -1050,38 +2034,74 @@ static int qmp_usbc_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	qmp->dev = dev;
-	dev_set_drvdata(dev, qmp);
 
 	qmp->orientation = TYPEC_ORIENTATION_NORMAL;
 
-	qmp->cfg = of_device_get_match_data(dev);
-	if (!qmp->cfg)
+	qmp->init_count = 0;
+
+	data_cfg = of_device_get_match_data(dev);
+	if (!data_cfg) {
+		dev_err(qmp->dev, "get data fail\n");
 		return -EINVAL;
+	}
 
 	mutex_init(&qmp->phy_mutex);
 
-	ret = qmp_usbc_vreg_init(qmp);
-	if (ret)
-		return ret;
+	qmp->type = data_cfg->type;
+	qmp->cfg = data_cfg->cfg;
 
-	ret = qmp_usbc_typec_switch_register(qmp);
-	if (ret)
+	ret = qmp_usbc_vreg_init(qmp);
+	if (ret) {
+		dev_err(qmp->dev, "qmp_type(%d) vreg init fail\n", qmp->type);
 		return ret;
+	}
 
-	ret = qmp_usbc_parse_vls_clamp(qmp);
-	if (ret)
-		return ret;
+	if (qmp->type == QMP_PHY_USBC_USB) {
+		qmp->layout = devm_kzalloc(dev, sizeof(struct qmp_phy_usb_layout), GFP_KERNEL);
+		if (!qmp->layout)
+			return -ENOMEM;
+
+		ret = qmp_usbc_typec_switch_register(qmp);
+		if (ret)
+			return ret;
+
+		ret = qmp_usbc_parse_usb_vls_clamp(qmp);
+		if (ret)
+			return ret;
+
+		/* Check for legacy binding with child node. */
+		np = of_get_child_by_name(dev->of_node, "phy");
+		if (np) {
+			ret = qmp_usbc_parse_usb_dt_legacy(qmp, np);
+		} else {
+			np = of_node_get(dev->of_node);
+			ret = qmp_usbc_parse_usb_dt(qmp);
+		}
+		if (ret)
+			goto err_node_put;
+	} else if (qmp->type == QMP_PHY_USBC_DP) {
+		qmp->layout = devm_kzalloc(dev, sizeof(struct qmp_phy_dp_layout), GFP_KERNEL);
+		if (!qmp->layout)
+			return -ENOMEM;
 
-	/* Check for legacy binding with child node. */
-	np = of_get_child_by_name(dev->of_node, "phy");
-	if (np) {
-		ret = qmp_usbc_parse_dt_legacy(qmp, np);
-	} else {
 		np = of_node_get(dev->of_node);
-		ret = qmp_usbc_parse_dt(qmp);
-	}
-	if (ret)
+		ret = qmp_usbc_parse_dp_phy_mode(qmp);
+		if (ret)
+			goto err_node_put;
+
+		ret = qmp_usbc_parse_dp_dt(qmp);
+		if (ret)
+			goto err_node_put;
+
+		ret = drm_aux_bridge_register(dev);
+		if (ret) {
+			dev_err(qmp->dev, "aux bridge reg fail ret=%d\n", ret);
+			goto err_node_put;
+		}
+	} else {
+		dev_err(dev, "invalid phy type: %d\n", qmp->type);
 		goto err_node_put;
+	}
 
 	pm_runtime_set_active(dev);
 	ret = devm_pm_runtime_enable(dev);
@@ -1093,19 +2113,33 @@ static int qmp_usbc_probe(struct platform_device *pdev)
 	 */
 	pm_runtime_forbid(dev);
 
-	ret = phy_pipe_clk_register(qmp, np);
-	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);
-		dev_err(dev, "failed to create PHY: %d\n", ret);
-		goto err_node_put;
+	if (qmp->type == QMP_PHY_USBC_USB) {
+		// pipe clk process
+		ret = phy_pipe_clk_register(qmp, np);
+		if (ret)
+			goto err_node_put;
+
+		qmp->phy = devm_phy_create(dev, np, &qmp_usbc_usb_phy_ops);
+		if (IS_ERR(qmp->phy)) {
+			ret = PTR_ERR(qmp->phy);
+			dev_err(dev, "failed to create PHY: %d\n", ret);
+			goto err_node_put;
+		}
+	} else {
+		ret = qmp_dp_register_clocks(qmp, np);
+		if (ret)
+			goto err_node_put;
+
+		qmp->phy = devm_phy_create(dev, np, &qmp_usbc_dp_phy_ops);
+		if (IS_ERR(qmp->phy)) {
+			ret = PTR_ERR(qmp->phy);
+			dev_err(dev, "failed to create PHY: %d\n", ret);
+			goto err_node_put;
+		}
 	}
 
 	phy_set_drvdata(qmp->phy, qmp);
-
+	dev_set_drvdata(dev, qmp);
 	of_node_put(np);
 
 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
@@ -1120,19 +2154,38 @@ static int qmp_usbc_probe(struct platform_device *pdev)
 static const struct of_device_id qmp_usbc_of_match_table[] = {
 	{
 		.compatible = "qcom,msm8998-qmp-usb3-phy",
-		.data = &msm8998_usb3phy_cfg,
+		.data =  &(struct dev_cfg) {
+			.type = QMP_PHY_USBC_USB,
+			.cfg = &msm8998_usb3phy_cfg,
+		},
 	}, {
 		.compatible = "qcom,qcm2290-qmp-usb3-phy",
-		.data = &qcm2290_usb3phy_cfg,
+		.data =  &(struct dev_cfg) {
+			.type = QMP_PHY_USBC_USB,
+			.cfg = &qcm2290_usb3phy_cfg,
+		},
+	}, {
+		.compatible = "qcom,qcs615-qmp-dp-phy",
+		.data =  &(struct dev_cfg) {
+			.type = QMP_PHY_USBC_DP,
+			.cfg = &qcs615_dpphy_cfg,
+		},
 	}, {
 		.compatible = "qcom,sdm660-qmp-usb3-phy",
-		.data = &sdm660_usb3phy_cfg,
+		.data =  &(struct dev_cfg) {
+			.type = QMP_PHY_USBC_USB,
+			.cfg = &sdm660_usb3phy_cfg,
+		},
 	}, {
 		.compatible = "qcom,sm6115-qmp-usb3-phy",
-		.data = &qcm2290_usb3phy_cfg,
+		.data =  &(struct dev_cfg) {
+			.type = QMP_PHY_USBC_USB,
+			.cfg = &qcm2290_usb3phy_cfg,
+		},
 	},
 	{ },
 };
+
 MODULE_DEVICE_TABLE(of, qmp_usbc_of_match_table);
 
 static struct platform_driver qmp_usbc_driver = {

-- 
2.25.1


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH 4/8] drm/msm/dp: Add DisplayPort support for QCS615
  2024-11-29  7:57 [PATCH 0/8] Add DisplayPort support for QCS615 platform Xiangxu Yin
                   ` (2 preceding siblings ...)
  2024-11-29  7:57 ` [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615 Xiangxu Yin
@ 2024-11-29  7:57 ` Xiangxu Yin
  2024-11-29 13:54   ` Dmitry Baryshkov
  2024-11-29  7:57 ` [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration Xiangxu Yin
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-11-29  7:57 UTC (permalink / raw)
  To: Rob Clark, Abhinav Kumar, Dmitry Baryshkov, Sean Paul,
	Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio, Xiangxu Yin

The Qualcomm QCS615 platform comes with a DisplayPort controller use the
same base offset as sc7180. add support for this in DP driver.

Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_display.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index aba925aab7ad7c6652e81004043864c1cb3ac370..4c83402fc7e0d41cb7621fa2efda043269d0a608 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -179,6 +179,7 @@ static const struct of_device_id msm_dp_dt_match[] = {
 	{ .compatible = "qcom,sc8280xp-dp", .data = &msm_dp_desc_sc8280xp },
 	{ .compatible = "qcom,sc8280xp-edp", .data = &msm_dp_desc_sc8280xp },
 	{ .compatible = "qcom,sdm845-dp", .data = &msm_dp_desc_sc7180 },
+	{ .compatible = "qcom,sm6150-dp", .data = &msm_dp_desc_sc7180 },
 	{ .compatible = "qcom,sm8350-dp", .data = &msm_dp_desc_sc7180 },
 	{ .compatible = "qcom,sm8650-dp", .data = &msm_dp_desc_sm8650 },
 	{ .compatible = "qcom,x1e80100-dp", .data = &msm_dp_desc_x1e80100 },

-- 
2.25.1


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration
  2024-11-29  7:57 [PATCH 0/8] Add DisplayPort support for QCS615 platform Xiangxu Yin
                   ` (3 preceding siblings ...)
  2024-11-29  7:57 ` [PATCH 4/8] drm/msm/dp: Add DisplayPort support for QCS615 Xiangxu Yin
@ 2024-11-29  7:57 ` Xiangxu Yin
  2024-11-29 13:50   ` Dmitry Baryshkov
  2024-11-29  7:57 ` [PATCH 6/8] drm/msm/dp: Add maximum width limitation for modes Xiangxu Yin
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-11-29  7:57 UTC (permalink / raw)
  To: Rob Clark, Abhinav Kumar, Dmitry Baryshkov, Sean Paul,
	Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio, Xiangxu Yin

Add the ability to configure lane mapping for the DP controller. This is
required when the platform's lane mapping does not follow the default
order (0, 1, 2, 3). The mapping rules are now configurable via the
`data-lane` property in the devicetree. This property defines the
logical-to-physical lane mapping sequence, ensuring correct lane
assignment for non-default configurations.

Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 11 +++++------
 drivers/gpu/drm/msm/dp/dp_catalog.h |  2 +-
 drivers/gpu/drm/msm/dp/dp_ctrl.c    |  2 +-
 drivers/gpu/drm/msm/dp/dp_panel.c   | 13 ++++++++++---
 drivers/gpu/drm/msm/dp/dp_panel.h   |  3 +++
 5 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index b4c8856fb25d01dd1b30c5ec33ce821aafa9551d..34439d0709d2e1437e5669fd0b995936420ee16f 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -361,17 +361,16 @@ void msm_dp_catalog_ctrl_config_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32
 	msm_dp_write_link(catalog, REG_DP_CONFIGURATION_CTRL, cfg);
 }
 
-void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog)
+void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog, u32 *l_map)
 {
 	struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog,
 				struct msm_dp_catalog_private, msm_dp_catalog);
-	u32 ln_0 = 0, ln_1 = 1, ln_2 = 2, ln_3 = 3; /* One-to-One mapping */
 	u32 ln_mapping;
 
-	ln_mapping = ln_0 << LANE0_MAPPING_SHIFT;
-	ln_mapping |= ln_1 << LANE1_MAPPING_SHIFT;
-	ln_mapping |= ln_2 << LANE2_MAPPING_SHIFT;
-	ln_mapping |= ln_3 << LANE3_MAPPING_SHIFT;
+	ln_mapping = l_map[0] << LANE0_MAPPING_SHIFT;
+	ln_mapping |= l_map[1] << LANE1_MAPPING_SHIFT;
+	ln_mapping |= l_map[2] << LANE2_MAPPING_SHIFT;
+	ln_mapping |= l_map[3] << LANE3_MAPPING_SHIFT;
 
 	msm_dp_write_link(catalog, REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING,
 			ln_mapping);
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index e932b17eecbf514070cd8cd0b98ca0fefbe81ab7..8b8de2a7d3ad561c1901e1bdaad92d4fab12e808 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -69,7 +69,7 @@ u32 msm_dp_catalog_aux_get_irq(struct msm_dp_catalog *msm_dp_catalog);
 /* DP Controller APIs */
 void msm_dp_catalog_ctrl_state_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 state);
 void msm_dp_catalog_ctrl_config_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 config);
-void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog);
+void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog, u32 *l_map);
 void msm_dp_catalog_ctrl_mainlink_ctrl(struct msm_dp_catalog *msm_dp_catalog, bool enable);
 void msm_dp_catalog_ctrl_psr_mainlink_enable(struct msm_dp_catalog *msm_dp_catalog, bool enable);
 void msm_dp_catalog_setup_peripheral_flush(struct msm_dp_catalog *msm_dp_catalog);
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index bc2ca8133b790fc049e18ab3b37a629558664dd4..49c8ce9b2d0e57a613e50865be3fe98e814d425a 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -177,7 +177,7 @@ static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl
 {
 	u32 cc, tb;
 
-	msm_dp_catalog_ctrl_lane_mapping(ctrl->catalog);
+	msm_dp_catalog_ctrl_lane_mapping(ctrl->catalog, ctrl->panel->lane_map);
 	msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
 	msm_dp_catalog_setup_peripheral_flush(ctrl->catalog);
 
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 5d7eaa31bf3176566f40f01ff636bee64e81c64f..8654180aa259234bbd41f4f88c13c485f9791b1d 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -11,7 +11,6 @@
 #include <drm/drm_of.h>
 #include <drm/drm_print.h>
 
-#define DP_MAX_NUM_DP_LANES	4
 #define DP_LINK_RATE_HBR2	540000 /* kbytes */
 
 struct msm_dp_panel_private {
@@ -461,6 +460,7 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
 	struct msm_dp_panel_private *panel;
 	struct device_node *of_node;
 	int cnt;
+	u32 lane_map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3};
 
 	panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
 	of_node = panel->dev->of_node;
@@ -474,10 +474,17 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
 		cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
 	}
 
-	if (cnt > 0)
+	if (cnt > 0) {
+		struct device_node *endpoint;
+
 		msm_dp_panel->max_dp_lanes = cnt;
-	else
+		endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1);
+		of_property_read_u32_array(endpoint, "data-lanes", lane_map, cnt);
+	} else {
 		msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
+	}
+
+	memcpy(msm_dp_panel->lane_map, lane_map, msm_dp_panel->max_dp_lanes * sizeof(u32));
 
 	msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node);
 	if (!msm_dp_panel->max_dp_link_rate)
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index 0e944db3adf2f187f313664fe80cf540ec7a19f2..7603b92c32902bd3d4485539bd6308537ff75a2c 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -11,6 +11,8 @@
 #include "dp_aux.h"
 #include "dp_link.h"
 
+#define DP_MAX_NUM_DP_LANES	4
+
 struct edid;
 
 struct msm_dp_display_mode {
@@ -46,6 +48,7 @@ struct msm_dp_panel {
 	bool video_test;
 	bool vsc_sdp_supported;
 
+	u32 lane_map[DP_MAX_NUM_DP_LANES];
 	u32 max_dp_lanes;
 	u32 max_dp_link_rate;
 

-- 
2.25.1


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH 6/8] drm/msm/dp: Add maximum width limitation for modes
  2024-11-29  7:57 [PATCH 0/8] Add DisplayPort support for QCS615 platform Xiangxu Yin
                   ` (4 preceding siblings ...)
  2024-11-29  7:57 ` [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration Xiangxu Yin
@ 2024-11-29  7:57 ` Xiangxu Yin
  2024-11-29 13:52   ` Dmitry Baryshkov
  2024-11-29  7:57 ` [PATCH 7/8] drm/msm/dp: Retry Link Training 2 with lower pattern Xiangxu Yin
  2024-11-29  7:57 ` [PATCH 8/8] drm/msm/dp: Support external GPIO HPD with 3rd pinctrl chip Xiangxu Yin
  7 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-11-29  7:57 UTC (permalink / raw)
  To: Rob Clark, Abhinav Kumar, Dmitry Baryshkov, Sean Paul,
	Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio, Xiangxu Yin

Introduce a maximum width constraint for modes during validation. This
ensures that the modes are filtered based on hardware capabilities,
specifically addressing the line buffer limitations of individual pipes.

Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_display.c |  3 +++
 drivers/gpu/drm/msm/dp/dp_display.h |  1 +
 drivers/gpu/drm/msm/dp/dp_panel.c   | 13 +++++++++++++
 drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
 4 files changed, 18 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 4c83402fc7e0d41cb7621fa2efda043269d0a608..eb6fb76c68e505fafbec563440e9784f51e1894b 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -944,6 +944,9 @@ enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge,
 	msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
 	link_info = &msm_dp_display->panel->link_info;
 
+	if (mode->hdisplay > msm_dp_display->panel->max_dp_width)
+		return MODE_BAD;
+
 	if (drm_mode_is_420_only(&dp->connector->display_info, mode) &&
 	    msm_dp_display->panel->vsc_sdp_supported)
 		mode_pclk_khz /= 2;
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index ecbc2d92f546a346ee53adcf1b060933e4f54317..7a11f7eeb691976f06afc7aff67650397d7deb90 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -11,6 +11,7 @@
 #include "disp/msm_disp_snapshot.h"
 
 #define DP_MAX_PIXEL_CLK_KHZ	675000
+#define DP_MAX_WIDTH	7680
 
 struct msm_dp {
 	struct drm_device *drm_dev;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 8654180aa259234bbd41f4f88c13c485f9791b1d..10501e301c5e073d8d34093b86a15d72e646a01f 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -4,6 +4,7 @@
  */
 
 #include "dp_panel.h"
+#include "dp_display.h"
 #include "dp_utils.h"
 
 #include <drm/drm_connector.h>
@@ -455,6 +456,16 @@ static u32 msm_dp_panel_link_frequencies(struct device_node *of_node)
 	return frequency;
 }
 
+static u32 msm_dp_panel_max_width(struct device_node *of_node)
+{
+	u32 max_width = 0;
+
+	if (of_property_read_u32(of_node, "max-width", &max_width))
+		max_width = DP_MAX_WIDTH;
+
+	return max_width;
+}
+
 static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
 {
 	struct msm_dp_panel_private *panel;
@@ -490,6 +501,8 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
 	if (!msm_dp_panel->max_dp_link_rate)
 		msm_dp_panel->max_dp_link_rate = DP_LINK_RATE_HBR2;
 
+	msm_dp_panel->max_dp_width = msm_dp_panel_max_width(of_node);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index 7603b92c32902bd3d4485539bd6308537ff75a2c..61513644161209c243bbb623ee4ded951b2a0597 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -51,6 +51,7 @@ struct msm_dp_panel {
 	u32 lane_map[DP_MAX_NUM_DP_LANES];
 	u32 max_dp_lanes;
 	u32 max_dp_link_rate;
+	u32 max_dp_width;
 
 	u32 max_bw_code;
 };

-- 
2.25.1


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH 7/8] drm/msm/dp: Retry Link Training 2 with lower pattern
  2024-11-29  7:57 [PATCH 0/8] Add DisplayPort support for QCS615 platform Xiangxu Yin
                   ` (5 preceding siblings ...)
  2024-11-29  7:57 ` [PATCH 6/8] drm/msm/dp: Add maximum width limitation for modes Xiangxu Yin
@ 2024-11-29  7:57 ` Xiangxu Yin
  2024-11-29 13:53   ` Dmitry Baryshkov
  2024-11-29  7:57 ` [PATCH 8/8] drm/msm/dp: Support external GPIO HPD with 3rd pinctrl chip Xiangxu Yin
  7 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-11-29  7:57 UTC (permalink / raw)
  To: Rob Clark, Abhinav Kumar, Dmitry Baryshkov, Sean Paul,
	Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio, Xiangxu Yin

Add a mechanism to retry Link Training 2 by lowering the pattern level
when the link training #2 first attempt fails. This approach enhances
compatibility, particularly addressing issues caused by certain hub
configurations.

Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_ctrl.c | 34 ++++++++++++++++++++++++++++++----
 1 file changed, 30 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 49c8ce9b2d0e57a613e50865be3fe98e814d425a..b1862294cb98c9f756b0108b7670cb42de37bae4 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -1220,7 +1220,7 @@ static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl)
 }
 
 static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
-			int *training_step)
+			int *training_step, bool downgrade)
 {
 	int tries = 0, ret = 0;
 	u8 pattern;
@@ -1243,6 +1243,28 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
 		state_ctrl_bit = 2;
 	}
 
+	/*
+	 * DP link training uses the highest allowed pattern by default.
+	 * If it fails, the pattern is downgraded to improve cable and monitor compatibility.
+	 */
+	if (downgrade) {
+		switch (pattern) {
+		case DP_TRAINING_PATTERN_4:
+			pattern = DP_TRAINING_PATTERN_3;
+			state_ctrl_bit = 3;
+			break;
+		case DP_TRAINING_PATTERN_3:
+			pattern = DP_TRAINING_PATTERN_2;
+			state_ctrl_bit = 2;
+			break;
+		default:
+			break;
+		}
+	}
+
+	drm_dbg_dp(ctrl->drm_dev, "pattern(%d) state_ctrl_bit(%d) downgrade(%d)\n",
+		pattern, state_ctrl_bit, downgrade);
+
 	ret = msm_dp_catalog_ctrl_set_pattern_state_bit(ctrl->catalog, state_ctrl_bit);
 	if (ret)
 		return ret;
@@ -1311,10 +1333,14 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
 	/* print success info as this is a result of user initiated action */
 	drm_dbg_dp(ctrl->drm_dev, "link training #1 successful\n");
 
-	ret = msm_dp_ctrl_link_train_2(ctrl, training_step);
+	ret = msm_dp_ctrl_link_train_2(ctrl, training_step, false);
 	if (ret) {
-		DRM_ERROR("link training #2 failed. ret=%d\n", ret);
-		goto end;
+		drm_dbg_dp(ctrl->drm_dev, "link training #2 failed, retry downgrade.\n");
+		ret = msm_dp_ctrl_link_train_2(ctrl, training_step, true);
+		if (ret) {
+			DRM_ERROR("link training #2 failed. ret=%d\n", ret);
+			goto end;
+		}
 	}
 
 	/* print success info as this is a result of user initiated action */

-- 
2.25.1


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH 8/8] drm/msm/dp: Support external GPIO HPD with 3rd pinctrl chip
  2024-11-29  7:57 [PATCH 0/8] Add DisplayPort support for QCS615 platform Xiangxu Yin
                   ` (6 preceding siblings ...)
  2024-11-29  7:57 ` [PATCH 7/8] drm/msm/dp: Retry Link Training 2 with lower pattern Xiangxu Yin
@ 2024-11-29  7:57 ` Xiangxu Yin
  2024-11-29  8:21   ` Krzysztof Kozlowski
                     ` (2 more replies)
  7 siblings, 3 replies; 60+ messages in thread
From: Xiangxu Yin @ 2024-11-29  7:57 UTC (permalink / raw)
  To: Rob Clark, Abhinav Kumar, Dmitry Baryshkov, Sean Paul,
	Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio, Xiangxu Yin

Add support for handling HPD (Hot Plug Detect) signals via external
GPIOs connected through pinctrl chips (e.g., Semtech SX1509Q). This
involves reinitializing the relevant GPIO and binding an interrupt
handler to process hot plug events. Since external GPIOs only support
edge interrupts (rising or falling) rather than state interrupts, the
GPIO state must be read during the first DP bridge HPD enablement. This
ensures the current connection state is determined and a hot plug event
is reported accordingly.

Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_display.c | 83 +++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index eb6fb76c68e505fafbec563440e9784f51e1894b..22c288ca61b9b444a7b8d4a574c614bfef9d88be 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -13,6 +13,8 @@
 #include <linux/delay.h>
 #include <drm/display/drm_dp_aux_bus.h>
 #include <drm/drm_edid.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_gpio.h>
 
 #include "msm_drv.h"
 #include "msm_kms.h"
@@ -78,6 +80,10 @@ struct msm_dp_display_private {
 
 	unsigned int id;
 
+	bool ext_gpio;
+	int gpio_num;
+	struct work_struct  gpio_work;
+
 	/* state variables */
 	bool core_initialized;
 	bool phy_initialized;
@@ -1182,6 +1188,42 @@ static irqreturn_t msm_dp_display_irq_handler(int irq, void *dev_id)
 	return ret;
 }
 
+
+static void msm_dp_gpio_work_handler(struct work_struct *work)
+{
+	struct msm_dp_display_private *dp = container_of(work,
+			struct msm_dp_display_private, gpio_work);
+	struct gpio_desc *desc;
+	bool hpd;
+
+	if (dp->ext_gpio) {
+		desc = gpio_to_desc(dp->gpio_num);
+		if (!desc) {
+			pr_err("Failed to get gpio_desc for GPIO %d\n", dp->gpio_num);
+			return;
+		}
+
+		hpd = gpiod_get_value_cansleep(desc);
+		if (hpd)
+			msm_dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0);
+		else
+			msm_dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0);
+	}
+}
+
+static irqreturn_t msm_dp_gpio_isr(int unused, void *data)
+{
+	struct msm_dp_display_private *dp = data;
+
+	if (!dp) {
+		DRM_ERROR("NULL data\n");
+		return IRQ_NONE;
+	}
+
+	schedule_work(&dp->gpio_work);
+	return IRQ_HANDLED;
+}
+
 static int msm_dp_display_request_irq(struct msm_dp_display_private *dp)
 {
 	int rc = 0;
@@ -1193,6 +1235,21 @@ static int msm_dp_display_request_irq(struct msm_dp_display_private *dp)
 		return dp->irq;
 	}
 
+	if (dp->ext_gpio) {
+		int edge, gpio_irq;
+
+		gpio_irq = gpio_to_irq(dp->gpio_num);
+		edge = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
+
+		rc = devm_request_threaded_irq(&pdev->dev, gpio_irq, NULL,
+		msm_dp_gpio_isr, edge, "dp_gpio_isr", dp);
+		if (rc < 0) {
+			DRM_ERROR("failed to request ext-gpio IRQ%u: %d\n",
+					gpio_irq, rc);
+			return rc;
+		}
+	}
+
 	rc = devm_request_irq(&pdev->dev, dp->irq, msm_dp_display_irq_handler,
 			      IRQF_TRIGGER_HIGH|IRQF_NO_AUTOEN,
 			      "dp_display_isr", dp);
@@ -1308,10 +1365,32 @@ static int msm_dp_display_probe(struct platform_device *pdev)
 		return -EPROBE_DEFER;
 	}
 
+	if (of_find_property(pdev->dev.of_node, "dp-hpd-gpio", NULL)) {
+		dp->ext_gpio = true;
+		dp->gpio_num = of_get_named_gpio(pdev->dev.of_node, "dp-hpd-gpio", 0);
+		if (dp->gpio_num < 0) {
+			dev_err(&pdev->dev, "Failed to get gpio:%d\n", dp->gpio_num);
+			return dp->gpio_num;
+		}
+
+		if (!gpio_is_valid(dp->gpio_num)) {
+			DRM_ERROR("gpio(%d) invalid\n", dp->gpio_num);
+			return -EINVAL;
+		}
+
+		rc = gpio_request(dp->gpio_num, "dp-hpd-gpio");
+		if (rc) {
+			dev_err(&pdev->dev, "Failed to request gpio:%d\n", dp->gpio_num);
+			return rc;
+		}
+		gpio_direction_input(dp->gpio_num);
+	}
+
 	/* setup event q */
 	mutex_init(&dp->event_mutex);
 	init_waitqueue_head(&dp->event_q);
 	spin_lock_init(&dp->event_lock);
+	INIT_WORK(&dp->gpio_work, msm_dp_gpio_work_handler);
 
 	/* Store DP audio handle inside DP display */
 	dp->msm_dp_display.msm_dp_audio = dp->audio;
@@ -1678,6 +1757,10 @@ void msm_dp_bridge_hpd_enable(struct drm_bridge *bridge)
 	msm_dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, true);
 
 	msm_dp_display->internal_hpd = true;
+
+	if (dp->ext_gpio)
+		schedule_work(&dp->gpio_work);
+
 	mutex_unlock(&dp->event_mutex);
 }
 

-- 
2.25.1


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* Re: [PATCH 1/8] dt-bindings: display/msm: Document DP on QCS615
  2024-11-29  7:57 ` [PATCH 1/8] dt-bindings: display/msm: Document DP on QCS615 Xiangxu Yin
@ 2024-11-29  8:11   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 60+ messages in thread
From: Krzysztof Kozlowski @ 2024-11-29  8:11 UTC (permalink / raw)
  To: Xiangxu Yin, Rob Clark, Abhinav Kumar, Dmitry Baryshkov,
	Sean Paul, Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio

On 29/11/2024 08:57, Xiangxu Yin wrote:
> Document the DP hardware found on the Qualcomm QCS615 platform.
> 
> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> ---
>  .../devicetree/bindings/display/msm/dp-controller.yaml      | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
> index a212f335d5ffae545d2e5bacec95299ca45e8405..a609245ae601bdc60b65f19d3e59c559886a969d 100644
> --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
> +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
> @@ -26,6 +26,7 @@ properties:
>            - qcom,sc8280xp-dp
>            - qcom,sc8280xp-edp
>            - qcom,sdm845-dp
> +          - qcom,sm6150-dp

I see sm6150, not qcs615.

>            - qcom,sm8350-dp
>            - qcom,sm8650-dp
>        - items:
> @@ -109,6 +110,18 @@ properties:
>    vdda-1p2-supply:
>      deprecated: true
>  
> +  max-width:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: Maximum allowed width for display modes
> +    default: 7680

I don't see why this is a property of board. Drop. Anyway, missing
vendor prefix or unnecessary $ref, if it comes from other schema.

> +
> +  dp-hpd-gpio:

gpios

> +    description: External GPIO for controlling HPD when a 3rd pinctrl is used
> +    items:
> +      - description: phandle to 3rd GPIO controller
> +      - description: GPIO pin number
> +      - description: Optional GPIO flags

Nope, that's not how GPIOs are created. Please take a look at any other
schema.

Anyway, I doubt that you need this property. See common bindings for
display pieces.


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 2/8] dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: Add DP support for QCS615
  2024-11-29  7:57 ` [PATCH 2/8] dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: Add DP support for QCS615 Xiangxu Yin
@ 2024-11-29  8:14   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 60+ messages in thread
From: Krzysztof Kozlowski @ 2024-11-29  8:14 UTC (permalink / raw)
  To: Xiangxu Yin, Rob Clark, Abhinav Kumar, Dmitry Baryshkov,
	Sean Paul, Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio

On 29/11/2024 08:57, Xiangxu Yin wrote:
> Declare the DP QMP PHY present on the Qualcomm QCS615 platforms.
> 
> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> ---
>  .../bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml     | 21 +++++++++++++++++++--
>  1 file changed, 19 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml
> index 1636285fbe535c430fdf792b33a5e9c523de323b..eb21cfe734526fce670c540212a607a016cedf2c 100644
> --- a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml
> +++ b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml
> @@ -18,6 +18,7 @@ properties:
>      enum:
>        - qcom,msm8998-qmp-usb3-phy
>        - qcom,qcm2290-qmp-usb3-phy
> +      - qcom,qcs615-qmp-dp-phy
>        - qcom,qcs615-qmp-usb3-phy
>        - qcom,sdm660-qmp-usb3-phy
>        - qcom,sm6115-qmp-usb3-phy
> @@ -47,7 +48,7 @@ properties:
>      const: 0
>  
>    clock-output-names:
> -    maxItems: 1
> +    maxItems: 2


Why all devices now have two clocks? No, this needs lower constraints
and further customization per each variant.

>  
>    "#phy-cells":
>      const: 0
> @@ -62,7 +63,8 @@ properties:
>      items:
>        - items:
>            - description: phandle to TCSR hardware block
> -          - description: offset of the VLS CLAMP register
> +          - description: offset of the VLS CLAMP register in USB mode
> +                         and offset of the DP Phy mode register in DP mode

You change all existing devices, no.

>      description: Clamp register present in the TCSR
>  
>    ports:
> @@ -128,6 +130,21 @@ allOf:
>              - const: com_aux
>              - const: pipe
>  
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            enum:
> +              - qcom,qcs615-qmp-dp-phy
> +    then:
> +      properties:
> +        clocks:
> +          maxItems: 2
> +        clock-names:
> +          items:
> +            - const: cfg_ahb
> +            - const: ref

Top level says you have minimum 4 clocks, not 2. You need to fix that,
if this devices stays in this schema. Anyway your changes suggest device
is quite different, so probably should not be here in the first place
but in different schema, maybe new one.



Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-11-29  7:57 ` [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615 Xiangxu Yin
@ 2024-11-29  8:18   ` Krzysztof Kozlowski
  2024-12-02 10:31     ` Xiangxu Yin
  2024-11-29 12:12   ` kernel test robot
  2024-11-29 14:33   ` Dmitry Baryshkov
  2 siblings, 1 reply; 60+ messages in thread
From: Krzysztof Kozlowski @ 2024-11-29  8:18 UTC (permalink / raw)
  To: Xiangxu Yin, Rob Clark, Abhinav Kumar, Dmitry Baryshkov,
	Sean Paul, Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio

On 29/11/2024 08:57, Xiangxu Yin wrote:
> Extended DP support for QCS615 USB or DP phy. Differentiated between
> USBC and DP PHY using the match table’s type, dynamically generating
> different types of cfg and layout attributes during initialization based
> on this type. Static variables are stored in cfg, while parsed values
> are organized into the layout structure.
> 
> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> ---
>  drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h |    1 +
>  drivers/phy/qualcomm/phy-qcom-qmp-usbc.c   | 1453 ++++++++++++++++++++++++----
>  2 files changed, 1254 insertions(+), 200 deletions(-)



...

> +	/* program default setting first */
> +	writel(0x2A, tx + QSERDES_V3_TX_TX_DRV_LVL);
> +	writel(0x20, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> +	writel(0x2A, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
> +	writel(0x20, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> +
> +	writel(voltage_swing_cfg, tx + QSERDES_V3_TX_TX_DRV_LVL);
> +	writel(pre_emphasis_cfg, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> +	writel(voltage_swing_cfg, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
> +	writel(pre_emphasis_cfg, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> +
> +	return 0;
> +}
> +
> +static int qcs615_qmp_configure_dp_phy(struct qmp_usbc *qmp)
> +{
> +	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +	u32 status;
> +
> +	writel(0x01, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +	writel(0x05, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +	writel(0x01, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +	writel(0x09, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +
> +	writel(0x20, layout->dp_serdes + QSERDES_COM_RESETSM_CNTRL);
> +
> +	// C_READY

Use Linux coding style.

Anyway, drop all useless comments. Say something useful or don't say
anything.

> +	if (readl_poll_timeout(layout->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;
> +	}
> +
> +	// FREQ_DONE
> +	if (readl_poll_timeout(layout->dp_serdes + QSERDES_COM_CMN_STATUS,
> +			status,
> +			((status & BIT(0)) > 0),
> +			500,
> +			10000)){
> +		dev_err(qmp->dev, "FREQ_DONE not ready\n");
> +		return -ETIMEDOUT;
> +	}
> +
> +	// PLL_LOCKED
> +	if (readl_poll_timeout(layout->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, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +	udelay(10);
> +
> +	// TSYNC_DONE
> +	if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS,
> +			status,
> +			((status & BIT(0)) > 0),
> +			500,
> +			10000)){
> +		dev_err(qmp->dev, "TSYNC_DONE not ready\n");
> +		return -ETIMEDOUT;
> +	}
> +
> +	// PHY_READY
> +	if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS,
> +			status,
> +			((status & BIT(1)) > 0),
> +			500,
> +			10000)){
> +		dev_err(qmp->dev, "PHY_READY not ready\n");
> +		return -ETIMEDOUT;
> +	}
> +
> +	writel(0x3f, layout->dp_tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
> +	writel(0x10, layout->dp_tx + QSERDES_V3_TX_HIGHZ_DRVR_EN);
> +	writel(0x0a, layout->dp_tx + QSERDES_V3_TX_TX_POL_INV);
> +	writel(0x3f, layout->dp_tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
> +	writel(0x10, layout->dp_tx2 + QSERDES_V3_TX_HIGHZ_DRVR_EN);
> +	writel(0x0a, layout->dp_tx2 + QSERDES_V3_TX_TX_POL_INV);
> +
> +	writel(0x18, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +	writel(0x19, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +
> +	if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_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 qcs615_qmp_calibrate_dp_phy(struct qmp_usbc *qmp)
> +{
> +	static const u8 cfg1_settings[] = {0x13, 0x23, 0x1d};
> +	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +	u8 val;
> +
> +	layout->dp_aux_cfg++;
> +	layout->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
> +	val = cfg1_settings[layout->dp_aux_cfg];
> +
> +	writel(val, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG1);
> +
> +	qmp_usbc_check_dp_phy(qmp, "pos_calibrate");
> +
> +	return 0;
> +}
> +
> +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;
> +	int num_vregs;
>  	u32 val = 0;
>  	int ret;
> +	unsigned int reg_pwr_dn;
>  
> -	ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
> +	if (qmp->type == QMP_PHY_USBC_USB) {


Sorry, all this code is unreviewable. Organize your changes in logical,
reviewable chunks.

> +		struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> +
> +		num_vregs = cfg->num_vregs;
> +		reg_pwr_dn = cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL];
> +	} else {

...

> +		.compatible = "qcom,qcs615-qmp-dp-phy",
> +		.data =  &(struct dev_cfg) {
> +			.type = QMP_PHY_USBC_DP,
> +			.cfg = &qcs615_dpphy_cfg,
> +		},
>  	}, {
>  		.compatible = "qcom,sdm660-qmp-usb3-phy",
> -		.data = &sdm660_usb3phy_cfg,
> +		.data =  &(struct dev_cfg) {
> +			.type = QMP_PHY_USBC_USB,
> +			.cfg = &sdm660_usb3phy_cfg,
> +		},
>  	}, {
>  		.compatible = "qcom,sm6115-qmp-usb3-phy",
> -		.data = &qcm2290_usb3phy_cfg,
> +		.data =  &(struct dev_cfg) {
> +			.type = QMP_PHY_USBC_USB,
> +			.cfg = &qcm2290_usb3phy_cfg,
> +		},
>  	},
>  	{ },
>  };
> +


You make some random changes all over this file. No, clean it up.

>  MODULE_DEVICE_TABLE(of, qmp_usbc_of_match_table);
>  
>  static struct platform_driver qmp_usbc_driver = {
> 


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 8/8] drm/msm/dp: Support external GPIO HPD with 3rd pinctrl chip
  2024-11-29  7:57 ` [PATCH 8/8] drm/msm/dp: Support external GPIO HPD with 3rd pinctrl chip Xiangxu Yin
@ 2024-11-29  8:21   ` Krzysztof Kozlowski
  2024-11-29 13:45   ` Dmitry Baryshkov
  2024-11-29 13:54   ` neil.armstrong
  2 siblings, 0 replies; 60+ messages in thread
From: Krzysztof Kozlowski @ 2024-11-29  8:21 UTC (permalink / raw)
  To: Xiangxu Yin, Rob Clark, Abhinav Kumar, Dmitry Baryshkov,
	Sean Paul, Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio

On 29/11/2024 08:57, Xiangxu Yin wrote:
>  
> +	if (of_find_property(pdev->dev.of_node, "dp-hpd-gpio", NULL)) {
> +		dp->ext_gpio = true;
> +		dp->gpio_num = of_get_named_gpio(pdev->dev.of_node, "dp-hpd-gpio", 0);
> +		if (dp->gpio_num < 0) {
> +			dev_err(&pdev->dev, "Failed to get gpio:%d\n", dp->gpio_num);
> +			return dp->gpio_num;
> +		}
> +
> +		if (!gpio_is_valid(dp->gpio_num)) {
> +			DRM_ERROR("gpio(%d) invalid\n", dp->gpio_num);
> +			return -EINVAL;
> +		}
> +
> +		rc = gpio_request(dp->gpio_num, "dp-hpd-gpio");
This is not how you request GPIOs. All this code is just wrong. See
Gpiolib API description/document. Or any other driver using GPIOs.

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-11-29  7:57 ` [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615 Xiangxu Yin
  2024-11-29  8:18   ` Krzysztof Kozlowski
@ 2024-11-29 12:12   ` kernel test robot
  2024-11-29 14:33   ` Dmitry Baryshkov
  2 siblings, 0 replies; 60+ messages in thread
From: kernel test robot @ 2024-11-29 12:12 UTC (permalink / raw)
  To: Xiangxu Yin, Rob Clark, Abhinav Kumar, Dmitry Baryshkov,
	Sean Paul, Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: llvm, oe-kbuild-all, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, linux-phy, linux-gpio, Xiangxu Yin

Hi Xiangxu,

kernel test robot noticed the following build warnings:

[auto build test WARNING on f486c8aa16b8172f63bddc70116a0c897a7f3f02]

url:    https://github.com/intel-lab-lkp/linux/commits/Xiangxu-Yin/dt-bindings-display-msm-Document-DP-on-QCS615/20241129-160612
base:   f486c8aa16b8172f63bddc70116a0c897a7f3f02
patch link:    https://lore.kernel.org/r/20241129-add-displayport-support-for-qcs615-platform-v1-3-09a4338d93ef%40quicinc.com
patch subject: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
config: arm64-allmodconfig (https://download.01.org/0day-ci/archive/20241129/202411292042.NDeS4BGv-lkp@intel.com/config)
compiler: clang version 20.0.0git (https://github.com/llvm/llvm-project 592c0fe55f6d9a811028b5f3507be91458ab2713)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241129/202411292042.NDeS4BGv-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202411292042.NDeS4BGv-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from drivers/phy/qualcomm/phy-qcom-qmp-usbc.c:17:
   In file included from include/linux/phy/phy.h:17:
   In file included from include/linux/regulator/consumer.h:35:
   In file included from include/linux/suspend.h:5:
   In file included from include/linux/swap.h:9:
   In file included from include/linux/memcontrol.h:21:
   In file included from include/linux/mm.h:2223:
   include/linux/vmstat.h:504:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     504 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     505 |                            item];
         |                            ~~~~
   include/linux/vmstat.h:511:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     511 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     512 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
   include/linux/vmstat.h:518:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
     518 |         return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
         |                               ~~~~~~~~~~~ ^ ~~~
   include/linux/vmstat.h:524:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     524 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     525 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
>> drivers/phy/qualcomm/phy-qcom-qmp-usbc.c:721:24: warning: variable 'pre_emphasis_cfg' is uninitialized when used here [-Wuninitialized]
     721 |         if ((v_level > 4) || (pre_emphasis_cfg > 4)) {
         |                               ^~~~~~~~~~~~~~~~
   drivers/phy/qualcomm/phy-qcom-qmp-usbc.c:708:40: note: initialize the variable 'pre_emphasis_cfg' to silence this warning
     708 |         u8 voltage_swing_cfg, pre_emphasis_cfg;
         |                                               ^
         |                                                = '\0'
>> drivers/phy/qualcomm/phy-qcom-qmp-usbc.c:1801:47: warning: variable 'ret' is uninitialized when used here [-Wuninitialized]
    1801 |                 dev_err(dev, "get resource fail, ret:%d\n", ret);
         |                                                             ^~~
   include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                                        ^~~~~~~~~~~
   include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                                     ^~~~~~~~~~~
   drivers/phy/qualcomm/phy-qcom-qmp-usbc.c:1797:9: note: initialize the variable 'ret' to silence this warning
    1797 |         int ret;
         |                ^
         |                 = 0
>> drivers/phy/qualcomm/phy-qcom-qmp-usbc.c:2082:13: warning: variable 'np' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
    2082 |         } else if (qmp->type == QMP_PHY_USBC_DP) {
         |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/phy/qualcomm/phy-qcom-qmp-usbc.c:2150:14: note: uninitialized use occurs here
    2150 |         of_node_put(np);
         |                     ^~
   drivers/phy/qualcomm/phy-qcom-qmp-usbc.c:2082:9: note: remove the 'if' if its condition is always true
    2082 |         } else if (qmp->type == QMP_PHY_USBC_DP) {
         |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/phy/qualcomm/phy-qcom-qmp-usbc.c:2027:24: note: initialize the variable 'np' to silence this warning
    2027 |         struct device_node *np;
         |                               ^
         |                                = NULL
   7 warnings generated.


vim +/pre_emphasis_cfg +721 drivers/phy/qualcomm/phy-qcom-qmp-usbc.c

   699	
   700	static int qcs615_qmp_configure_dp_voltages(struct qmp_usbc *qmp)
   701	{
   702		struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
   703		struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
   704		const struct phy_configure_opts_dp *dp_opts = &layout->dp_opts;
   705		void __iomem *tx = layout->dp_tx;
   706		void __iomem *tx2 = layout->dp_tx2;
   707		unsigned int v_level = 0, p_level = 0;
   708		u8 voltage_swing_cfg, pre_emphasis_cfg;
   709		int i;
   710	
   711		if (dp_opts->lanes > 4) {
   712			dev_err(qmp->dev, "Invalid lane_num(%d)\n", dp_opts->lanes);
   713			return -EINVAL;
   714		}
   715	
   716		for (i = 0; i < dp_opts->lanes; i++) {
   717			v_level = max(v_level, dp_opts->voltage[i]);
   718			p_level = max(p_level, dp_opts->pre[i]);
   719		}
   720	
 > 721		if ((v_level > 4) || (pre_emphasis_cfg > 4)) {
   722			dev_err(qmp->dev, "Invalid v(%d) | p(%d) level)\n",
   723				v_level, pre_emphasis_cfg);
   724			return -EINVAL;
   725		}
   726	
   727		voltage_swing_cfg = (*cfg->swing_tbl)[v_level][p_level];
   728		pre_emphasis_cfg = (*cfg->pre_emphasis_tbl)[v_level][p_level];
   729	
   730		/* Enable MUX to use Cursor values from these registers */
   731		voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN;
   732		pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN;
   733	
   734		if (voltage_swing_cfg == 0xFF && pre_emphasis_cfg == 0xFF)
   735			return -EINVAL;
   736	
   737		/* program default setting first */
   738		writel(0x2A, tx + QSERDES_V3_TX_TX_DRV_LVL);
   739		writel(0x20, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
   740		writel(0x2A, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
   741		writel(0x20, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
   742	
   743		writel(voltage_swing_cfg, tx + QSERDES_V3_TX_TX_DRV_LVL);
   744		writel(pre_emphasis_cfg, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
   745		writel(voltage_swing_cfg, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
   746		writel(pre_emphasis_cfg, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
   747	
   748		return 0;
   749	}
   750	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 8/8] drm/msm/dp: Support external GPIO HPD with 3rd pinctrl chip
  2024-11-29  7:57 ` [PATCH 8/8] drm/msm/dp: Support external GPIO HPD with 3rd pinctrl chip Xiangxu Yin
  2024-11-29  8:21   ` Krzysztof Kozlowski
@ 2024-11-29 13:45   ` Dmitry Baryshkov
  2024-11-29 13:54   ` neil.armstrong
  2 siblings, 0 replies; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-11-29 13:45 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>
> Add support for handling HPD (Hot Plug Detect) signals via external
> GPIOs connected through pinctrl chips (e.g., Semtech SX1509Q). This
> involves reinitializing the relevant GPIO and binding an interrupt
> handler to process hot plug events. Since external GPIOs only support
> edge interrupts (rising or falling) rather than state interrupts, the
> GPIO state must be read during the first DP bridge HPD enablement. This
> ensures the current connection state is determined and a hot plug event
> is reported accordingly.

NAK, use dp-connector instead.

>
> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> ---
>  drivers/gpu/drm/msm/dp/dp_display.c | 83 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 83 insertions(+)


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration
  2024-11-29  7:57 ` [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration Xiangxu Yin
@ 2024-11-29 13:50   ` Dmitry Baryshkov
  2024-12-02  8:40     ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-11-29 13:50 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>
> Add the ability to configure lane mapping for the DP controller. This is
> required when the platform's lane mapping does not follow the default
> order (0, 1, 2, 3). The mapping rules are now configurable via the
> `data-lane` property in the devicetree. This property defines the
> logical-to-physical lane mapping sequence, ensuring correct lane
> assignment for non-default configurations.
>
> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> ---
>  drivers/gpu/drm/msm/dp/dp_catalog.c | 11 +++++------
>  drivers/gpu/drm/msm/dp/dp_catalog.h |  2 +-
>  drivers/gpu/drm/msm/dp/dp_ctrl.c    |  2 +-
>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 ++++++++++---
>  drivers/gpu/drm/msm/dp/dp_panel.h   |  3 +++
>  5 files changed, 20 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
> index b4c8856fb25d01dd1b30c5ec33ce821aafa9551d..34439d0709d2e1437e5669fd0b995936420ee16f 100644
> --- a/drivers/gpu/drm/msm/dp/dp_catalog.c
> +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
> @@ -361,17 +361,16 @@ void msm_dp_catalog_ctrl_config_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32
>         msm_dp_write_link(catalog, REG_DP_CONFIGURATION_CTRL, cfg);
>  }
>
> -void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog)
> +void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog, u32 *l_map)

lane_map, not l_map.

>  {
>         struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog,
>                                 struct msm_dp_catalog_private, msm_dp_catalog);
> -       u32 ln_0 = 0, ln_1 = 1, ln_2 = 2, ln_3 = 3; /* One-to-One mapping */
>         u32 ln_mapping;
>
> -       ln_mapping = ln_0 << LANE0_MAPPING_SHIFT;
> -       ln_mapping |= ln_1 << LANE1_MAPPING_SHIFT;
> -       ln_mapping |= ln_2 << LANE2_MAPPING_SHIFT;
> -       ln_mapping |= ln_3 << LANE3_MAPPING_SHIFT;
> +       ln_mapping = l_map[0] << LANE0_MAPPING_SHIFT;
> +       ln_mapping |= l_map[1] << LANE1_MAPPING_SHIFT;
> +       ln_mapping |= l_map[2] << LANE2_MAPPING_SHIFT;
> +       ln_mapping |= l_map[3] << LANE3_MAPPING_SHIFT;
>
>         msm_dp_write_link(catalog, REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING,
>                         ln_mapping);
> diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
> index e932b17eecbf514070cd8cd0b98ca0fefbe81ab7..8b8de2a7d3ad561c1901e1bdaad92d4fab12e808 100644
> --- a/drivers/gpu/drm/msm/dp/dp_catalog.h
> +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
> @@ -69,7 +69,7 @@ u32 msm_dp_catalog_aux_get_irq(struct msm_dp_catalog *msm_dp_catalog);
>  /* DP Controller APIs */
>  void msm_dp_catalog_ctrl_state_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 state);
>  void msm_dp_catalog_ctrl_config_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 config);
> -void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog);
> +void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog, u32 *l_map);
>  void msm_dp_catalog_ctrl_mainlink_ctrl(struct msm_dp_catalog *msm_dp_catalog, bool enable);
>  void msm_dp_catalog_ctrl_psr_mainlink_enable(struct msm_dp_catalog *msm_dp_catalog, bool enable);
>  void msm_dp_catalog_setup_peripheral_flush(struct msm_dp_catalog *msm_dp_catalog);
> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> index bc2ca8133b790fc049e18ab3b37a629558664dd4..49c8ce9b2d0e57a613e50865be3fe98e814d425a 100644
> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> @@ -177,7 +177,7 @@ static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl
>  {
>         u32 cc, tb;
>
> -       msm_dp_catalog_ctrl_lane_mapping(ctrl->catalog);
> +       msm_dp_catalog_ctrl_lane_mapping(ctrl->catalog, ctrl->panel->lane_map);
>         msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
>         msm_dp_catalog_setup_peripheral_flush(ctrl->catalog);
>
> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
> index 5d7eaa31bf3176566f40f01ff636bee64e81c64f..8654180aa259234bbd41f4f88c13c485f9791b1d 100644
> --- a/drivers/gpu/drm/msm/dp/dp_panel.c
> +++ b/drivers/gpu/drm/msm/dp/dp_panel.c
> @@ -11,7 +11,6 @@
>  #include <drm/drm_of.h>
>  #include <drm/drm_print.h>
>
> -#define DP_MAX_NUM_DP_LANES    4
>  #define DP_LINK_RATE_HBR2      540000 /* kbytes */
>
>  struct msm_dp_panel_private {
> @@ -461,6 +460,7 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>         struct msm_dp_panel_private *panel;
>         struct device_node *of_node;
>         int cnt;
> +       u32 lane_map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3};
>
>         panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
>         of_node = panel->dev->of_node;
> @@ -474,10 +474,17 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>                 cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
>         }
>
> -       if (cnt > 0)
> +       if (cnt > 0) {
> +               struct device_node *endpoint;
> +
>                 msm_dp_panel->max_dp_lanes = cnt;
> -       else
> +               endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1);
> +               of_property_read_u32_array(endpoint, "data-lanes", lane_map, cnt);
> +       } else {
>                 msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
> +       }

Why? This sounds more like dp_catalog or (after the refactoring at
[1]) dp_ctrl. But not the dp_panel.

[1] https://patchwork.freedesktop.org/project/freedreno/series/?ordering=-last_updated

> +
> +       memcpy(msm_dp_panel->lane_map, lane_map, msm_dp_panel->max_dp_lanes * sizeof(u32));
>
>         msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node);
>         if (!msm_dp_panel->max_dp_link_rate)
> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
> index 0e944db3adf2f187f313664fe80cf540ec7a19f2..7603b92c32902bd3d4485539bd6308537ff75a2c 100644
> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
> @@ -11,6 +11,8 @@
>  #include "dp_aux.h"
>  #include "dp_link.h"
>
> +#define DP_MAX_NUM_DP_LANES    4
> +
>  struct edid;
>
>  struct msm_dp_display_mode {
> @@ -46,6 +48,7 @@ struct msm_dp_panel {
>         bool video_test;
>         bool vsc_sdp_supported;
>
> +       u32 lane_map[DP_MAX_NUM_DP_LANES];
>         u32 max_dp_lanes;
>         u32 max_dp_link_rate;
>
>
> --
> 2.25.1
>


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 6/8] drm/msm/dp: Add maximum width limitation for modes
  2024-11-29  7:57 ` [PATCH 6/8] drm/msm/dp: Add maximum width limitation for modes Xiangxu Yin
@ 2024-11-29 13:52   ` Dmitry Baryshkov
  2024-12-02  9:05     ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-11-29 13:52 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>
> Introduce a maximum width constraint for modes during validation. This
> ensures that the modes are filtered based on hardware capabilities,
> specifically addressing the line buffer limitations of individual pipes.

This doesn't describe, why this is necessary. What does "buffer
limitations of individual pipes" mean?
If the platforms have hw capabilities like being unable to support 8k
or 10k, it should go to platform data

>
> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> ---
>  drivers/gpu/drm/msm/dp/dp_display.c |  3 +++
>  drivers/gpu/drm/msm/dp/dp_display.h |  1 +
>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 +++++++++++++
>  drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
>  4 files changed, 18 insertions(+)
>
> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
> index 4c83402fc7e0d41cb7621fa2efda043269d0a608..eb6fb76c68e505fafbec563440e9784f51e1894b 100644
> --- a/drivers/gpu/drm/msm/dp/dp_display.c
> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> @@ -944,6 +944,9 @@ enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge,
>         msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
>         link_info = &msm_dp_display->panel->link_info;
>
> +       if (mode->hdisplay > msm_dp_display->panel->max_dp_width)
> +               return MODE_BAD;
> +
>         if (drm_mode_is_420_only(&dp->connector->display_info, mode) &&
>             msm_dp_display->panel->vsc_sdp_supported)
>                 mode_pclk_khz /= 2;
> diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
> index ecbc2d92f546a346ee53adcf1b060933e4f54317..7a11f7eeb691976f06afc7aff67650397d7deb90 100644
> --- a/drivers/gpu/drm/msm/dp/dp_display.h
> +++ b/drivers/gpu/drm/msm/dp/dp_display.h
> @@ -11,6 +11,7 @@
>  #include "disp/msm_disp_snapshot.h"
>
>  #define DP_MAX_PIXEL_CLK_KHZ   675000
> +#define DP_MAX_WIDTH   7680
>
>  struct msm_dp {
>         struct drm_device *drm_dev;
> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
> index 8654180aa259234bbd41f4f88c13c485f9791b1d..10501e301c5e073d8d34093b86a15d72e646a01f 100644
> --- a/drivers/gpu/drm/msm/dp/dp_panel.c
> +++ b/drivers/gpu/drm/msm/dp/dp_panel.c
> @@ -4,6 +4,7 @@
>   */
>
>  #include "dp_panel.h"
> +#include "dp_display.h"
>  #include "dp_utils.h"
>
>  #include <drm/drm_connector.h>
> @@ -455,6 +456,16 @@ static u32 msm_dp_panel_link_frequencies(struct device_node *of_node)
>         return frequency;
>  }
>
> +static u32 msm_dp_panel_max_width(struct device_node *of_node)
> +{
> +       u32 max_width = 0;
> +
> +       if (of_property_read_u32(of_node, "max-width", &max_width))
> +               max_width = DP_MAX_WIDTH;
> +
> +       return max_width;

msm_dp_panel->max_dp_width = DP_MAX_WIDTH;
of_property_read_u32(of_node, "max-width", &msm_dp_panel->max_dp_width);

> +}
> +
>  static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>  {
>         struct msm_dp_panel_private *panel;
> @@ -490,6 +501,8 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>         if (!msm_dp_panel->max_dp_link_rate)
>                 msm_dp_panel->max_dp_link_rate = DP_LINK_RATE_HBR2;
>
> +       msm_dp_panel->max_dp_width = msm_dp_panel_max_width(of_node);
> +
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
> index 7603b92c32902bd3d4485539bd6308537ff75a2c..61513644161209c243bbb623ee4ded951b2a0597 100644
> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
> @@ -51,6 +51,7 @@ struct msm_dp_panel {
>         u32 lane_map[DP_MAX_NUM_DP_LANES];
>         u32 max_dp_lanes;
>         u32 max_dp_link_rate;
> +       u32 max_dp_width;
>
>         u32 max_bw_code;
>  };
>
> --
> 2.25.1
>


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 7/8] drm/msm/dp: Retry Link Training 2 with lower pattern
  2024-11-29  7:57 ` [PATCH 7/8] drm/msm/dp: Retry Link Training 2 with lower pattern Xiangxu Yin
@ 2024-11-29 13:53   ` Dmitry Baryshkov
  2024-12-03  8:13     ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-11-29 13:53 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>
> Add a mechanism to retry Link Training 2 by lowering the pattern level
> when the link training #2 first attempt fails. This approach enhances
> compatibility, particularly addressing issues caused by certain hub
> configurations.

Please reference corresponding part of the standard, describing this lowering.

>
> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> ---
>  drivers/gpu/drm/msm/dp/dp_ctrl.c | 34 ++++++++++++++++++++++++++++++----
>  1 file changed, 30 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> index 49c8ce9b2d0e57a613e50865be3fe98e814d425a..b1862294cb98c9f756b0108b7670cb42de37bae4 100644
> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> @@ -1220,7 +1220,7 @@ static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl)
>  }
>
>  static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
> -                       int *training_step)
> +                       int *training_step, bool downgrade)
>  {
>         int tries = 0, ret = 0;
>         u8 pattern;
> @@ -1243,6 +1243,28 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
>                 state_ctrl_bit = 2;
>         }
>
> +       /*
> +        * DP link training uses the highest allowed pattern by default.
> +        * If it fails, the pattern is downgraded to improve cable and monitor compatibility.
> +        */
> +       if (downgrade) {
> +               switch (pattern) {
> +               case DP_TRAINING_PATTERN_4:
> +                       pattern = DP_TRAINING_PATTERN_3;
> +                       state_ctrl_bit = 3;
> +                       break;
> +               case DP_TRAINING_PATTERN_3:
> +                       pattern = DP_TRAINING_PATTERN_2;
> +                       state_ctrl_bit = 2;
> +                       break;
> +               default:
> +                       break;
> +               }
> +       }
> +
> +       drm_dbg_dp(ctrl->drm_dev, "pattern(%d) state_ctrl_bit(%d) downgrade(%d)\n",
> +               pattern, state_ctrl_bit, downgrade);
> +
>         ret = msm_dp_catalog_ctrl_set_pattern_state_bit(ctrl->catalog, state_ctrl_bit);
>         if (ret)
>                 return ret;
> @@ -1311,10 +1333,14 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
>         /* print success info as this is a result of user initiated action */
>         drm_dbg_dp(ctrl->drm_dev, "link training #1 successful\n");
>
> -       ret = msm_dp_ctrl_link_train_2(ctrl, training_step);
> +       ret = msm_dp_ctrl_link_train_2(ctrl, training_step, false);
>         if (ret) {
> -               DRM_ERROR("link training #2 failed. ret=%d\n", ret);
> -               goto end;
> +               drm_dbg_dp(ctrl->drm_dev, "link training #2 failed, retry downgrade.\n");
> +               ret = msm_dp_ctrl_link_train_2(ctrl, training_step, true);
> +               if (ret) {
> +                       DRM_ERROR("link training #2 failed. ret=%d\n", ret);
> +                       goto end;
> +               }
>         }
>
>         /* print success info as this is a result of user initiated action */
>
> --
> 2.25.1
>


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 4/8] drm/msm/dp: Add DisplayPort support for QCS615
  2024-11-29  7:57 ` [PATCH 4/8] drm/msm/dp: Add DisplayPort support for QCS615 Xiangxu Yin
@ 2024-11-29 13:54   ` Dmitry Baryshkov
  0 siblings, 0 replies; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-11-29 13:54 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>
> The Qualcomm QCS615 platform comes with a DisplayPort controller use the
> same base offset as sc7180. add support for this in DP driver.
>
> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> ---
>  drivers/gpu/drm/msm/dp/dp_display.c | 1 +
>  1 file changed, 1 insertion(+)

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 8/8] drm/msm/dp: Support external GPIO HPD with 3rd pinctrl chip
  2024-11-29  7:57 ` [PATCH 8/8] drm/msm/dp: Support external GPIO HPD with 3rd pinctrl chip Xiangxu Yin
  2024-11-29  8:21   ` Krzysztof Kozlowski
  2024-11-29 13:45   ` Dmitry Baryshkov
@ 2024-11-29 13:54   ` neil.armstrong
  2 siblings, 0 replies; 60+ messages in thread
From: neil.armstrong @ 2024-11-29 13:54 UTC (permalink / raw)
  To: Xiangxu Yin, Rob Clark, Abhinav Kumar, Dmitry Baryshkov,
	Sean Paul, Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio

On 29/11/2024 08:57, Xiangxu Yin wrote:
> Add support for handling HPD (Hot Plug Detect) signals via external
> GPIOs connected through pinctrl chips (e.g., Semtech SX1509Q). This
> involves reinitializing the relevant GPIO and binding an interrupt
> handler to process hot plug events. Since external GPIOs only support
> edge interrupts (rising or falling) rather than state interrupts, the
> GPIO state must be read during the first DP bridge HPD enablement. This
> ensures the current connection state is determined and a hot plug event
> is reported accordingly.
> 
> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> ---
>   drivers/gpu/drm/msm/dp/dp_display.c | 83 +++++++++++++++++++++++++++++++++++++
>   1 file changed, 83 insertions(+)
> 
> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
> index eb6fb76c68e505fafbec563440e9784f51e1894b..22c288ca61b9b444a7b8d4a574c614bfef9d88be 100644
> --- a/drivers/gpu/drm/msm/dp/dp_display.c
> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> @@ -13,6 +13,8 @@
>   #include <linux/delay.h>
>   #include <drm/display/drm_dp_aux_bus.h>
>   #include <drm/drm_edid.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/of_gpio.h>
>   
>   #include "msm_drv.h"
>   #include "msm_kms.h"
> @@ -78,6 +80,10 @@ struct msm_dp_display_private {
>   
>   	unsigned int id;
>   
> +	bool ext_gpio;
> +	int gpio_num;
> +	struct work_struct  gpio_work;
> +
>   	/* state variables */
>   	bool core_initialized;
>   	bool phy_initialized;
> @@ -1182,6 +1188,42 @@ static irqreturn_t msm_dp_display_irq_handler(int irq, void *dev_id)
>   	return ret;
>   }
>   
> +
> +static void msm_dp_gpio_work_handler(struct work_struct *work)
> +{
> +	struct msm_dp_display_private *dp = container_of(work,
> +			struct msm_dp_display_private, gpio_work);
> +	struct gpio_desc *desc;
> +	bool hpd;
> +
> +	if (dp->ext_gpio) {
> +		desc = gpio_to_desc(dp->gpio_num);
> +		if (!desc) {
> +			pr_err("Failed to get gpio_desc for GPIO %d\n", dp->gpio_num);
> +			return;
> +		}
> +
> +		hpd = gpiod_get_value_cansleep(desc);
> +		if (hpd)
> +			msm_dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0);
> +		else
> +			msm_dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0);
> +	}
> +}
> +
> +static irqreturn_t msm_dp_gpio_isr(int unused, void *data)
> +{
> +	struct msm_dp_display_private *dp = data;
> +
> +	if (!dp) {
> +		DRM_ERROR("NULL data\n");
> +		return IRQ_NONE;
> +	}
> +
> +	schedule_work(&dp->gpio_work);

this msm_dp_gpio_isr is already threaded, would would you also schedule a work ?

> +	return IRQ_HANDLED;
> +}
> +
>   static int msm_dp_display_request_irq(struct msm_dp_display_private *dp)
>   {
>   	int rc = 0;
> @@ -1193,6 +1235,21 @@ static int msm_dp_display_request_irq(struct msm_dp_display_private *dp)
>   		return dp->irq;
>   	}
>   
> +	if (dp->ext_gpio) {
> +		int edge, gpio_irq;
> +
> +		gpio_irq = gpio_to_irq(dp->gpio_num);

But as Dmitry reported, the system should use a dp-connected as a next bridge
instead which already supports all this much better:
drivers/gpu/drm/bridge/display-connector.c
Documentation/devicetree/bindings/display/connector/dp-connector.yaml

> +		edge = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
> +
> +		rc = devm_request_threaded_irq(&pdev->dev, gpio_irq, NULL,
> +		msm_dp_gpio_isr, edge, "dp_gpio_isr", dp);
> +		if (rc < 0) {
> +			DRM_ERROR("failed to request ext-gpio IRQ%u: %d\n",
> +					gpio_irq, rc);
> +			return rc;
> +		}
> +	}
> +
>   	rc = devm_request_irq(&pdev->dev, dp->irq, msm_dp_display_irq_handler,
>   			      IRQF_TRIGGER_HIGH|IRQF_NO_AUTOEN,
>   			      "dp_display_isr", dp);
> @@ -1308,10 +1365,32 @@ static int msm_dp_display_probe(struct platform_device *pdev)
>   		return -EPROBE_DEFER;
>   	}
>   
> +	if (of_find_property(pdev->dev.of_node, "dp-hpd-gpio", NULL)) {
> +		dp->ext_gpio = true;
> +		dp->gpio_num = of_get_named_gpio(pdev->dev.of_node, "dp-hpd-gpio", 0);
> +		if (dp->gpio_num < 0) {
> +			dev_err(&pdev->dev, "Failed to get gpio:%d\n", dp->gpio_num);
> +			return dp->gpio_num;
> +		}
> +
> +		if (!gpio_is_valid(dp->gpio_num)) {
> +			DRM_ERROR("gpio(%d) invalid\n", dp->gpio_num);
> +			return -EINVAL;
> +		}
> +
> +		rc = gpio_request(dp->gpio_num, "dp-hpd-gpio");
> +		if (rc) {
> +			dev_err(&pdev->dev, "Failed to request gpio:%d\n", dp->gpio_num);
> +			return rc;
> +		}
> +		gpio_direction_input(dp->gpio_num);
> +	}
> +
>   	/* setup event q */
>   	mutex_init(&dp->event_mutex);
>   	init_waitqueue_head(&dp->event_q);
>   	spin_lock_init(&dp->event_lock);
> +	INIT_WORK(&dp->gpio_work, msm_dp_gpio_work_handler);
>   
>   	/* Store DP audio handle inside DP display */
>   	dp->msm_dp_display.msm_dp_audio = dp->audio;
> @@ -1678,6 +1757,10 @@ void msm_dp_bridge_hpd_enable(struct drm_bridge *bridge)
>   	msm_dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, true);
>   
>   	msm_dp_display->internal_hpd = true;
> +
> +	if (dp->ext_gpio)
> +		schedule_work(&dp->gpio_work);
> +
>   	mutex_unlock(&dp->event_mutex);
>   }
>   
> 


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-11-29  7:57 ` [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615 Xiangxu Yin
  2024-11-29  8:18   ` Krzysztof Kozlowski
  2024-11-29 12:12   ` kernel test robot
@ 2024-11-29 14:33   ` Dmitry Baryshkov
  2024-12-05 13:26     ` Xiangxu Yin
  2 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-11-29 14:33 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>
> Extended DP support for QCS615 USB or DP phy. Differentiated between
> USBC and DP PHY using the match table’s type, dynamically generating
> different types of cfg and layout attributes during initialization based
> on this type. Static variables are stored in cfg, while parsed values
> are organized into the layout structure.

We didn't have an understanding / conclusion whether
qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
or two PHYs being placed next to each other. Could you please start
your commit message by explaining it? Or even better, make that a part
of the cover letter for a new series touching just the USBC PHY
driver. DP changes don't have anything in common with the PHY changes,
so you can split the series into two.

>
> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> ---
>  drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h |    1 +
>  drivers/phy/qualcomm/phy-qcom-qmp-usbc.c   | 1453 ++++++++++++++++++++++++----

Too many changes for a single patch. Please split into logical chunks.

>  2 files changed, 1254 insertions(+), 200 deletions(-)
>
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h
> index 0ebd405bcaf0cac8215550bfc9b226f30cc43a59..59885616405f878885d0837838a0bac1899fb69f 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h
> @@ -25,6 +25,7 @@
>  #define QSERDES_DP_PHY_AUX_CFG7                                0x03c
>  #define QSERDES_DP_PHY_AUX_CFG8                                0x040
>  #define QSERDES_DP_PHY_AUX_CFG9                                0x044
> +#define QSERDES_DP_PHY_VCO_DIV                         0x068
>
>  /* QSERDES COM_BIAS_EN_CLKBUFLR_EN bits */
>  # define QSERDES_V3_COM_BIAS_EN                                0x0001
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
> index cf12a6f12134dc77ff032f967b2efa43e3de4b21..7fece9d7dc959ed5a7c62077d8552324c3734859 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
> @@ -22,13 +22,20 @@
>  #include <linux/slab.h>
>  #include <linux/usb/typec.h>
>  #include <linux/usb/typec_mux.h>
> +#include <dt-bindings/phy/phy-qcom-qmp.h>
> +#include <drm/bridge/aux-bridge.h>
>
>  #include "phy-qcom-qmp-common.h"
>
>  #include "phy-qcom-qmp.h"
>  #include "phy-qcom-qmp-pcs-misc-v3.h"
>
> +#include "phy-qcom-qmp-dp-phy.h"
> +#include "phy-qcom-qmp-dp-phy-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 {
> @@ -284,7 +291,26 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = {
>         QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88),
>  };
>
> -struct qmp_usbc_offsets {
> +enum qmp_phy_usbc_type {
> +       QMP_PHY_USBC_INVALID,

How can a type be invalid?

> +       QMP_PHY_USBC_USB,
> +       QMP_PHY_USBC_DP,
> +};
> +
> +/* list of regulators */
> +struct qmp_regulator_data {
> +       const char *name;
> +       unsigned int enable_load;
> +};
> +
> +struct dev_cfg {
> +       int type;
> +       const void *cfg;
> +};
> +
> +struct qmp_usbc;
> +
> +struct qmp_usbc_usb_offsets {
>         u16 serdes;
>         u16 pcs;
>         u16 pcs_misc;
> @@ -295,9 +321,9 @@ struct qmp_usbc_offsets {
>         u16 rx2;
>  };
>
> -/* struct qmp_phy_cfg - per-PHY initialization config */
> -struct qmp_phy_cfg {
> -       const struct qmp_usbc_offsets *offsets;
> +/* struct qmp_phy_usb_cfg - per-usb PHY initialization config */

what is "per-usb PHY"?

> +struct qmp_phy_usb_cfg {
> +       const struct qmp_usbc_usb_offsets *offsets;
>
>         /* Init sequence for PHY blocks - serdes, tx, rx, pcs */
>         const struct qmp_phy_init_tbl *serdes_tbl;
> @@ -317,11 +343,7 @@ struct qmp_phy_cfg {
>         const unsigned int *regs;
>  };
>
> -struct qmp_usbc {
> -       struct device *dev;
> -
> -       const struct qmp_phy_cfg *cfg;
> -
> +struct qmp_phy_usb_layout {
>         void __iomem *serdes;
>         void __iomem *pcs;
>         void __iomem *pcs_misc;
> @@ -329,28 +351,67 @@ struct qmp_usbc {
>         void __iomem *rx;
>         void __iomem *tx2;
>         void __iomem *rx2;
> -
>         struct regmap *tcsr_map;
>         u32 vls_clamp_reg;
> -
> +       enum phy_mode mode;
> +       struct typec_switch_dev *sw;
>         struct clk *pipe_clk;
> +       struct clk_fixed_rate pipe_clk_fixed;
> +};
> +
> +struct qmp_usbc_dp_offsets {
> +       u16 dp_serdes;
> +       u16 dp_txa;
> +       u16 dp_txb;
> +       u16 dp_phy;
> +};
> +
> +/* struct qmp_phy_dp_cfg - per-dp PHY initialization config */
> +struct qmp_phy_dp_cfg {
> +       const struct qmp_usbc_dp_offsets *offsets;
> +
> +       /* DP PHY swing and pre_emphasis tables */
> +       const u8 (*swing_tbl)[4][4];
> +       const u8 (*pre_emphasis_tbl)[4][4];
> +
> +       // /* DP PHY callbacks */
> +       int (*dp_aux_init)(struct qmp_usbc *qmp);
> +       int (*configure_dp_serdes)(struct qmp_usbc *qmp);
> +       int (*configure_dp_voltages)(struct qmp_usbc *qmp);
> +       int (*configure_dp_phy)(struct qmp_usbc *qmp);
> +       int (*calibrate_dp_phy)(struct qmp_usbc *qmp);
> +
> +       const struct qmp_regulator_data *vreg_list;
> +       int num_vregs;
> +};
> +
> +struct qmp_phy_dp_layout {
> +       void __iomem *dp_phy;
> +       void __iomem *dp_tx;
> +       void __iomem *dp_tx2;
> +       void __iomem *dp_serdes;
> +       struct regmap *tcsr_map;
> +       u32 dp_phy_mode;
> +       unsigned int dp_aux_cfg;
> +       struct phy_configure_opts_dp dp_opts;
> +       struct clk_hw dp_link_hw;
> +       struct clk_hw dp_pixel_hw;
> +};
> +
> +struct qmp_usbc {
> +       struct device *dev;
> +       int type;
>         struct clk_bulk_data *clks;
>         int num_clks;
>         int num_resets;
>         struct reset_control_bulk_data *resets;
>         struct regulator_bulk_data *vregs;
> -
>         struct mutex phy_mutex;
> -
> -       enum phy_mode mode;
> -       unsigned int usb_init_count;
> -
>         struct phy *phy;
> -
> -       struct clk_fixed_rate pipe_clk_fixed;
> -
> -       struct typec_switch_dev *sw;
>         enum typec_orientation orientation;
> +       unsigned int init_count;
> +       const void *cfg;
> +       void *layout;

The patch contains a mixture of renames bundled with actual changes.
Please explain why old names are bad in a separate patch.

>  };
>
>  static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
> @@ -391,12 +452,21 @@ static const char * const usb3phy_reset_l[] = {
>         "phy_phy", "phy",
>  };
>
> +static const char * const dp_usb3phy_reset_l[] = {
> +       "phy",
> +};
> +
>  /* list of regulators */
> -static const char * const qmp_phy_vreg_l[] = {
> +static const char * const qmp_phy_usb_vreg_l[] = {
>         "vdda-phy", "vdda-pll",
>  };
>
> -static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {
> +static struct qmp_regulator_data qmp_phy_dp_vreg_l[] = {
> +       { .name = "vdda-phy", .enable_load = 21800 },
> +       { .name = "vdda-pll", .enable_load = 36000 },
> +};
> +
> +static const struct qmp_usbc_usb_offsets qmp_usbc_usb_offsets_v3_qcm2290 = {
>         .serdes         = 0x0,
>         .pcs            = 0xc00,
>         .pcs_misc       = 0xa00,
> @@ -406,8 +476,15 @@ static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {
>         .rx2            = 0x800,
>  };
>
> -static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
> -       .offsets                = &qmp_usbc_offsets_v3_qcm2290,
> +static const struct qmp_usbc_dp_offsets qmp_usbc_dp_offsets_qcs615 = {
> +       .dp_serdes      = 0x0C00,
> +       .dp_txa         = 0x0400,
> +       .dp_txb         = 0x0800,
> +       .dp_phy         = 0x0000,
> +};
> +
> +static const struct qmp_phy_usb_cfg msm8998_usb3phy_cfg = {
> +       .offsets                = &qmp_usbc_usb_offsets_v3_qcm2290,
>
>         .serdes_tbl             = msm8998_usb3_serdes_tbl,
>         .serdes_tbl_num         = ARRAY_SIZE(msm8998_usb3_serdes_tbl),
> @@ -417,13 +494,13 @@ 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_usb_vreg_l,
> +       .num_vregs              = ARRAY_SIZE(qmp_phy_usb_vreg_l),
>         .regs                   = qmp_v3_usb3phy_regs_layout,
>  };
>
> -static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = {
> -       .offsets                = &qmp_usbc_offsets_v3_qcm2290,
> +static const struct qmp_phy_usb_cfg qcm2290_usb3phy_cfg = {
> +       .offsets                = &qmp_usbc_usb_offsets_v3_qcm2290,
>
>         .serdes_tbl             = qcm2290_usb3_serdes_tbl,
>         .serdes_tbl_num         = ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
> @@ -433,13 +510,13 @@ 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_usb_vreg_l,
> +       .num_vregs              = ARRAY_SIZE(qmp_phy_usb_vreg_l),
>         .regs                   = qmp_v3_usb3phy_regs_layout_qcm2290,
>  };
>
> -static const struct qmp_phy_cfg sdm660_usb3phy_cfg = {
> -       .offsets                = &qmp_usbc_offsets_v3_qcm2290,
> +static const struct qmp_phy_usb_cfg sdm660_usb3phy_cfg = {
> +       .offsets                = &qmp_usbc_usb_offsets_v3_qcm2290,
>
>         .serdes_tbl             = qcm2290_usb3_serdes_tbl,
>         .serdes_tbl_num         = ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
> @@ -449,20 +526,352 @@ 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_usb_vreg_l,
> +       .num_vregs              = ARRAY_SIZE(qmp_phy_usb_vreg_l),
>         .regs                   = qmp_v3_usb3phy_regs_layout_qcm2290,
>  };
>
> -static int qmp_usbc_init(struct phy *phy)
> +static const u8 qmp_dp_pre_emphasis_hbr2_rbr[4][4] = {
> +       {0x00, 0x0B, 0x12, 0xFF},       /* pe0, 0 db */
> +       {0x00, 0x0A, 0x12, 0xFF},       /* pe1, 3.5 db */
> +       {0x00, 0x0C, 0xFF, 0xFF},       /* pe2, 6.0 db */
> +       {0xFF, 0xFF, 0xFF, 0xFF}        /* pe3, 9.5 db */
> +};
> +
> +static const u8 qmp_dp_voltage_swing_hbr2_rbr[4][4] = {
> +       {0x07, 0x0F, 0x14, 0xFF}, /* sw0, 0.4v  */
> +       {0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */
> +       {0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */
> +       {0xFF, 0xFF, 0xFF, 0xFF}  /* sw1, 1.2 v, optional */
> +};
> +
> +static int qcs615_qmp_dp_aux_init(struct qmp_usbc *qmp);
> +static int qcs615_qmp_configure_dp_serdes(struct qmp_usbc *qmp);
> +static int qcs615_qmp_configure_dp_voltages(struct qmp_usbc *qmp);
> +static int qcs615_qmp_configure_dp_phy(struct qmp_usbc *qmp);
> +static int qcs615_qmp_calibrate_dp_phy(struct qmp_usbc *qmp);

Are those functions really platform-specific?

> +
> +static void qmp_usbc_check_dp_phy(struct qmp_usbc *qmp, const char *pos);
> +
> +static const struct qmp_phy_dp_cfg qcs615_dpphy_cfg = {
> +       .offsets                = &qmp_usbc_dp_offsets_qcs615,
> +
> +       .swing_tbl              = &qmp_dp_voltage_swing_hbr2_rbr,
> +       .pre_emphasis_tbl       = &qmp_dp_pre_emphasis_hbr2_rbr,
> +
> +       .dp_aux_init            = qcs615_qmp_dp_aux_init,
> +       .configure_dp_serdes    = qcs615_qmp_configure_dp_serdes,
> +       .configure_dp_voltages  = qcs615_qmp_configure_dp_voltages,
> +       .configure_dp_phy   = qcs615_qmp_configure_dp_phy,
> +       .calibrate_dp_phy       = qcs615_qmp_calibrate_dp_phy,
> +
> +       .vreg_list              = qmp_phy_dp_vreg_l,
> +       .num_vregs              = ARRAY_SIZE(qmp_phy_dp_vreg_l),
> +};
> +
> +#define to_usb_cfg(x) ((struct qmp_phy_usb_cfg *)(x->cfg))
> +#define to_dp_cfg(x) ((struct qmp_phy_dp_cfg *)(x->cfg))
> +#define to_usb_layout(x) ((struct qmp_phy_usb_layout *)(x->layout))
> +#define to_dp_layout(x) ((struct qmp_phy_dp_layout *)(x->layout))
> +
> +static int qcs615_qmp_dp_aux_init(struct qmp_usbc *qmp)
> +{
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +
> +       regmap_write(layout->tcsr_map, layout->dp_phy_mode, 0x1);
> +
> +       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,
> +              layout->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,
> +              layout->dp_phy + QSERDES_DP_PHY_PD_CTL);
> +
> +       writel(0x00, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG0);
> +       writel(0x13, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG1);
> +       writel(0x00, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG2);
> +       writel(0x00, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG3);
> +       writel(0x0a, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG4);
> +       writel(0x26, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG5);
> +       writel(0x0a, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG6);
> +       writel(0x03, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG7);
> +       writel(0xbb, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG8);
> +       writel(0x03, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG9);
> +       layout->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,
> +              layout->dp_phy + QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK);
> +       return 0;
> +}

We've had DP PHY implementation in QMP Combo PHY and in eDP PHY.
Please review them and work on extracting common bits into some kind
of a library. At least -combo and your -usbc implementation seem close
enough to warrant common library code.

> +
> +static int qcs615_qmp_configure_dp_serdes(struct qmp_usbc *qmp)
> +{
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +       void __iomem *serdes = layout->dp_serdes;
> +       const struct phy_configure_opts_dp *dp_opts = &layout->dp_opts;
> +       u8 hsclk_sel;
> +       u8 dec_start_mode0;
> +       u8 div_frac_start1_mode0;
> +       u8 div_frac_start2_mode0;
> +       u8 div_frac_start3_mode0;
> +       u8 lock_cmp1_mode0;
> +       u8 lock_cmp2_mode0;
> +       u8 lock_cmp3_mode0;
> +
> +       switch (dp_opts->link_rate) {
> +       case 1620:
> +               hsclk_sel = 0x2c;
> +               dec_start_mode0 = 0x69;
> +               div_frac_start1_mode0 = 0x00;
> +               div_frac_start2_mode0 = 0x80;
> +               div_frac_start3_mode0 = 0x07;
> +               lock_cmp1_mode0 = 0xbf;
> +               lock_cmp2_mode0 = 0x21;
> +               lock_cmp3_mode0 = 0x00;
> +               break;
> +       case 2700:
> +               hsclk_sel = 0x24;
> +               dec_start_mode0 = 0x69;
> +               div_frac_start1_mode0 = 0x00;
> +               div_frac_start2_mode0 = 0x80;
> +               div_frac_start3_mode0 = 0x07;
> +               lock_cmp1_mode0 = 0x3f;
> +               lock_cmp2_mode0 = 0x38;
> +               lock_cmp3_mode0 = 0x00;
> +               break;
> +       case 5400:
> +               hsclk_sel = 0x20;
> +               dec_start_mode0 = 0x8c;
> +               div_frac_start1_mode0 = 0x00;
> +               div_frac_start2_mode0 = 0x00;
> +               div_frac_start3_mode0 = 0x0a;
> +               lock_cmp1_mode0 = 0x7f;
> +               lock_cmp2_mode0 = 0x70;
> +               lock_cmp3_mode0 = 0x00;
> +               break;
> +       default:
> +               /* Other link rates aren't supported */
> +               return -EINVAL;
> +       }
> +
> +       writel(0x01, serdes + QSERDES_COM_SVS_MODE_CLK_SEL);
> +       writel(0x37, serdes + QSERDES_COM_SYSCLK_EN_SEL);
> +       writel(0x00, serdes + QSERDES_COM_CLK_SELECT);
> +       writel(0x06, serdes + QSERDES_COM_SYS_CLK_CTRL);
> +       writel(0x3f, serdes + QSERDES_COM_BIAS_EN_CLKBUFLR_EN);
> +       writel(0x0e, serdes + QSERDES_COM_CLK_ENABLE1);
> +       writel(0x0f, serdes + QSERDES_COM_BG_CTRL);
> +       writel(0x06, serdes + QSERDES_COM_SYSCLK_BUF_ENABLE);
> +       writel(0x30, serdes + QSERDES_COM_CLK_SELECT);
> +       writel(0x0f, serdes + QSERDES_COM_PLL_IVCO);
> +       writel(0x28, serdes + QSERDES_COM_PLL_CCTRL_MODE0);
> +       writel(0x16, serdes + QSERDES_COM_PLL_RCTRL_MODE0);
> +       writel(0x0b, serdes + QSERDES_COM_CP_CTRL_MODE0);
> +
> +       writel(hsclk_sel, serdes + QSERDES_COM_HSCLK_SEL);
> +       writel(dec_start_mode0, serdes + QSERDES_COM_DEC_START_MODE0);
> +       writel(div_frac_start1_mode0, serdes + QSERDES_COM_DIV_FRAC_START1_MODE0);
> +       writel(div_frac_start2_mode0, serdes + QSERDES_COM_DIV_FRAC_START2_MODE0);
> +       writel(div_frac_start3_mode0, serdes + QSERDES_COM_DIV_FRAC_START3_MODE0);
> +       writel(lock_cmp1_mode0, serdes + QSERDES_COM_LOCK_CMP1_MODE0);
> +       writel(lock_cmp2_mode0, serdes + QSERDES_COM_LOCK_CMP2_MODE0);
> +       writel(lock_cmp3_mode0, serdes + QSERDES_COM_LOCK_CMP3_MODE0);
> +
> +       writel(0x40, serdes + QSERDES_COM_INTEGLOOP_GAIN0_MODE0);
> +       writel(0x00, serdes + QSERDES_COM_INTEGLOOP_GAIN1_MODE0);
> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE_MAP);
> +       writel(0x08, serdes + QSERDES_COM_BG_TIMER);
> +       writel(0x05, serdes + QSERDES_COM_CORECLK_DIV);
> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE_CTRL);
> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE1_MODE0);
> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE2_MODE0);
> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE_CTRL);
> +
> +       writel(0x0f, serdes + QSERDES_COM_CORE_CLK_EN);
> +
> +       return 0;
> +}
> +
> +static int qcs615_qmp_configure_dp_voltages(struct qmp_usbc *qmp)
> +{
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +       struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> +       const struct phy_configure_opts_dp *dp_opts = &layout->dp_opts;
> +       void __iomem *tx = layout->dp_tx;
> +       void __iomem *tx2 = layout->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) || (pre_emphasis_cfg > 4)) {
> +               dev_err(qmp->dev, "Invalid v(%d) | p(%d) level)\n",
> +                       v_level, pre_emphasis_cfg);
> +               return -EINVAL;
> +       }
> +
> +       voltage_swing_cfg = (*cfg->swing_tbl)[v_level][p_level];
> +       pre_emphasis_cfg = (*cfg->pre_emphasis_tbl)[v_level][p_level];
> +
> +       /* Enable MUX to use Cursor values from these registers */
> +       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;
> +
> +       /* program default setting first */
> +       writel(0x2A, tx + QSERDES_V3_TX_TX_DRV_LVL);
> +       writel(0x20, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> +       writel(0x2A, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
> +       writel(0x20, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);

Lowercase all hex numbers.

> +
> +       writel(voltage_swing_cfg, tx + QSERDES_V3_TX_TX_DRV_LVL);
> +       writel(pre_emphasis_cfg, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> +       writel(voltage_swing_cfg, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
> +       writel(pre_emphasis_cfg, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> +
> +       return 0;
> +}
> +
> +static int qcs615_qmp_configure_dp_phy(struct qmp_usbc *qmp)
> +{
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +       u32 status;
> +
> +       writel(0x01, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +       writel(0x05, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +       writel(0x01, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +       writel(0x09, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +
> +       writel(0x20, layout->dp_serdes + QSERDES_COM_RESETSM_CNTRL);
> +
> +       // C_READY
> +       if (readl_poll_timeout(layout->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;
> +       }
> +
> +       // FREQ_DONE
> +       if (readl_poll_timeout(layout->dp_serdes + QSERDES_COM_CMN_STATUS,
> +                       status,
> +                       ((status & BIT(0)) > 0),
> +                       500,
> +                       10000)){
> +               dev_err(qmp->dev, "FREQ_DONE not ready\n");
> +               return -ETIMEDOUT;
> +       }
> +
> +       // PLL_LOCKED
> +       if (readl_poll_timeout(layout->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, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +       udelay(10);
> +
> +       // TSYNC_DONE
> +       if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS,
> +                       status,
> +                       ((status & BIT(0)) > 0),
> +                       500,
> +                       10000)){
> +               dev_err(qmp->dev, "TSYNC_DONE not ready\n");
> +               return -ETIMEDOUT;
> +       }
> +
> +       // PHY_READY
> +       if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS,
> +                       status,
> +                       ((status & BIT(1)) > 0),
> +                       500,
> +                       10000)){
> +               dev_err(qmp->dev, "PHY_READY not ready\n");
> +               return -ETIMEDOUT;
> +       }
> +
> +       writel(0x3f, layout->dp_tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
> +       writel(0x10, layout->dp_tx + QSERDES_V3_TX_HIGHZ_DRVR_EN);
> +       writel(0x0a, layout->dp_tx + QSERDES_V3_TX_TX_POL_INV);
> +       writel(0x3f, layout->dp_tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
> +       writel(0x10, layout->dp_tx2 + QSERDES_V3_TX_HIGHZ_DRVR_EN);
> +       writel(0x0a, layout->dp_tx2 + QSERDES_V3_TX_TX_POL_INV);
> +
> +       writel(0x18, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +       writel(0x19, layout->dp_phy + QSERDES_DP_PHY_CFG);
> +
> +       if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_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 qcs615_qmp_calibrate_dp_phy(struct qmp_usbc *qmp)
> +{
> +       static const u8 cfg1_settings[] = {0x13, 0x23, 0x1d};
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +       u8 val;
> +
> +       layout->dp_aux_cfg++;
> +       layout->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
> +       val = cfg1_settings[layout->dp_aux_cfg];
> +
> +       writel(val, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG1);
> +
> +       qmp_usbc_check_dp_phy(qmp, "pos_calibrate");
> +
> +       return 0;
> +}
> +
> +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;
> +       int num_vregs;
>         u32 val = 0;
>         int ret;
> +       unsigned int reg_pwr_dn;
>
> -       ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
> +       if (qmp->type == QMP_PHY_USBC_USB) {
> +               struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> +
> +               num_vregs = cfg->num_vregs;
> +               reg_pwr_dn = cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL];
> +       } else {
> +               struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> +
> +               num_vregs = cfg->num_vregs;
> +       }
> +
> +       ret = regulator_bulk_enable(num_vregs, qmp->vregs);
>         if (ret) {
>                 dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
>                 return ret;
> @@ -484,73 +893,85 @@ static int qmp_usbc_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);
> +
> +       if (qmp->type == QMP_PHY_USBC_USB) {

Why?

> +               struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> +
> +               qphy_setbits(layout->pcs, reg_pwr_dn, SW_PWRDN);
> +               writel(val, layout->pcs_misc);
> +       }
>
>         return 0;
>
>  err_assert_reset:
>         reset_control_bulk_assert(qmp->num_resets, qmp->resets);
>  err_disable_regulators:
> -       regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
> +       regulator_bulk_disable(num_vregs, qmp->vregs);
>
>         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;
> +       int num_vregs;
>
>         reset_control_bulk_assert(qmp->num_resets, qmp->resets);
>
>         clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
>
> -       regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
> +       if (qmp->type == QMP_PHY_USBC_USB) {
> +               struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> +
> +               num_vregs = cfg->num_vregs;
> +       } else {
> +               struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> +
> +               num_vregs = cfg->num_vregs;
> +       }
> +       regulator_bulk_disable(num_vregs, qmp->vregs);
>
>         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;
> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>         void __iomem *status;
>         unsigned int val;
>         int ret;
>
> -       qmp_configure(qmp->dev, qmp->serdes, cfg->serdes_tbl,
> +       qmp_configure(qmp->dev, layout->serdes, cfg->serdes_tbl,
>                       cfg->serdes_tbl_num);
>
> -       ret = clk_prepare_enable(qmp->pipe_clk);
> +       ret = clk_prepare_enable(layout->pipe_clk);
>         if (ret) {
>                 dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret);
>                 return ret;
>         }
>
>         /* Tx, Rx, and PCS configurations */
> -       qmp_configure_lane(qmp->dev, qmp->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
> -       qmp_configure_lane(qmp->dev, qmp->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
> +       qmp_configure_lane(qmp->dev, layout->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
> +       qmp_configure_lane(qmp->dev, layout->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
>
> -       qmp_configure_lane(qmp->dev, qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);
> -       qmp_configure_lane(qmp->dev, qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
> +       qmp_configure_lane(qmp->dev, layout->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);
> +       qmp_configure_lane(qmp->dev, layout->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
>
> -       qmp_configure(qmp->dev, qmp->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
> +       qmp_configure(qmp->dev, layout->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
>
>         /* Pull PHY out of reset state */
> -       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
> +       qphy_clrbits(layout->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
>
>         /* start SerDes and Phy-Coding-Sublayer */
> -       qphy_setbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START);
> +       qphy_setbits(layout->pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START);
>
> -       status = qmp->pcs + cfg->regs[QPHY_PCS_STATUS];
> +       status = layout->pcs + cfg->regs[QPHY_PCS_STATUS];
>         ret = readl_poll_timeout(status, val, !(val & PHYSTATUS), 200,
>                                  PHY_INIT_COMPLETE_TIMEOUT);
>         if (ret) {
> @@ -561,92 +982,348 @@ static int qmp_usbc_power_on(struct phy *phy)
>         return 0;
>
>  err_disable_pipe_clk:
> -       clk_disable_unprepare(qmp->pipe_clk);
> +       clk_disable_unprepare(layout->pipe_clk);
>
>         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;
> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>
> -       clk_disable_unprepare(qmp->pipe_clk);
> +       clk_disable_unprepare(layout->pipe_clk);
>
>         /* PHY reset */
> -       qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
> +       qphy_setbits(layout->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
>
>         /* stop SerDes and Phy-Coding-Sublayer */
> -       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL],
> +       qphy_clrbits(layout->pcs, cfg->regs[QPHY_START_CTRL],
>                         SERDES_START | PCS_START);
>
>         /* Put PHY into POWER DOWN state: active low */
> -       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
> +       qphy_clrbits(layout->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
>                         SW_PWRDN);
>
>         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;
>         }
>
> -       qmp->usb_init_count++;
> +       qmp->init_count++;
>  out_unlock:
>         mutex_unlock(&qmp->phy_mutex);
>
>         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);
> +       qmp->init_count--;
> +       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_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode)
> +{
> +       struct qmp_usbc *qmp = phy_get_drvdata(phy);
> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> +
> +       layout->mode = mode;
> +
> +       return 0;
> +}
> +
> +static int qmp_usbc_dp_init(struct phy *phy)
> +{
> +       struct qmp_usbc *qmp = phy_get_drvdata(phy);
> +       const struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> +       int ret;
> +
> +       if (qmp->init_count) {
> +               dev_err(qmp->dev, "type(%d) inited(%d)\n", qmp->type, qmp->init_count);
> +               return 0;
> +       }
> +
> +       mutex_lock(&qmp->phy_mutex);
> +
> +       ret = qmp_usbc_com_init(phy);
> +       if (ret) {
> +               dev_err(qmp->dev, "type(%d) com_init fail\n", qmp->type);
> +               goto dp_init_unlock;
> +       }
> +
> +       cfg->dp_aux_init(qmp);
> +
> +       qmp->init_count++;
> +
> +dp_init_unlock:
> +       mutex_unlock(&qmp->phy_mutex);
> +       return ret;
> +}
> +
> +static int qmp_usbc_dp_exit(struct phy *phy)
> +{
> +       struct qmp_usbc *qmp = phy_get_drvdata(phy);
> +
> +       mutex_lock(&qmp->phy_mutex);
> +
> +       qmp_usbc_com_exit(phy);
> +
> +       qmp->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);
> +       struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +       int ret;
> +
> +       mutex_lock(&qmp->phy_mutex);
> +
> +       memcpy(&layout->dp_opts, dp_opts, sizeof(*dp_opts));
> +       if (layout->dp_opts.set_voltages) {
> +               ret = cfg->configure_dp_voltages(qmp);
> +               if (ret) {
> +                       dev_err(qmp->dev, "type(%d) err(%d)\n", qmp->type, ret);
> +                       mutex_unlock(&qmp->phy_mutex);
> +                       return ret;
> +               }
> +
> +               layout->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);
> +       struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> +       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, "type(%d) err(%d)\n", qmp->type, ret);
> +                       mutex_unlock(&qmp->phy_mutex);
> +                       return ret;
> +               }
> +       }
> +
> +       mutex_unlock(&qmp->phy_mutex);
> +       return 0;
>  }
>
> -static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode)
> +static int qmp_usbc_configure_dp_clocks(struct qmp_usbc *qmp)
> +{
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +       const struct phy_configure_opts_dp *dp_opts = &layout->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;
> +       case 8100:
> +               phy_vco_div = 0x0;
> +               pixel_freq = 8100000000UL / 6;
> +               break;
> +       default:
> +               /* Other link rates aren't supported */
> +               return -EINVAL;
> +       }
> +       writel(phy_vco_div, layout->dp_phy + QSERDES_DP_PHY_VCO_DIV);
> +
> +       clk_set_rate(layout->dp_link_hw.clk, dp_opts->link_rate * 100000);
> +       clk_set_rate(layout->dp_pixel_hw.clk, pixel_freq);
> +
> +       return 0;
> +}
> +
> +static void qmp_usbc_check_dp_phy(struct qmp_usbc *qmp, const char *pos)
> +{
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +       u8 c_ready, cmn_status, phy_status;
> +
> +       c_ready = readl(layout->dp_serdes + QSERDES_COM_C_READY_STATUS);
> +       cmn_status = readl(layout->dp_serdes + QSERDES_COM_CMN_STATUS);
> +       phy_status = readl(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS);
> +
> +       dev_dbg(qmp->dev, "pos(%s) c_ready(0x%x) cmn_status(0x%x) phy_status(0x%x)\n",
> +               pos, c_ready, cmn_status, phy_status);
> +}
> +
> +static int qmp_usbc_dp_power_on(struct phy *phy)
> +{
> +       struct qmp_usbc *qmp = phy_get_drvdata(phy);
> +       const struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +       const struct phy_configure_opts_dp *dp_opts = &layout->dp_opts;
> +       bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
> +       void __iomem *tx = layout->dp_tx;
> +       void __iomem *tx2 = layout->dp_tx2;
> +       u8 lane_mode_1;
> +       int ret = 0;
> +
> +       mutex_lock(&qmp->phy_mutex);
> +
> +       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,
> +               layout->dp_phy + QSERDES_DP_PHY_PD_CTL);
> +
> +       ret = cfg->configure_dp_serdes(qmp);
> +       if (ret) {
> +               dev_err(qmp->dev, "failed to config pll\n");
> +               goto power_on_unlock;
> +       }
> +
> +       if (dp_opts->link_rate >= 2700)
> +               lane_mode_1 = 0xc4;
> +       else
> +               lane_mode_1 = 0xc6;
> +
> +       writel(lane_mode_1, tx + QSERDES_V3_TX_LANE_MODE_1);
> +       writel(lane_mode_1, tx2 + QSERDES_V3_TX_LANE_MODE_1);
> +
> +       if (reverse)
> +               writel(0xc9, layout->dp_phy + QSERDES_DP_PHY_MODE);
> +       else
> +               writel(0xd9, layout->dp_phy + QSERDES_DP_PHY_MODE);
> +
> +       writel(0x05, layout->dp_phy + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL);
> +       writel(0x05, layout->dp_phy + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL);
> +
> +       writel(0x1a, tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
> +       writel(0x40, tx + QSERDES_V3_TX_VMODE_CTRL1);
> +       writel(0x30, tx + QSERDES_V3_TX_PRE_STALL_LDO_BOOST_EN);
> +       writel(0x3d, tx + QSERDES_V3_TX_INTERFACE_SELECT);
> +       writel(0x0f, tx + QSERDES_V3_TX_CLKBUF_ENABLE);
> +       writel(0x03, tx + QSERDES_V3_TX_RESET_TSYNC_EN);
> +       writel(0x03, tx + QSERDES_V3_TX_TRAN_DRVR_EMP_EN);
> +       writel(0x00, tx + QSERDES_V3_TX_PARRATE_REC_DETECT_IDLE_EN);
> +       writel(0x00, tx + QSERDES_V3_TX_TX_INTERFACE_MODE);
> +       writel(0x2b, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> +       writel(0x2f, tx + QSERDES_V3_TX_TX_DRV_LVL);
> +       writel(0x04, tx + QSERDES_V3_TX_TX_BAND);
> +       writel(0x12, tx + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX);
> +       writel(0x12, tx + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX);
> +
> +       writel(0x1a, tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
> +       writel(0x40, tx2 + QSERDES_V3_TX_VMODE_CTRL1);
> +       writel(0x30, tx2 + QSERDES_V3_TX_PRE_STALL_LDO_BOOST_EN);
> +       writel(0x3d, tx2 + QSERDES_V3_TX_INTERFACE_SELECT);
> +       writel(0x0f, tx2 + QSERDES_V3_TX_CLKBUF_ENABLE);
> +       writel(0x03, tx2 + QSERDES_V3_TX_RESET_TSYNC_EN);
> +       writel(0x03, tx2 + QSERDES_V3_TX_TRAN_DRVR_EMP_EN);
> +       writel(0x00, tx2 + QSERDES_V3_TX_PARRATE_REC_DETECT_IDLE_EN);
> +       writel(0x00, tx2 + QSERDES_V3_TX_TX_INTERFACE_MODE);
> +       writel(0x2b, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> +       writel(0x2f, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
> +       writel(0x04, tx2 + QSERDES_V3_TX_TX_BAND);
> +       writel(0x12, tx2 + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX);
> +       writel(0x12, tx2 + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX);
> +
> +       writel(0x02, layout->dp_serdes + QSERDES_COM_CMN_CONFIG);
> +       qmp_usbc_configure_dp_clocks(qmp);
> +
> +       ret = cfg->configure_dp_phy(qmp);
> +       if (ret) {
> +               dev_err(qmp->dev, "failed to config dp phy\n");
> +               goto power_on_unlock;
> +       }
> +
> +       qmp_usbc_check_dp_phy(qmp, "usbc_dp_power_on_finish");
> +
> +power_on_unlock:
> +       mutex_unlock(&qmp->phy_mutex);
> +
> +       return ret;
> +}
> +
> +static int qmp_usbc_dp_power_off(struct phy *phy)
>  {
>         struct qmp_usbc *qmp = phy_get_drvdata(phy);
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +
> +       mutex_lock(&qmp->phy_mutex);
>
> -       qmp->mode = mode;
> +       /* Assert DP PHY power down */
> +       writel(DP_PHY_PD_CTL_PSR_PWRDN, layout->dp_phy + QSERDES_DP_PHY_PD_CTL);
> +
> +       mutex_unlock(&qmp->phy_mutex);
>
>         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,
> +};
> +
> +static const struct phy_ops qmp_usbc_dp_phy_ops = {
> +       .init           = qmp_usbc_dp_init,
> +       .exit           = qmp_usbc_dp_exit,
> +       .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;
> -       void __iomem *pcs = qmp->pcs;
> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> +       void __iomem *pcs = layout->pcs;
>         u32 intr_mask;
>
> -       if (qmp->mode == PHY_MODE_USB_HOST_SS ||
> -           qmp->mode == PHY_MODE_USB_DEVICE_SS)
> +       if (layout->mode == PHY_MODE_USB_HOST_SS ||
> +           layout->mode == PHY_MODE_USB_DEVICE_SS)
>                 intr_mask = ARCVR_DTCT_EN | ALFPS_DTCT_EN;
>         else
>                 intr_mask = ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL;
> @@ -663,18 +1340,19 @@ static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp)
>         qphy_setbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask);
>
>         /* Enable i/o clamp_n for autonomous mode */
> -       if (qmp->tcsr_map && qmp->vls_clamp_reg)
> -               regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 1);
> +       if (layout->tcsr_map && layout->vls_clamp_reg)
> +               regmap_write(layout->tcsr_map, layout->vls_clamp_reg, 1);
>  }
>
>  static void qmp_usbc_disable_autonomous_mode(struct qmp_usbc *qmp)
>  {
> -       const struct qmp_phy_cfg *cfg = qmp->cfg;
> -       void __iomem *pcs = qmp->pcs;
> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> +       void __iomem *pcs = layout->pcs;
>
>         /* Disable i/o clamp_n on resume for normal mode */
> -       if (qmp->tcsr_map && qmp->vls_clamp_reg)
> -               regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 0);
> +       if (layout->tcsr_map && layout->vls_clamp_reg)
> +               regmap_write(layout->tcsr_map, layout->vls_clamp_reg, 0);
>
>         qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL],
>                      ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL | ALFPS_DTCT_EN);
> @@ -688,16 +1366,19 @@ static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev)
>  {
>         struct qmp_usbc *qmp = dev_get_drvdata(dev);
>
> -       dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode);
> -
>         if (!qmp->phy->init_count) {
>                 dev_vdbg(dev, "PHY not initialized, bailing out\n");
>                 return 0;
>         }
>
> -       qmp_usbc_enable_autonomous_mode(qmp);
> +       if (qmp->type == QMP_PHY_USBC_USB) {
> +               struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> +
> +               dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", layout->mode);
> +               qmp_usbc_enable_autonomous_mode(qmp);
> +               clk_disable_unprepare(layout->pipe_clk);
> +       }
>
> -       clk_disable_unprepare(qmp->pipe_clk);
>         clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
>
>         return 0;
> @@ -708,8 +1389,6 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev)
>         struct qmp_usbc *qmp = dev_get_drvdata(dev);
>         int ret = 0;
>
> -       dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode);
> -
>         if (!qmp->phy->init_count) {
>                 dev_vdbg(dev, "PHY not initialized, bailing out\n");
>                 return 0;
> @@ -719,14 +1398,19 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev)
>         if (ret)
>                 return ret;
>
> -       ret = clk_prepare_enable(qmp->pipe_clk);
> -       if (ret) {
> -               dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);
> -               clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
> -               return ret;
> -       }
> +       if (qmp->type == QMP_PHY_USBC_USB) {
> +               struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>
> -       qmp_usbc_disable_autonomous_mode(qmp);
> +               dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", layout->mode);
> +               ret = clk_prepare_enable(layout->pipe_clk);
> +               if (ret) {
> +                       dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);
> +                       clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
> +                       return ret;
> +               }
> +
> +               qmp_usbc_disable_autonomous_mode(qmp);
> +       }
>
>         return 0;
>  }
> @@ -738,19 +1422,54 @@ static const struct dev_pm_ops qmp_usbc_pm_ops = {
>
>  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;
> +       int ret, i;
>
> -       qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL);
> -       if (!qmp->vregs)
> -               return -ENOMEM;
> +       if (qmp->type == QMP_PHY_USBC_USB) {
> +               struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> +               int num = cfg->num_vregs;
>
> -       for (i = 0; i < num; i++)
> -               qmp->vregs[i].supply = cfg->vreg_list[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);
> +               ret = devm_regulator_bulk_get(dev, num, qmp->vregs);
> +               if (ret) {
> +                       dev_err(dev, "failed at devm_regulator_bulk_get\n");
> +                       return ret;
> +               }
> +       } else {
> +               struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> +               int num = cfg->num_vregs;
> +
> +               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].name;
> +
> +               ret = devm_regulator_bulk_get(dev, num, qmp->vregs);
> +               if (ret) {
> +                       dev_err(dev, "failed at devm_regulator_bulk_get\n");
> +                       return ret;
> +               }
> +
> +               for (i = 0; i < num; i++) {
> +                       ret = regulator_set_load(qmp->vregs[i].consumer,
> +                                               cfg->vreg_list[i].enable_load);
> +                       if (ret) {
> +                               dev_err(dev, "failed to set load at %s\n",
> +                                       qmp->vregs[i].supply);
> +                               return ret;
> +                       }
> +               }
> +       }
> +
> +       return 0;
>  }
>
>  static int qmp_usbc_reset_init(struct qmp_usbc *qmp,
> @@ -821,7 +1540,9 @@ static void phy_clk_release_provider(void *res)
>   */
>  static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np)
>  {
> -       struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed;
> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> +
> +       struct clk_fixed_rate *fixed = &layout->pipe_clk_fixed;
>         struct clk_init_data init = { };
>         int ret;
>
> @@ -864,12 +1585,12 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw,
>         mutex_lock(&qmp->phy_mutex);
>         qmp->orientation = orientation;
>
> -       if (qmp->usb_init_count) {
> -               qmp_usbc_power_off(qmp->phy);
> -               qmp_usbc_exit(qmp->phy);
> +       if (qmp->init_count) {
> +               qmp_usbc_usb_power_off(qmp->phy);
> +               qmp_usbc_com_exit(qmp->phy);
>
> -               qmp_usbc_init(qmp->phy);
> -               qmp_usbc_power_on(qmp->phy);
> +               qmp_usbc_com_init(qmp->phy);
> +               qmp_usbc_usb_power_on(qmp->phy);
>         }
>
>         mutex_unlock(&qmp->phy_mutex);
> @@ -880,22 +1601,24 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw,
>  static void qmp_usbc_typec_unregister(void *data)
>  {
>         struct qmp_usbc *qmp = data;
> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>
> -       typec_switch_unregister(qmp->sw);
> +       typec_switch_unregister(layout->sw);
>  }
>
>  static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp)
>  {
>         struct typec_switch_desc sw_desc = {};
>         struct device *dev = qmp->dev;
> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>
>         sw_desc.drvdata = qmp;
>         sw_desc.fwnode = dev->fwnode;
>         sw_desc.set = qmp_usbc_typec_switch_set;
> -       qmp->sw = typec_switch_register(dev, &sw_desc);
> -       if (IS_ERR(qmp->sw)) {
> -               dev_err(dev, "Unable to register typec switch: %pe\n", qmp->sw);
> -               return PTR_ERR(qmp->sw);
> +       layout->sw = typec_switch_register(dev, &sw_desc);
> +       if (IS_ERR(layout->sw)) {
> +               dev_err(dev, "Unable to register typec switch: %pe\n", layout->sw);
> +               return PTR_ERR(layout->sw);
>         }
>
>         return devm_add_action_or_reset(dev, qmp_usbc_typec_unregister, qmp);
> @@ -907,15 +1630,16 @@ static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp)
>  }
>  #endif
>
> -static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np)
> +static int qmp_usbc_parse_usb_dt_legacy(struct qmp_usbc *qmp, struct device_node *np)
>  {
>         struct platform_device *pdev = to_platform_device(qmp->dev);
>         struct device *dev = qmp->dev;
> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>         int ret;
>
> -       qmp->serdes = devm_platform_ioremap_resource(pdev, 0);
> -       if (IS_ERR(qmp->serdes))
> -               return PTR_ERR(qmp->serdes);
> +       layout->serdes = devm_platform_ioremap_resource(pdev, 0);
> +       if (IS_ERR(layout->serdes))
> +               return PTR_ERR(layout->serdes);
>
>         /*
>          * Get memory resources for the PHY:
> @@ -923,35 +1647,35 @@ static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np
>          * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5
>          * For single lane PHYs: pcs_misc (optional) -> 3.
>          */
> -       qmp->tx = devm_of_iomap(dev, np, 0, NULL);
> -       if (IS_ERR(qmp->tx))
> -               return PTR_ERR(qmp->tx);
> +       layout->tx = devm_of_iomap(dev, np, 0, NULL);
> +       if (IS_ERR(layout->tx))
> +               return PTR_ERR(layout->tx);
>
> -       qmp->rx = devm_of_iomap(dev, np, 1, NULL);
> -       if (IS_ERR(qmp->rx))
> -               return PTR_ERR(qmp->rx);
> +       layout->rx = devm_of_iomap(dev, np, 1, NULL);
> +       if (IS_ERR(layout->rx))
> +               return PTR_ERR(layout->rx);
>
> -       qmp->pcs = devm_of_iomap(dev, np, 2, NULL);
> -       if (IS_ERR(qmp->pcs))
> -               return PTR_ERR(qmp->pcs);
> +       layout->pcs = devm_of_iomap(dev, np, 2, NULL);
> +       if (IS_ERR(layout->pcs))
> +               return PTR_ERR(layout->pcs);
>
> -       qmp->tx2 = devm_of_iomap(dev, np, 3, NULL);
> -       if (IS_ERR(qmp->tx2))
> -               return PTR_ERR(qmp->tx2);
> +       layout->tx2 = devm_of_iomap(dev, np, 3, NULL);
> +       if (IS_ERR(layout->tx2))
> +               return PTR_ERR(layout->tx2);
>
> -       qmp->rx2 = devm_of_iomap(dev, np, 4, NULL);
> -       if (IS_ERR(qmp->rx2))
> -               return PTR_ERR(qmp->rx2);
> +       layout->rx2 = devm_of_iomap(dev, np, 4, NULL);
> +       if (IS_ERR(layout->rx2))
> +               return PTR_ERR(layout->rx2);
>
> -       qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
> -       if (IS_ERR(qmp->pcs_misc)) {
> +       layout->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
> +       if (IS_ERR(layout->pcs_misc)) {
>                 dev_vdbg(dev, "PHY pcs_misc-reg not used\n");
> -               qmp->pcs_misc = NULL;
> +               layout->pcs_misc = NULL;
>         }
>
> -       qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
> -       if (IS_ERR(qmp->pipe_clk)) {
> -               return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
> +       layout->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
> +       if (IS_ERR(layout->pipe_clk)) {
> +               return dev_err_probe(dev, PTR_ERR(layout->pipe_clk),
>                                      "failed to get pipe clock\n");
>         }
>
> @@ -969,11 +1693,12 @@ static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np
>         return 0;
>  }
>
> -static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
> +static int qmp_usbc_parse_usb_dt(struct qmp_usbc *qmp)
>  {
>         struct platform_device *pdev = to_platform_device(qmp->dev);
> -       const struct qmp_phy_cfg *cfg = qmp->cfg;
> -       const struct qmp_usbc_offsets *offs = cfg->offsets;
> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> +       const struct qmp_usbc_usb_offsets *offs = cfg->offsets;
> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>         struct device *dev = qmp->dev;
>         void __iomem *base;
>         int ret;
> @@ -985,23 +1710,23 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
>         if (IS_ERR(base))
>                 return PTR_ERR(base);
>
> -       qmp->serdes = base + offs->serdes;
> -       qmp->pcs = base + offs->pcs;
> +       layout->serdes = base + offs->serdes;
> +       layout->pcs = base + offs->pcs;
>         if (offs->pcs_misc)
> -               qmp->pcs_misc = base + offs->pcs_misc;
> -       qmp->tx = base + offs->tx;
> -       qmp->rx = base + offs->rx;
> +               layout->pcs_misc = base + offs->pcs_misc;
> +       layout->tx = base + offs->tx;
> +       layout->rx = base + offs->rx;
>
> -       qmp->tx2 = base + offs->tx2;
> -       qmp->rx2 = base + offs->rx2;
> +       layout->tx2 = base + offs->tx2;
> +       layout->rx2 = base + offs->rx2;
>
>         ret = qmp_usbc_clk_init(qmp);
>         if (ret)
>                 return ret;
>
> -       qmp->pipe_clk = devm_clk_get(dev, "pipe");
> -       if (IS_ERR(qmp->pipe_clk)) {
> -               return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
> +       layout->pipe_clk = devm_clk_get(dev, "pipe");
> +       if (IS_ERR(layout->pipe_clk)) {
> +               return dev_err_probe(dev, PTR_ERR(layout->pipe_clk),
>                                      "failed to get pipe clock\n");
>         }
>
> @@ -1013,10 +1738,11 @@ 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_usb_vls_clamp(struct qmp_usbc *qmp)
>  {
>         struct of_phandle_args tcsr_args;
>         struct device *dev = qmp->dev;
> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>         int ret;
>
>         /*  for backwards compatibility ignore if there is no property */
> @@ -1027,22 +1753,280 @@ static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp)
>         else if (ret < 0)
>                 return dev_err_probe(dev, ret, "Failed to parse qcom,tcsr-reg\n");
>
> -       qmp->tcsr_map = syscon_node_to_regmap(tcsr_args.np);
> +       layout->tcsr_map = syscon_node_to_regmap(tcsr_args.np);
>         of_node_put(tcsr_args.np);
> -       if (IS_ERR(qmp->tcsr_map))
> -               return PTR_ERR(qmp->tcsr_map);
> +       if (IS_ERR(layout->tcsr_map))
> +               return PTR_ERR(layout->tcsr_map);
>
> -       qmp->vls_clamp_reg = tcsr_args.args[0];
> +       layout->vls_clamp_reg = tcsr_args.args[0];
>
>         return 0;
>  }
>
> +static int qmp_usbc_parse_dp_phy_mode(struct qmp_usbc *qmp)
> +{
> +       struct of_phandle_args tcsr_args;
> +       struct device *dev = qmp->dev;
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +       int ret;
> +
> +       /*  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);
> +       if (ret < 0)
> +               return dev_err_probe(dev, ret, "Failed to parse qcom,tcsr-reg\n");
> +
> +       layout->tcsr_map = syscon_node_to_regmap(tcsr_args.np);
> +       of_node_put(tcsr_args.np);
> +       if (IS_ERR(layout->tcsr_map))
> +               return PTR_ERR(layout->tcsr_map);
> +
> +       layout->dp_phy_mode = tcsr_args.args[0];
> +
> +       return 0;
> +}
> +
> +static int qmp_usbc_parse_dp_dt(struct qmp_usbc *qmp)
> +{
> +       struct platform_device *pdev = to_platform_device(qmp->dev);
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +       struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> +       const struct qmp_usbc_dp_offsets *offs = cfg->offsets;
> +       struct device *dev = qmp->dev;
> +       void __iomem *base;
> +       int ret;
> +
> +       base = devm_platform_ioremap_resource(pdev, 0);
> +       if (IS_ERR(base)) {
> +               dev_err(dev, "get resource fail, ret:%d\n", ret);
> +               return PTR_ERR(base);
> +       }
> +
> +       layout->dp_serdes = base + offs->dp_serdes;
> +       layout->dp_tx = base + offs->dp_txa;
> +       layout->dp_tx2 = base + offs->dp_txb;
> +       layout->dp_phy = base + offs->dp_phy;
> +
> +       ret = qmp_usbc_clk_init(qmp);
> +       if (ret) {
> +               dev_err(dev, "clk init fail, ret:%d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = qmp_usbc_reset_init(qmp, dp_usb3phy_reset_l,
> +                                ARRAY_SIZE(dp_usb3phy_reset_l));
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +/*
> + * 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 and 8.1 GHz are same link rate as 2.7GHz, i.e. div 4 and div 6 */
> +               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;
> +       struct qmp_phy_dp_layout *layout;
> +       const struct phy_configure_opts_dp *dp_opts;
> +
> +       layout = container_of(hw, struct qmp_phy_dp_layout, dp_pixel_hw);
> +
> +       dp_opts = &layout->dp_opts;
> +
> +       switch (dp_opts->link_rate) {
> +       case 1620:
> +               return 1620000000UL / 2;
> +       case 2700:
> +               return 2700000000UL / 2;
> +       case 5400:
> +               return 5400000000UL / 4;
> +       case 8100:
> +               return 8100000000UL / 6;
> +       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:
> +       case 810000000:
> +               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_combo *qmp;
> +       struct qmp_phy_dp_layout *layout;
> +       const struct phy_configure_opts_dp *dp_opts;
> +
> +       layout = container_of(hw, struct qmp_phy_dp_layout, dp_link_hw);
> +       dp_opts = &layout->dp_opts;
> +
> +       switch (dp_opts->link_rate) {
> +       case 1620:
> +       case 2700:
> +       case 5400:
> +       case 8100:
> +               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 = { };
> +       int ret = 0;
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +
> +       ret = of_property_read_string_index(np, "clock-output-names", 0, &init.name);
> +       if (ret < 0) {
> +               dev_err(qmp->dev, "%pOFn: No link clock-output-names\n", np);
> +               return ret;
> +       }
> +
> +       init.ops = &qmp_dp_link_clk_ops;
> +       layout->dp_link_hw.init = &init;
> +       ret = devm_clk_hw_register(qmp->dev, &layout->dp_link_hw);
> +       if (ret < 0) {
> +               dev_err(qmp->dev, "link clk reg fail ret=%d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
> +       if (ret) {
> +               dev_err(qmp->dev, "%pOFn: No div clock-output-names\n", np);
> +               return ret;
> +       }
> +
> +       init.ops = &qmp_dp_pixel_clk_ops;
> +       layout->dp_pixel_hw.init = &init;
> +       ret = devm_clk_hw_register(qmp->dev, &layout->dp_pixel_hw);
> +       if (ret) {
> +               dev_err(qmp->dev, "pxl clk reg fail ret=%d\n", ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static struct clk_hw *qmp_dp_clks_hw_get(struct of_phandle_args *clkspec, void *data)
> +{
> +       struct qmp_usbc *qmp = data;
> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> +
> +       switch (clkspec->args[0]) {
> +       case QMP_USB43DP_DP_LINK_CLK:
> +               return &layout->dp_link_hw;
> +       case QMP_USB43DP_DP_VCO_DIV_CLK:
> +               return &layout->dp_pixel_hw;
> +       }
> +
> +       return ERR_PTR(-EINVAL);
> +}
> +
> +static int qmp_dp_register_clocks(struct qmp_usbc *qmp, struct device_node *dp_np)
> +{
> +       int ret;
> +
> +       ret = phy_dp_clks_register(qmp, dp_np);
> +       if (ret) {
> +               dev_err(qmp->dev, "dp clk reg fail ret:%d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = of_clk_add_hw_provider(dp_np, qmp_dp_clks_hw_get, qmp);
> +       if (ret) {
> +               dev_err(qmp->dev, "add provider fail ret:%d\n", ret);
> +               return ret;
> +       }
> +
> +       return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, dp_np);
> +}
> +
>  static int qmp_usbc_probe(struct platform_device *pdev)
>  {
>         struct device *dev = &pdev->dev;
>         struct phy_provider *phy_provider;
>         struct device_node *np;
>         struct qmp_usbc *qmp;
> +       const struct dev_cfg *data_cfg;
>         int ret;
>
>         qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL);
> @@ -1050,38 +2034,74 @@ static int qmp_usbc_probe(struct platform_device *pdev)
>                 return -ENOMEM;
>
>         qmp->dev = dev;
> -       dev_set_drvdata(dev, qmp);
>
>         qmp->orientation = TYPEC_ORIENTATION_NORMAL;
>
> -       qmp->cfg = of_device_get_match_data(dev);
> -       if (!qmp->cfg)
> +       qmp->init_count = 0;
> +
> +       data_cfg = of_device_get_match_data(dev);
> +       if (!data_cfg) {
> +               dev_err(qmp->dev, "get data fail\n");
>                 return -EINVAL;
> +       }
>
>         mutex_init(&qmp->phy_mutex);
>
> -       ret = qmp_usbc_vreg_init(qmp);
> -       if (ret)
> -               return ret;
> +       qmp->type = data_cfg->type;
> +       qmp->cfg = data_cfg->cfg;
>
> -       ret = qmp_usbc_typec_switch_register(qmp);
> -       if (ret)
> +       ret = qmp_usbc_vreg_init(qmp);
> +       if (ret) {
> +               dev_err(qmp->dev, "qmp_type(%d) vreg init fail\n", qmp->type);
>                 return ret;
> +       }
>
> -       ret = qmp_usbc_parse_vls_clamp(qmp);
> -       if (ret)
> -               return ret;
> +       if (qmp->type == QMP_PHY_USBC_USB) {
> +               qmp->layout = devm_kzalloc(dev, sizeof(struct qmp_phy_usb_layout), GFP_KERNEL);
> +               if (!qmp->layout)
> +                       return -ENOMEM;
> +
> +               ret = qmp_usbc_typec_switch_register(qmp);
> +               if (ret)
> +                       return ret;
> +
> +               ret = qmp_usbc_parse_usb_vls_clamp(qmp);
> +               if (ret)
> +                       return ret;
> +
> +               /* Check for legacy binding with child node. */
> +               np = of_get_child_by_name(dev->of_node, "phy");
> +               if (np) {
> +                       ret = qmp_usbc_parse_usb_dt_legacy(qmp, np);
> +               } else {
> +                       np = of_node_get(dev->of_node);
> +                       ret = qmp_usbc_parse_usb_dt(qmp);
> +               }
> +               if (ret)
> +                       goto err_node_put;
> +       } else if (qmp->type == QMP_PHY_USBC_DP) {
> +               qmp->layout = devm_kzalloc(dev, sizeof(struct qmp_phy_dp_layout), GFP_KERNEL);
> +               if (!qmp->layout)
> +                       return -ENOMEM;
>
> -       /* Check for legacy binding with child node. */
> -       np = of_get_child_by_name(dev->of_node, "phy");
> -       if (np) {
> -               ret = qmp_usbc_parse_dt_legacy(qmp, np);
> -       } else {
>                 np = of_node_get(dev->of_node);
> -               ret = qmp_usbc_parse_dt(qmp);
> -       }
> -       if (ret)
> +               ret = qmp_usbc_parse_dp_phy_mode(qmp);
> +               if (ret)
> +                       goto err_node_put;
> +
> +               ret = qmp_usbc_parse_dp_dt(qmp);
> +               if (ret)
> +                       goto err_node_put;
> +
> +               ret = drm_aux_bridge_register(dev);
> +               if (ret) {
> +                       dev_err(qmp->dev, "aux bridge reg fail ret=%d\n", ret);
> +                       goto err_node_put;
> +               }
> +       } else {
> +               dev_err(dev, "invalid phy type: %d\n", qmp->type);
>                 goto err_node_put;
> +       }
>
>         pm_runtime_set_active(dev);
>         ret = devm_pm_runtime_enable(dev);
> @@ -1093,19 +2113,33 @@ static int qmp_usbc_probe(struct platform_device *pdev)
>          */
>         pm_runtime_forbid(dev);
>
> -       ret = phy_pipe_clk_register(qmp, np);
> -       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);
> -               dev_err(dev, "failed to create PHY: %d\n", ret);
> -               goto err_node_put;
> +       if (qmp->type == QMP_PHY_USBC_USB) {
> +               // pipe clk process
> +               ret = phy_pipe_clk_register(qmp, np);
> +               if (ret)
> +                       goto err_node_put;
> +
> +               qmp->phy = devm_phy_create(dev, np, &qmp_usbc_usb_phy_ops);
> +               if (IS_ERR(qmp->phy)) {
> +                       ret = PTR_ERR(qmp->phy);
> +                       dev_err(dev, "failed to create PHY: %d\n", ret);
> +                       goto err_node_put;
> +               }
> +       } else {
> +               ret = qmp_dp_register_clocks(qmp, np);
> +               if (ret)
> +                       goto err_node_put;
> +
> +               qmp->phy = devm_phy_create(dev, np, &qmp_usbc_dp_phy_ops);
> +               if (IS_ERR(qmp->phy)) {
> +                       ret = PTR_ERR(qmp->phy);
> +                       dev_err(dev, "failed to create PHY: %d\n", ret);
> +                       goto err_node_put;
> +               }
>         }
>
>         phy_set_drvdata(qmp->phy, qmp);
> -
> +       dev_set_drvdata(dev, qmp);
>         of_node_put(np);
>
>         phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> @@ -1120,19 +2154,38 @@ static int qmp_usbc_probe(struct platform_device *pdev)
>  static const struct of_device_id qmp_usbc_of_match_table[] = {
>         {
>                 .compatible = "qcom,msm8998-qmp-usb3-phy",
> -               .data = &msm8998_usb3phy_cfg,
> +               .data =  &(struct dev_cfg) {
> +                       .type = QMP_PHY_USBC_USB,
> +                       .cfg = &msm8998_usb3phy_cfg,
> +               },
>         }, {
>                 .compatible = "qcom,qcm2290-qmp-usb3-phy",
> -               .data = &qcm2290_usb3phy_cfg,
> +               .data =  &(struct dev_cfg) {
> +                       .type = QMP_PHY_USBC_USB,
> +                       .cfg = &qcm2290_usb3phy_cfg,
> +               },
> +       }, {
> +               .compatible = "qcom,qcs615-qmp-dp-phy",
> +               .data =  &(struct dev_cfg) {
> +                       .type = QMP_PHY_USBC_DP,
> +                       .cfg = &qcs615_dpphy_cfg,
> +               },
>         }, {
>                 .compatible = "qcom,sdm660-qmp-usb3-phy",
> -               .data = &sdm660_usb3phy_cfg,
> +               .data =  &(struct dev_cfg) {
> +                       .type = QMP_PHY_USBC_USB,
> +                       .cfg = &sdm660_usb3phy_cfg,
> +               },
>         }, {
>                 .compatible = "qcom,sm6115-qmp-usb3-phy",
> -               .data = &qcm2290_usb3phy_cfg,
> +               .data =  &(struct dev_cfg) {
> +                       .type = QMP_PHY_USBC_USB,
> +                       .cfg = &qcm2290_usb3phy_cfg,
> +               },
>         },
>         { },
>  };
> +
>  MODULE_DEVICE_TABLE(of, qmp_usbc_of_match_table);
>
>  static struct platform_driver qmp_usbc_driver = {
>
> --
> 2.25.1
>


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration
  2024-11-29 13:50   ` Dmitry Baryshkov
@ 2024-12-02  8:40     ` Xiangxu Yin
  2024-12-02 10:46       ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-12-02  8:40 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 11/29/2024 9:50 PM, Dmitry Baryshkov wrote:
> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>
>> Add the ability to configure lane mapping for the DP controller. This is
>> required when the platform's lane mapping does not follow the default
>> order (0, 1, 2, 3). The mapping rules are now configurable via the
>> `data-lane` property in the devicetree. This property defines the
>> logical-to-physical lane mapping sequence, ensuring correct lane
>> assignment for non-default configurations.
>>
>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
>> ---
>>  drivers/gpu/drm/msm/dp/dp_catalog.c | 11 +++++------
>>  drivers/gpu/drm/msm/dp/dp_catalog.h |  2 +-
>>  drivers/gpu/drm/msm/dp/dp_ctrl.c    |  2 +-
>>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 ++++++++++---
>>  drivers/gpu/drm/msm/dp/dp_panel.h   |  3 +++
>>  5 files changed, 20 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
>> index b4c8856fb25d01dd1b30c5ec33ce821aafa9551d..34439d0709d2e1437e5669fd0b995936420ee16f 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_catalog.c
>> +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
>> @@ -361,17 +361,16 @@ void msm_dp_catalog_ctrl_config_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32
>>         msm_dp_write_link(catalog, REG_DP_CONFIGURATION_CTRL, cfg);
>>  }
>>
>> -void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog)
>> +void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog, u32 *l_map)
> 
> lane_map, not l_map.
> 
Ok, will update in next patch.
>>  {
>>         struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog,
>>                                 struct msm_dp_catalog_private, msm_dp_catalog);
>> -       u32 ln_0 = 0, ln_1 = 1, ln_2 = 2, ln_3 = 3; /* One-to-One mapping */
>>         u32 ln_mapping;
>>
>> -       ln_mapping = ln_0 << LANE0_MAPPING_SHIFT;
>> -       ln_mapping |= ln_1 << LANE1_MAPPING_SHIFT;
>> -       ln_mapping |= ln_2 << LANE2_MAPPING_SHIFT;
>> -       ln_mapping |= ln_3 << LANE3_MAPPING_SHIFT;
>> +       ln_mapping = l_map[0] << LANE0_MAPPING_SHIFT;
>> +       ln_mapping |= l_map[1] << LANE1_MAPPING_SHIFT;
>> +       ln_mapping |= l_map[2] << LANE2_MAPPING_SHIFT;
>> +       ln_mapping |= l_map[3] << LANE3_MAPPING_SHIFT;
>>
>>         msm_dp_write_link(catalog, REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING,
>>                         ln_mapping);
>> diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
>> index e932b17eecbf514070cd8cd0b98ca0fefbe81ab7..8b8de2a7d3ad561c1901e1bdaad92d4fab12e808 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_catalog.h
>> +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
>> @@ -69,7 +69,7 @@ u32 msm_dp_catalog_aux_get_irq(struct msm_dp_catalog *msm_dp_catalog);
>>  /* DP Controller APIs */
>>  void msm_dp_catalog_ctrl_state_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 state);
>>  void msm_dp_catalog_ctrl_config_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 config);
>> -void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog);
>> +void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog, u32 *l_map);
>>  void msm_dp_catalog_ctrl_mainlink_ctrl(struct msm_dp_catalog *msm_dp_catalog, bool enable);
>>  void msm_dp_catalog_ctrl_psr_mainlink_enable(struct msm_dp_catalog *msm_dp_catalog, bool enable);
>>  void msm_dp_catalog_setup_peripheral_flush(struct msm_dp_catalog *msm_dp_catalog);
>> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
>> index bc2ca8133b790fc049e18ab3b37a629558664dd4..49c8ce9b2d0e57a613e50865be3fe98e814d425a 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
>> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
>> @@ -177,7 +177,7 @@ static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl
>>  {
>>         u32 cc, tb;
>>
>> -       msm_dp_catalog_ctrl_lane_mapping(ctrl->catalog);
>> +       msm_dp_catalog_ctrl_lane_mapping(ctrl->catalog, ctrl->panel->lane_map);
>>         msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
>>         msm_dp_catalog_setup_peripheral_flush(ctrl->catalog);
>>
>> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
>> index 5d7eaa31bf3176566f40f01ff636bee64e81c64f..8654180aa259234bbd41f4f88c13c485f9791b1d 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_panel.c
>> +++ b/drivers/gpu/drm/msm/dp/dp_panel.c
>> @@ -11,7 +11,6 @@
>>  #include <drm/drm_of.h>
>>  #include <drm/drm_print.h>
>>
>> -#define DP_MAX_NUM_DP_LANES    4
>>  #define DP_LINK_RATE_HBR2      540000 /* kbytes */
>>
>>  struct msm_dp_panel_private {
>> @@ -461,6 +460,7 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>>         struct msm_dp_panel_private *panel;
>>         struct device_node *of_node;
>>         int cnt;
>> +       u32 lane_map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3};
>>
>>         panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
>>         of_node = panel->dev->of_node;
>> @@ -474,10 +474,17 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>>                 cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
>>         }
>>
>> -       if (cnt > 0)
>> +       if (cnt > 0) {
>> +               struct device_node *endpoint;
>> +
>>                 msm_dp_panel->max_dp_lanes = cnt;
>> -       else
>> +               endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1);
>> +               of_property_read_u32_array(endpoint, "data-lanes", lane_map, cnt);
>> +       } else {
>>                 msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
>> +       }
> 
> Why? This sounds more like dp_catalog or (after the refactoring at
> [1]) dp_ctrl. But not the dp_panel.
> 
> [1] https://patchwork.freedesktop.org/project/freedreno/series/?ordering=-last_updated
> 
We are used the same prop 'data-lanes = <3 2 0 1>' in mdss_dp_out to keep similar behaviour with dsi_host_parse_lane_data.
From the modules used, catalog seems more appropriate, but since the max_dp_lanes is parsed at dp_panel, it has been placed here.
Should lane_map parsing in msm_dp_catalog_get, and keep max_dp_lanes parsing at the dp_panel?
>> +
>> +       memcpy(msm_dp_panel->lane_map, lane_map, msm_dp_panel->max_dp_lanes * sizeof(u32));
>>
>>         msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node);
>>         if (!msm_dp_panel->max_dp_link_rate)
>> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
>> index 0e944db3adf2f187f313664fe80cf540ec7a19f2..7603b92c32902bd3d4485539bd6308537ff75a2c 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
>> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
>> @@ -11,6 +11,8 @@
>>  #include "dp_aux.h"
>>  #include "dp_link.h"
>>
>> +#define DP_MAX_NUM_DP_LANES    4
>> +
>>  struct edid;
>>
>>  struct msm_dp_display_mode {
>> @@ -46,6 +48,7 @@ struct msm_dp_panel {
>>         bool video_test;
>>         bool vsc_sdp_supported;
>>
>> +       u32 lane_map[DP_MAX_NUM_DP_LANES];
>>         u32 max_dp_lanes;
>>         u32 max_dp_link_rate;
>>
>>
>> --
>> 2.25.1
>>
> 
> 


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 6/8] drm/msm/dp: Add maximum width limitation for modes
  2024-11-29 13:52   ` Dmitry Baryshkov
@ 2024-12-02  9:05     ` Xiangxu Yin
  2024-12-02  9:32       ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-12-02  9:05 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 11/29/2024 9:52 PM, Dmitry Baryshkov wrote:
> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>
>> Introduce a maximum width constraint for modes during validation. This
>> ensures that the modes are filtered based on hardware capabilities,
>> specifically addressing the line buffer limitations of individual pipes.
> 
> This doesn't describe, why this is necessary. What does "buffer
> limitations of individual pipes" mean?
> If the platforms have hw capabilities like being unable to support 8k
> or 10k, it should go to platform data
> 
It's SSPP line buffer limitation for this platform and only support to 2160 mode width.
Then, shall I add max_width config to struct msm_dp_desc in next patch? for other platform will set defualt value to ‘DP_MAX_WIDTH 7680'
>>
>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
>> ---
>>  drivers/gpu/drm/msm/dp/dp_display.c |  3 +++
>>  drivers/gpu/drm/msm/dp/dp_display.h |  1 +
>>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 +++++++++++++
>>  drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
>>  4 files changed, 18 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
>> index 4c83402fc7e0d41cb7621fa2efda043269d0a608..eb6fb76c68e505fafbec563440e9784f51e1894b 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_display.c
>> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
>> @@ -944,6 +944,9 @@ enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge,
>>         msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
>>         link_info = &msm_dp_display->panel->link_info;
>>
>> +       if (mode->hdisplay > msm_dp_display->panel->max_dp_width)
>> +               return MODE_BAD;
>> +
>>         if (drm_mode_is_420_only(&dp->connector->display_info, mode) &&
>>             msm_dp_display->panel->vsc_sdp_supported)
>>                 mode_pclk_khz /= 2;
>> diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
>> index ecbc2d92f546a346ee53adcf1b060933e4f54317..7a11f7eeb691976f06afc7aff67650397d7deb90 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_display.h
>> +++ b/drivers/gpu/drm/msm/dp/dp_display.h
>> @@ -11,6 +11,7 @@
>>  #include "disp/msm_disp_snapshot.h"
>>
>>  #define DP_MAX_PIXEL_CLK_KHZ   675000
>> +#define DP_MAX_WIDTH   7680
>>
>>  struct msm_dp {
>>         struct drm_device *drm_dev;
>> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
>> index 8654180aa259234bbd41f4f88c13c485f9791b1d..10501e301c5e073d8d34093b86a15d72e646a01f 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_panel.c
>> +++ b/drivers/gpu/drm/msm/dp/dp_panel.c
>> @@ -4,6 +4,7 @@
>>   */
>>
>>  #include "dp_panel.h"
>> +#include "dp_display.h"
>>  #include "dp_utils.h"
>>
>>  #include <drm/drm_connector.h>
>> @@ -455,6 +456,16 @@ static u32 msm_dp_panel_link_frequencies(struct device_node *of_node)
>>         return frequency;
>>  }
>>
>> +static u32 msm_dp_panel_max_width(struct device_node *of_node)
>> +{
>> +       u32 max_width = 0;
>> +
>> +       if (of_property_read_u32(of_node, "max-width", &max_width))
>> +               max_width = DP_MAX_WIDTH;
>> +
>> +       return max_width;
> 
> msm_dp_panel->max_dp_width = DP_MAX_WIDTH;
> of_property_read_u32(of_node, "max-width", &msm_dp_panel->max_dp_width);
> 
>> +}
>> +
>>  static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>>  {
>>         struct msm_dp_panel_private *panel;
>> @@ -490,6 +501,8 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>>         if (!msm_dp_panel->max_dp_link_rate)
>>                 msm_dp_panel->max_dp_link_rate = DP_LINK_RATE_HBR2;
>>
>> +       msm_dp_panel->max_dp_width = msm_dp_panel_max_width(of_node);
>> +
>>         return 0;
>>  }
>>
>> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
>> index 7603b92c32902bd3d4485539bd6308537ff75a2c..61513644161209c243bbb623ee4ded951b2a0597 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
>> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
>> @@ -51,6 +51,7 @@ struct msm_dp_panel {
>>         u32 lane_map[DP_MAX_NUM_DP_LANES];
>>         u32 max_dp_lanes;
>>         u32 max_dp_link_rate;
>> +       u32 max_dp_width;
>>
>>         u32 max_bw_code;
>>  };
>>
>> --
>> 2.25.1
>>
> 
> 


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 6/8] drm/msm/dp: Add maximum width limitation for modes
  2024-12-02  9:05     ` Xiangxu Yin
@ 2024-12-02  9:32       ` Dmitry Baryshkov
  2024-12-03  7:41         ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-12-02  9:32 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Mon, 2 Dec 2024 at 11:05, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>
>
>
> On 11/29/2024 9:52 PM, Dmitry Baryshkov wrote:
> > On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>
> >> Introduce a maximum width constraint for modes during validation. This
> >> ensures that the modes are filtered based on hardware capabilities,
> >> specifically addressing the line buffer limitations of individual pipes.
> >
> > This doesn't describe, why this is necessary. What does "buffer
> > limitations of individual pipes" mean?
> > If the platforms have hw capabilities like being unable to support 8k
> > or 10k, it should go to platform data
> >
> It's SSPP line buffer limitation for this platform and only support to 2160 mode width.
> Then, shall I add max_width config to struct msm_dp_desc in next patch? for other platform will set defualt value to ‘DP_MAX_WIDTH 7680'

SSPP line buffer limitations are to be handled in the DPU driver. The
DP driver shouldn't care about those.

> >>
> >> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> >> ---
> >>  drivers/gpu/drm/msm/dp/dp_display.c |  3 +++
> >>  drivers/gpu/drm/msm/dp/dp_display.h |  1 +
> >>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 +++++++++++++
> >>  drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
> >>  4 files changed, 18 insertions(+)


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-11-29  8:18   ` Krzysztof Kozlowski
@ 2024-12-02 10:31     ` Xiangxu Yin
  2024-12-02 15:48       ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-12-02 10:31 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Rob Clark, Abhinav Kumar, Dmitry Baryshkov,
	Sean Paul, Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez
  Cc: linux-arm-msm, dri-devel, freedreno, devicetree, linux-kernel,
	linux-phy, linux-gpio



On 11/29/2024 4:18 PM, Krzysztof Kozlowski wrote:
> On 29/11/2024 08:57, Xiangxu Yin wrote:
>> Extended DP support for QCS615 USB or DP phy. Differentiated between
>> USBC and DP PHY using the match table’s type, dynamically generating
>> different types of cfg and layout attributes during initialization based
>> on this type. Static variables are stored in cfg, while parsed values
>> are organized into the layout structure.
>>
>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
>> ---
>>  drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h |    1 +
>>  drivers/phy/qualcomm/phy-qcom-qmp-usbc.c   | 1453 ++++++++++++++++++++++++----
>>  2 files changed, 1254 insertions(+), 200 deletions(-)
> 
> 
> 
> ...
> 
>> +	/* program default setting first */
>> +	writel(0x2A, tx + QSERDES_V3_TX_TX_DRV_LVL);
>> +	writel(0x20, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
>> +	writel(0x2A, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
>> +	writel(0x20, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
>> +
>> +	writel(voltage_swing_cfg, tx + QSERDES_V3_TX_TX_DRV_LVL);
>> +	writel(pre_emphasis_cfg, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
>> +	writel(voltage_swing_cfg, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
>> +	writel(pre_emphasis_cfg, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
>> +
>> +	return 0;
>> +}
>> +
>> +static int qcs615_qmp_configure_dp_phy(struct qmp_usbc *qmp)
>> +{
>> +	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +	u32 status;
>> +
>> +	writel(0x01, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +	writel(0x05, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +	writel(0x01, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +	writel(0x09, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +
>> +	writel(0x20, layout->dp_serdes + QSERDES_COM_RESETSM_CNTRL);
>> +
>> +	// C_READY
> 
> Use Linux coding style.
> 
> Anyway, drop all useless comments. Say something useful or don't say
> anything.
> 
Ok, will update in next seperated patches.
>> +	if (readl_poll_timeout(layout->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;
>> +	}
>> +
>> +	// FREQ_DONE
>> +	if (readl_poll_timeout(layout->dp_serdes + QSERDES_COM_CMN_STATUS,
>> +			status,
>> +			((status & BIT(0)) > 0),
>> +			500,
>> +			10000)){
>> +		dev_err(qmp->dev, "FREQ_DONE not ready\n");
>> +		return -ETIMEDOUT;
>> +	}
>> +
>> +	// PLL_LOCKED
>> +	if (readl_poll_timeout(layout->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, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +	udelay(10);
>> +
>> +	// TSYNC_DONE
>> +	if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS,
>> +			status,
>> +			((status & BIT(0)) > 0),
>> +			500,
>> +			10000)){
>> +		dev_err(qmp->dev, "TSYNC_DONE not ready\n");
>> +		return -ETIMEDOUT;
>> +	}
>> +
>> +	// PHY_READY
>> +	if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS,
>> +			status,
>> +			((status & BIT(1)) > 0),
>> +			500,
>> +			10000)){
>> +		dev_err(qmp->dev, "PHY_READY not ready\n");
>> +		return -ETIMEDOUT;
>> +	}
>> +
>> +	writel(0x3f, layout->dp_tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
>> +	writel(0x10, layout->dp_tx + QSERDES_V3_TX_HIGHZ_DRVR_EN);
>> +	writel(0x0a, layout->dp_tx + QSERDES_V3_TX_TX_POL_INV);
>> +	writel(0x3f, layout->dp_tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
>> +	writel(0x10, layout->dp_tx2 + QSERDES_V3_TX_HIGHZ_DRVR_EN);
>> +	writel(0x0a, layout->dp_tx2 + QSERDES_V3_TX_TX_POL_INV);
>> +
>> +	writel(0x18, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +	writel(0x19, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +
>> +	if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_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 qcs615_qmp_calibrate_dp_phy(struct qmp_usbc *qmp)
>> +{
>> +	static const u8 cfg1_settings[] = {0x13, 0x23, 0x1d};
>> +	struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +	u8 val;
>> +
>> +	layout->dp_aux_cfg++;
>> +	layout->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
>> +	val = cfg1_settings[layout->dp_aux_cfg];
>> +
>> +	writel(val, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG1);
>> +
>> +	qmp_usbc_check_dp_phy(qmp, "pos_calibrate");
>> +
>> +	return 0;
>> +}
>> +
>> +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;
>> +	int num_vregs;
>>  	u32 val = 0;
>>  	int ret;
>> +	unsigned int reg_pwr_dn;
>>  
>> -	ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
>> +	if (qmp->type == QMP_PHY_USBC_USB) {
> 
> 
> Sorry, all this code is unreviewable. Organize your changes in logical,
> reviewable chunks.
> 
Will create new patch list and seperate patchsets.
>> +		struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
>> +
>> +		num_vregs = cfg->num_vregs;
>> +		reg_pwr_dn = cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL];
>> +	} else {
> 
> ...
> 
>> +		.compatible = "qcom,qcs615-qmp-dp-phy",
>> +		.data =  &(struct dev_cfg) {
>> +			.type = QMP_PHY_USBC_DP,
>> +			.cfg = &qcs615_dpphy_cfg,
>> +		},
>>  	}, {
>>  		.compatible = "qcom,sdm660-qmp-usb3-phy",
>> -		.data = &sdm660_usb3phy_cfg,
>> +		.data =  &(struct dev_cfg) {
>> +			.type = QMP_PHY_USBC_USB,
>> +			.cfg = &sdm660_usb3phy_cfg,
>> +		},
>>  	}, {
>>  		.compatible = "qcom,sm6115-qmp-usb3-phy",
>> -		.data = &qcm2290_usb3phy_cfg,
>> +		.data =  &(struct dev_cfg) {
>> +			.type = QMP_PHY_USBC_USB,
>> +			.cfg = &qcm2290_usb3phy_cfg,
>> +		},
>>  	},
>>  	{ },
>>  };
>> +
> 
> 
> You make some random changes all over this file. No, clean it up.
> 
>>  MODULE_DEVICE_TABLE(of, qmp_usbc_of_match_table);
>>  
>>  static struct platform_driver qmp_usbc_driver = {
>>
> 
> 
> Best regards,
> Krzysztof


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration
  2024-12-02  8:40     ` Xiangxu Yin
@ 2024-12-02 10:46       ` Dmitry Baryshkov
  2024-12-05 11:28         ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-12-02 10:46 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Mon, Dec 02, 2024 at 04:40:05PM +0800, Xiangxu Yin wrote:
> 
> 
> On 11/29/2024 9:50 PM, Dmitry Baryshkov wrote:
> > On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>
> >> Add the ability to configure lane mapping for the DP controller. This is
> >> required when the platform's lane mapping does not follow the default
> >> order (0, 1, 2, 3). The mapping rules are now configurable via the
> >> `data-lane` property in the devicetree. This property defines the
> >> logical-to-physical lane mapping sequence, ensuring correct lane
> >> assignment for non-default configurations.
> >>
> >> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> >> ---
> >>  drivers/gpu/drm/msm/dp/dp_catalog.c | 11 +++++------
> >>  drivers/gpu/drm/msm/dp/dp_catalog.h |  2 +-
> >>  drivers/gpu/drm/msm/dp/dp_ctrl.c    |  2 +-
> >>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 ++++++++++---
> >>  drivers/gpu/drm/msm/dp/dp_panel.h   |  3 +++
> >>  5 files changed, 20 insertions(+), 11 deletions(-)
> >>

> >> @@ -461,6 +460,7 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
> >>         struct msm_dp_panel_private *panel;
> >>         struct device_node *of_node;
> >>         int cnt;
> >> +       u32 lane_map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3};
> >>
> >>         panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
> >>         of_node = panel->dev->of_node;
> >> @@ -474,10 +474,17 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
> >>                 cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
> >>         }
> >>
> >> -       if (cnt > 0)
> >> +       if (cnt > 0) {
> >> +               struct device_node *endpoint;
> >> +
> >>                 msm_dp_panel->max_dp_lanes = cnt;
> >> -       else
> >> +               endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1);
> >> +               of_property_read_u32_array(endpoint, "data-lanes", lane_map, cnt);
> >> +       } else {
> >>                 msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
> >> +       }
> > 
> > Why? This sounds more like dp_catalog or (after the refactoring at
> > [1]) dp_ctrl. But not the dp_panel.
> > 
> > [1] https://patchwork.freedesktop.org/project/freedreno/series/?ordering=-last_updated
> > 
> We are used the same prop 'data-lanes = <3 2 0 1>' in mdss_dp_out to keep similar behaviour with dsi_host_parse_lane_data.
> From the modules used, catalog seems more appropriate, but since the max_dp_lanes is parsed at dp_panel, it has been placed here.
> Should lane_map parsing in msm_dp_catalog_get, and keep max_dp_lanes parsing at the dp_panel?

msm_dp_catalog_get() is going to be removed. Since the functions that
are going to use it are in dp_ctrl module, I thought that dp_ctrl.c is
the best place. A better option might be to move max_dp_lanes and
max_dp_link_rate to dp_link.c as those are link params. Then
lane_mapping also logically becomes a part of dp_link module.

But now I have a more important question (triggered by Krishna's email
about SAR2130P's USB): if the lanes are swapped, does USB 3 work on that
platform? Or is it being demoted to USB 2 with nobody noticing that?

If lanes 0/1 and 2/3 are swapped, shouldn't it be handled in the QMP
PHY, where we handle lanes and orientation switching?

> >> +
> >> +       memcpy(msm_dp_panel->lane_map, lane_map, msm_dp_panel->max_dp_lanes * sizeof(u32));
> >>
> >>         msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node);
> >>         if (!msm_dp_panel->max_dp_link_rate)
> >> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
> >> index 0e944db3adf2f187f313664fe80cf540ec7a19f2..7603b92c32902bd3d4485539bd6308537ff75a2c 100644
> >> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
> >> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
> >> @@ -11,6 +11,8 @@
> >>  #include "dp_aux.h"
> >>  #include "dp_link.h"
> >>
> >> +#define DP_MAX_NUM_DP_LANES    4
> >> +
> >>  struct edid;
> >>
> >>  struct msm_dp_display_mode {
> >> @@ -46,6 +48,7 @@ struct msm_dp_panel {
> >>         bool video_test;
> >>         bool vsc_sdp_supported;
> >>
> >> +       u32 lane_map[DP_MAX_NUM_DP_LANES];
> >>         u32 max_dp_lanes;
> >>         u32 max_dp_link_rate;
> >>
> >>
> >> --
> >> 2.25.1
> >>
> > 
> > 
> 
> 
> -- 
> linux-phy mailing list
> linux-phy@lists.infradead.org
> https://lists.infradead.org/mailman/listinfo/linux-phy

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-12-02 10:31     ` Xiangxu Yin
@ 2024-12-02 15:48       ` Dmitry Baryshkov
  0 siblings, 0 replies; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-12-02 15:48 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Krzysztof Kozlowski, Rob Clark, Abhinav Kumar, Sean Paul,
	Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, linux-phy, linux-gpio

On Mon, Dec 02, 2024 at 06:31:44PM +0800, Xiangxu Yin wrote:
> 
> 
> On 11/29/2024 4:18 PM, Krzysztof Kozlowski wrote:
> > On 29/11/2024 08:57, Xiangxu Yin wrote:
> >> +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;
> >> +	int num_vregs;
> >>  	u32 val = 0;
> >>  	int ret;
> >> +	unsigned int reg_pwr_dn;
> >>  
> >> -	ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
> >> +	if (qmp->type == QMP_PHY_USBC_USB) {
> > 
> > 
> > Sorry, all this code is unreviewable. Organize your changes in logical,
> > reviewable chunks.
> > 
> Will create new patch list and seperate patchsets.

Please respond to the comment regarding the single PHY vs multiple PHYs
first.

> >> +		struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> >> +
> >> +		num_vregs = cfg->num_vregs;
> >> +		reg_pwr_dn = cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL];
> >> +	} else {
> > 

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 6/8] drm/msm/dp: Add maximum width limitation for modes
  2024-12-02  9:32       ` Dmitry Baryshkov
@ 2024-12-03  7:41         ` Xiangxu Yin
  2024-12-03 13:58           ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-12-03  7:41 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 12/2/2024 5:32 PM, Dmitry Baryshkov wrote:
> On Mon, 2 Dec 2024 at 11:05, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>
>>
>>
>> On 11/29/2024 9:52 PM, Dmitry Baryshkov wrote:
>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>
>>>> Introduce a maximum width constraint for modes during validation. This
>>>> ensures that the modes are filtered based on hardware capabilities,
>>>> specifically addressing the line buffer limitations of individual pipes.
>>>
>>> This doesn't describe, why this is necessary. What does "buffer
>>> limitations of individual pipes" mean?
>>> If the platforms have hw capabilities like being unable to support 8k
>>> or 10k, it should go to platform data
>>>
>> It's SSPP line buffer limitation for this platform and only support to 2160 mode width.
>> Then, shall I add max_width config to struct msm_dp_desc in next patch? for other platform will set defualt value to ‘DP_MAX_WIDTH 7680'
> 
> SSPP line buffer limitations are to be handled in the DPU driver. The
> DP driver shouldn't care about those.
> 
Ok, Will drop this part in next patch.
>>>>
>>>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
>>>> ---
>>>>  drivers/gpu/drm/msm/dp/dp_display.c |  3 +++
>>>>  drivers/gpu/drm/msm/dp/dp_display.h |  1 +
>>>>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 +++++++++++++
>>>>  drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
>>>>  4 files changed, 18 insertions(+)
> 
> 


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 7/8] drm/msm/dp: Retry Link Training 2 with lower pattern
  2024-11-29 13:53   ` Dmitry Baryshkov
@ 2024-12-03  8:13     ` Xiangxu Yin
  2024-12-03 14:07       ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-12-03  8:13 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 11/29/2024 9:53 PM, Dmitry Baryshkov wrote:
> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>
>> Add a mechanism to retry Link Training 2 by lowering the pattern level
>> when the link training #2 first attempt fails. This approach enhances
>> compatibility, particularly addressing issues caused by certain hub
>> configurations.
> 
> Please reference corresponding part of the standard, describing this lowering.
> 
Per DisplayPort 1.4a specification Section 3.5.1.2 and Table 3-10, while the standard doesn't explicitly define a TPS downgrade mechanism, it does specify:
- All devices shall support TPS1 and TPS2
- HDR2-capable devices shall support TPS3
- HDR3-capable devices shall support TPS4
While these capabilities are explicitly defined DPCD for sink devices, source device capabilities are less strictly defined, with the minimum requirement being support for TPS1 and TPS2.
In QCS615 DP phy is only supporting to HBR2, we observed a critical interoperability scenario with a DP->HDMI bridge. When link training at TPS4 consistently failed, downgrading to the next lower training pattern successfully established the link and display output successfully.

This experience suggests that implementing a flexible link training pattern downgrade mechanism can significantly improve compatibility with third-party, non-standard hubs and displays,
especially in scenarios where strict adherence to the highest training pattern might prevent successful connection.
>>
>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
>> ---
>>  drivers/gpu/drm/msm/dp/dp_ctrl.c | 34 ++++++++++++++++++++++++++++++----
>>  1 file changed, 30 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
>> index 49c8ce9b2d0e57a613e50865be3fe98e814d425a..b1862294cb98c9f756b0108b7670cb42de37bae4 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
>> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
>> @@ -1220,7 +1220,7 @@ static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl)
>>  }
>>
>>  static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
>> -                       int *training_step)
>> +                       int *training_step, bool downgrade)
>>  {
>>         int tries = 0, ret = 0;
>>         u8 pattern;
>> @@ -1243,6 +1243,28 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
>>                 state_ctrl_bit = 2;
>>         }
>>
>> +       /*
>> +        * DP link training uses the highest allowed pattern by default.
>> +        * If it fails, the pattern is downgraded to improve cable and monitor compatibility.
>> +        */
>> +       if (downgrade) {
>> +               switch (pattern) {
>> +               case DP_TRAINING_PATTERN_4:
>> +                       pattern = DP_TRAINING_PATTERN_3;
>> +                       state_ctrl_bit = 3;
>> +                       break;
>> +               case DP_TRAINING_PATTERN_3:
>> +                       pattern = DP_TRAINING_PATTERN_2;
>> +                       state_ctrl_bit = 2;
>> +                       break;
>> +               default:
>> +                       break;
>> +               }
>> +       }
>> +
>> +       drm_dbg_dp(ctrl->drm_dev, "pattern(%d) state_ctrl_bit(%d) downgrade(%d)\n",
>> +               pattern, state_ctrl_bit, downgrade);
>> +
>>         ret = msm_dp_catalog_ctrl_set_pattern_state_bit(ctrl->catalog, state_ctrl_bit);
>>         if (ret)
>>                 return ret;
>> @@ -1311,10 +1333,14 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
>>         /* print success info as this is a result of user initiated action */
>>         drm_dbg_dp(ctrl->drm_dev, "link training #1 successful\n");
>>
>> -       ret = msm_dp_ctrl_link_train_2(ctrl, training_step);
>> +       ret = msm_dp_ctrl_link_train_2(ctrl, training_step, false);
>>         if (ret) {
>> -               DRM_ERROR("link training #2 failed. ret=%d\n", ret);
>> -               goto end;
>> +               drm_dbg_dp(ctrl->drm_dev, "link training #2 failed, retry downgrade.\n");
>> +               ret = msm_dp_ctrl_link_train_2(ctrl, training_step, true);
>> +               if (ret) {
>> +                       DRM_ERROR("link training #2 failed. ret=%d\n", ret);
>> +                       goto end;
>> +               }
>>         }
>>
>>         /* print success info as this is a result of user initiated action */
>>
>> --
>> 2.25.1
>>
> 
> 


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 6/8] drm/msm/dp: Add maximum width limitation for modes
  2024-12-03  7:41         ` Xiangxu Yin
@ 2024-12-03 13:58           ` Dmitry Baryshkov
  2024-12-06 20:13             ` Abhinav Kumar
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-12-03 13:58 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Tue, Dec 03, 2024 at 03:41:53PM +0800, Xiangxu Yin wrote:
> 
> 
> On 12/2/2024 5:32 PM, Dmitry Baryshkov wrote:
> > On Mon, 2 Dec 2024 at 11:05, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>
> >>
> >>
> >> On 11/29/2024 9:52 PM, Dmitry Baryshkov wrote:
> >>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>
> >>>> Introduce a maximum width constraint for modes during validation. This
> >>>> ensures that the modes are filtered based on hardware capabilities,
> >>>> specifically addressing the line buffer limitations of individual pipes.
> >>>
> >>> This doesn't describe, why this is necessary. What does "buffer
> >>> limitations of individual pipes" mean?
> >>> If the platforms have hw capabilities like being unable to support 8k
> >>> or 10k, it should go to platform data
> >>>
> >> It's SSPP line buffer limitation for this platform and only support to 2160 mode width.
> >> Then, shall I add max_width config to struct msm_dp_desc in next patch? for other platform will set defualt value to ‘DP_MAX_WIDTH 7680'
> > 
> > SSPP line buffer limitations are to be handled in the DPU driver. The
> > DP driver shouldn't care about those.
> > 
> Ok, Will drop this part in next patch.

If you drop it, what will be left from the patch itself?

> >>>>
> >>>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> >>>> ---
> >>>>  drivers/gpu/drm/msm/dp/dp_display.c |  3 +++
> >>>>  drivers/gpu/drm/msm/dp/dp_display.h |  1 +
> >>>>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 +++++++++++++
> >>>>  drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
> >>>>  4 files changed, 18 insertions(+)
> > 
> > 
> 

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 7/8] drm/msm/dp: Retry Link Training 2 with lower pattern
  2024-12-03  8:13     ` Xiangxu Yin
@ 2024-12-03 14:07       ` Dmitry Baryshkov
  2025-05-27 20:49         ` Konrad Dybcio
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-12-03 14:07 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Tue, Dec 03, 2024 at 04:13:22PM +0800, Xiangxu Yin wrote:
> 
> 
> On 11/29/2024 9:53 PM, Dmitry Baryshkov wrote:
> > On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>
> >> Add a mechanism to retry Link Training 2 by lowering the pattern level
> >> when the link training #2 first attempt fails. This approach enhances
> >> compatibility, particularly addressing issues caused by certain hub
> >> configurations.
> > 
> > Please reference corresponding part of the standard, describing this lowering.
> > 
> Per DisplayPort 1.4a specification Section 3.5.1.2 and Table 3-10, while the standard doesn't explicitly define a TPS downgrade mechanism, it does specify:

Anything in DP 2.1?

> - All devices shall support TPS1 and TPS2
> - HDR2-capable devices shall support TPS3
> - HDR3-capable devices shall support TPS4
> While these capabilities are explicitly defined DPCD for sink devices, source device capabilities are less strictly defined, with the minimum requirement being support for TPS1 and TPS2.
> In QCS615 DP phy is only supporting to HBR2, we observed a critical interoperability scenario with a DP->HDMI bridge. When link training at TPS4 consistently failed, downgrading to the next lower training pattern successfully established the link and display output successfully.

Any other driver doing such TPS lowering? Or maybe we should be
selecting TPS3 for HBR2-only devices?

> 
> This experience suggests that implementing a flexible link training pattern downgrade mechanism can significantly improve compatibility with third-party, non-standard hubs and displays,
> especially in scenarios where strict adherence to the highest training pattern might prevent successful connection.
> >>
> >> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> >> ---
> >>  drivers/gpu/drm/msm/dp/dp_ctrl.c | 34 ++++++++++++++++++++++++++++++----
> >>  1 file changed, 30 insertions(+), 4 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> >> index 49c8ce9b2d0e57a613e50865be3fe98e814d425a..b1862294cb98c9f756b0108b7670cb42de37bae4 100644
> >> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
> >> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> >> @@ -1220,7 +1220,7 @@ static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl)
> >>  }
> >>
> >>  static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
> >> -                       int *training_step)
> >> +                       int *training_step, bool downgrade)
> >>  {
> >>         int tries = 0, ret = 0;
> >>         u8 pattern;
> >> @@ -1243,6 +1243,28 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
> >>                 state_ctrl_bit = 2;
> >>         }
> >>
> >> +       /*
> >> +        * DP link training uses the highest allowed pattern by default.
> >> +        * If it fails, the pattern is downgraded to improve cable and monitor compatibility.
> >> +        */
> >> +       if (downgrade) {
> >> +               switch (pattern) {
> >> +               case DP_TRAINING_PATTERN_4:
> >> +                       pattern = DP_TRAINING_PATTERN_3;
> >> +                       state_ctrl_bit = 3;
> >> +                       break;
> >> +               case DP_TRAINING_PATTERN_3:
> >> +                       pattern = DP_TRAINING_PATTERN_2;
> >> +                       state_ctrl_bit = 2;
> >> +                       break;
> >> +               default:
> >> +                       break;
> >> +               }
> >> +       }
> >> +
> >> +       drm_dbg_dp(ctrl->drm_dev, "pattern(%d) state_ctrl_bit(%d) downgrade(%d)\n",
> >> +               pattern, state_ctrl_bit, downgrade);
> >> +
> >>         ret = msm_dp_catalog_ctrl_set_pattern_state_bit(ctrl->catalog, state_ctrl_bit);
> >>         if (ret)
> >>                 return ret;
> >> @@ -1311,10 +1333,14 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
> >>         /* print success info as this is a result of user initiated action */
> >>         drm_dbg_dp(ctrl->drm_dev, "link training #1 successful\n");
> >>
> >> -       ret = msm_dp_ctrl_link_train_2(ctrl, training_step);
> >> +       ret = msm_dp_ctrl_link_train_2(ctrl, training_step, false);
> >>         if (ret) {
> >> -               DRM_ERROR("link training #2 failed. ret=%d\n", ret);
> >> -               goto end;
> >> +               drm_dbg_dp(ctrl->drm_dev, "link training #2 failed, retry downgrade.\n");
> >> +               ret = msm_dp_ctrl_link_train_2(ctrl, training_step, true);
> >> +               if (ret) {
> >> +                       DRM_ERROR("link training #2 failed. ret=%d\n", ret);
> >> +                       goto end;
> >> +               }
> >>         }
> >>
> >>         /* print success info as this is a result of user initiated action */
> >>
> >> --
> >> 2.25.1
> >>
> > 
> > 
> 
> 
> -- 
> linux-phy mailing list
> linux-phy@lists.infradead.org
> https://lists.infradead.org/mailman/listinfo/linux-phy

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration
  2024-12-02 10:46       ` Dmitry Baryshkov
@ 2024-12-05 11:28         ` Xiangxu Yin
  2024-12-05 11:40           ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-12-05 11:28 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 12/2/2024 6:46 PM, Dmitry Baryshkov wrote:
> On Mon, Dec 02, 2024 at 04:40:05PM +0800, Xiangxu Yin wrote:
>>
>>
>> On 11/29/2024 9:50 PM, Dmitry Baryshkov wrote:
>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>
>>>> Add the ability to configure lane mapping for the DP controller. This is
>>>> required when the platform's lane mapping does not follow the default
>>>> order (0, 1, 2, 3). The mapping rules are now configurable via the
>>>> `data-lane` property in the devicetree. This property defines the
>>>> logical-to-physical lane mapping sequence, ensuring correct lane
>>>> assignment for non-default configurations.
>>>>
>>>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
>>>> ---
>>>>  drivers/gpu/drm/msm/dp/dp_catalog.c | 11 +++++------
>>>>  drivers/gpu/drm/msm/dp/dp_catalog.h |  2 +-
>>>>  drivers/gpu/drm/msm/dp/dp_ctrl.c    |  2 +-
>>>>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 ++++++++++---
>>>>  drivers/gpu/drm/msm/dp/dp_panel.h   |  3 +++
>>>>  5 files changed, 20 insertions(+), 11 deletions(-)
>>>>
> 
>>>> @@ -461,6 +460,7 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>>>>         struct msm_dp_panel_private *panel;
>>>>         struct device_node *of_node;
>>>>         int cnt;
>>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3};
>>>>
>>>>         panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
>>>>         of_node = panel->dev->of_node;
>>>> @@ -474,10 +474,17 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>>>>                 cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
>>>>         }
>>>>
>>>> -       if (cnt > 0)
>>>> +       if (cnt > 0) {
>>>> +               struct device_node *endpoint;
>>>> +
>>>>                 msm_dp_panel->max_dp_lanes = cnt;
>>>> -       else
>>>> +               endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1);
>>>> +               of_property_read_u32_array(endpoint, "data-lanes", lane_map, cnt);
>>>> +       } else {
>>>>                 msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
>>>> +       }
>>>
>>> Why? This sounds more like dp_catalog or (after the refactoring at
>>> [1]) dp_ctrl. But not the dp_panel.
>>>
>>> [1] https://patchwork.freedesktop.org/project/freedreno/series/?ordering=-last_updated
>>>
>> We are used the same prop 'data-lanes = <3 2 0 1>' in mdss_dp_out to keep similar behaviour with dsi_host_parse_lane_data.
>> From the modules used, catalog seems more appropriate, but since the max_dp_lanes is parsed at dp_panel, it has been placed here.
>> Should lane_map parsing in msm_dp_catalog_get, and keep max_dp_lanes parsing at the dp_panel?
> 
> msm_dp_catalog_get() is going to be removed. Since the functions that
> are going to use it are in dp_ctrl module, I thought that dp_ctrl.c is
> the best place. A better option might be to move max_dp_lanes and
> max_dp_link_rate to dp_link.c as those are link params. Then
> lane_mapping also logically becomes a part of dp_link module.
> 
> But now I have a more important question (triggered by Krishna's email
> about SAR2130P's USB): if the lanes are swapped, does USB 3 work on that
> platform? Or is it being demoted to USB 2 with nobody noticing that?
> 
> If lanes 0/1 and 2/3 are swapped, shouldn't it be handled in the QMP
> PHY, where we handle lanes and orientation switching?
> 
I have checked the DP hardware programming guide and also discussed it with Krishna.

According to the HPG section '3.4.2 PN and Lane Swap: PHY supports PN swap for mainlink and AUX, but it doesn't support lane swap feature.' 

The lane swap mainly refers to the logical to physical mapping between the DP controller and the DP PHY. The PHY handles polarity inversion, and the lane map does not affect USB behavior.

On the QCS615 platform, we have also tested when DP works with lane swap, other USB 3.0 ports can works normally at super speed.

Additionally, if it were placed on the PHY side, the PHY would need access to dp_link’s domain which can access REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING.
Therefore, we believe that the  max_dp_link_rate,max_dp_lanes and lane_map move to dp_link side is better.

>>>> +
>>>> +       memcpy(msm_dp_panel->lane_map, lane_map, msm_dp_panel->max_dp_lanes * sizeof(u32));
>>>>
>>>>         msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node);
>>>>         if (!msm_dp_panel->max_dp_link_rate)
>>>> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
>>>> index 0e944db3adf2f187f313664fe80cf540ec7a19f2..7603b92c32902bd3d4485539bd6308537ff75a2c 100644
>>>> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
>>>> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
>>>> @@ -11,6 +11,8 @@
>>>>  #include "dp_aux.h"
>>>>  #include "dp_link.h"
>>>>
>>>> +#define DP_MAX_NUM_DP_LANES    4
>>>> +
>>>>  struct edid;
>>>>
>>>>  struct msm_dp_display_mode {
>>>> @@ -46,6 +48,7 @@ struct msm_dp_panel {
>>>>         bool video_test;
>>>>         bool vsc_sdp_supported;
>>>>
>>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES];
>>>>         u32 max_dp_lanes;
>>>>         u32 max_dp_link_rate;
>>>>
>>>>
>>>> --
>>>> 2.25.1
>>>>
>>>
>>>
>>
>>
>> -- 
>> linux-phy mailing list
>> linux-phy@lists.infradead.org
>> https://lists.infradead.org/mailman/listinfo/linux-phy
> 


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration
  2024-12-05 11:28         ` Xiangxu Yin
@ 2024-12-05 11:40           ` Dmitry Baryshkov
  2024-12-19 10:36             ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-12-05 11:40 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Thu, 5 Dec 2024 at 13:28, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>
>
>
> On 12/2/2024 6:46 PM, Dmitry Baryshkov wrote:
> > On Mon, Dec 02, 2024 at 04:40:05PM +0800, Xiangxu Yin wrote:
> >>
> >>
> >> On 11/29/2024 9:50 PM, Dmitry Baryshkov wrote:
> >>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>
> >>>> Add the ability to configure lane mapping for the DP controller. This is
> >>>> required when the platform's lane mapping does not follow the default
> >>>> order (0, 1, 2, 3). The mapping rules are now configurable via the
> >>>> `data-lane` property in the devicetree. This property defines the
> >>>> logical-to-physical lane mapping sequence, ensuring correct lane
> >>>> assignment for non-default configurations.
> >>>>
> >>>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> >>>> ---
> >>>>  drivers/gpu/drm/msm/dp/dp_catalog.c | 11 +++++------
> >>>>  drivers/gpu/drm/msm/dp/dp_catalog.h |  2 +-
> >>>>  drivers/gpu/drm/msm/dp/dp_ctrl.c    |  2 +-
> >>>>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 ++++++++++---
> >>>>  drivers/gpu/drm/msm/dp/dp_panel.h   |  3 +++
> >>>>  5 files changed, 20 insertions(+), 11 deletions(-)
> >>>>
> >
> >>>> @@ -461,6 +460,7 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
> >>>>         struct msm_dp_panel_private *panel;
> >>>>         struct device_node *of_node;
> >>>>         int cnt;
> >>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3};
> >>>>
> >>>>         panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
> >>>>         of_node = panel->dev->of_node;
> >>>> @@ -474,10 +474,17 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
> >>>>                 cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
> >>>>         }
> >>>>
> >>>> -       if (cnt > 0)
> >>>> +       if (cnt > 0) {
> >>>> +               struct device_node *endpoint;
> >>>> +
> >>>>                 msm_dp_panel->max_dp_lanes = cnt;
> >>>> -       else
> >>>> +               endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1);
> >>>> +               of_property_read_u32_array(endpoint, "data-lanes", lane_map, cnt);
> >>>> +       } else {
> >>>>                 msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
> >>>> +       }
> >>>
> >>> Why? This sounds more like dp_catalog or (after the refactoring at
> >>> [1]) dp_ctrl. But not the dp_panel.
> >>>
> >>> [1] https://patchwork.freedesktop.org/project/freedreno/series/?ordering=-last_updated
> >>>
> >> We are used the same prop 'data-lanes = <3 2 0 1>' in mdss_dp_out to keep similar behaviour with dsi_host_parse_lane_data.
> >> From the modules used, catalog seems more appropriate, but since the max_dp_lanes is parsed at dp_panel, it has been placed here.
> >> Should lane_map parsing in msm_dp_catalog_get, and keep max_dp_lanes parsing at the dp_panel?
> >
> > msm_dp_catalog_get() is going to be removed. Since the functions that
> > are going to use it are in dp_ctrl module, I thought that dp_ctrl.c is
> > the best place. A better option might be to move max_dp_lanes and
> > max_dp_link_rate to dp_link.c as those are link params. Then
> > lane_mapping also logically becomes a part of dp_link module.
> >
> > But now I have a more important question (triggered by Krishna's email
> > about SAR2130P's USB): if the lanes are swapped, does USB 3 work on that
> > platform? Or is it being demoted to USB 2 with nobody noticing that?
> >
> > If lanes 0/1 and 2/3 are swapped, shouldn't it be handled in the QMP
> > PHY, where we handle lanes and orientation switching?
> >
> I have checked the DP hardware programming guide and also discussed it with Krishna.
>
> According to the HPG section '3.4.2 PN and Lane Swap: PHY supports PN swap for mainlink and AUX, but it doesn't support lane swap feature.'
>
> The lane swap mainly refers to the logical to physical mapping between the DP controller and the DP PHY. The PHY handles polarity inversion, and the lane map does not affect USB behavior.
>
> On the QCS615 platform, we have also tested when DP works with lane swap, other USB 3.0 ports can works normally at super speed.

"Other USB 3.0 ports"? What does that mean? Please correct me if I'm
wrong, you should have a USB+DP combo port that is being managed with
combo PHY. Does USB 3 work on that port?

In other words, where the order of lanes is actually inverted? Between
DP and combo PHY? Within combo PHY? Between the PHY and the pinout?
Granted that SM6150 was supported in msm-4.14 could you possibly point
out a corresponding commit or a set of commits from that kernel?

>
> Additionally, if it were placed on the PHY side, the PHY would need access to dp_link’s domain which can access REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING.

I was thinking about inverting the SW_PORTSEL_VAL bit.

> Therefore, we believe that the  max_dp_link_rate,max_dp_lanes and lane_map move to dp_link side is better.
>
> >>>> +
> >>>> +       memcpy(msm_dp_panel->lane_map, lane_map, msm_dp_panel->max_dp_lanes * sizeof(u32));
> >>>>
> >>>>         msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node);
> >>>>         if (!msm_dp_panel->max_dp_link_rate)
> >>>> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
> >>>> index 0e944db3adf2f187f313664fe80cf540ec7a19f2..7603b92c32902bd3d4485539bd6308537ff75a2c 100644
> >>>> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
> >>>> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
> >>>> @@ -11,6 +11,8 @@
> >>>>  #include "dp_aux.h"
> >>>>  #include "dp_link.h"
> >>>>
> >>>> +#define DP_MAX_NUM_DP_LANES    4
> >>>> +
> >>>>  struct edid;
> >>>>
> >>>>  struct msm_dp_display_mode {
> >>>> @@ -46,6 +48,7 @@ struct msm_dp_panel {
> >>>>         bool video_test;
> >>>>         bool vsc_sdp_supported;
> >>>>
> >>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES];
> >>>>         u32 max_dp_lanes;
> >>>>         u32 max_dp_link_rate;
> >>>>
> >>>>
> >>>> --
> >>>> 2.25.1
> >>>>
> >>>
> >>>
> >>
> >>
> >> --
> >> linux-phy mailing list
> >> linux-phy@lists.infradead.org
> >> https://lists.infradead.org/mailman/listinfo/linux-phy
> >
>


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-11-29 14:33   ` Dmitry Baryshkov
@ 2024-12-05 13:26     ` Xiangxu Yin
  2024-12-05 18:31       ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-12-05 13:26 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>
>> Extended DP support for QCS615 USB or DP phy. Differentiated between
>> USBC and DP PHY using the match table’s type, dynamically generating
>> different types of cfg and layout attributes during initialization based
>> on this type. Static variables are stored in cfg, while parsed values
>> are organized into the layout structure.
> 
> We didn't have an understanding / conclusion whether
> qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
> or two PHYs being placed next to each other. Could you please start
> your commit message by explaining it? Or even better, make that a part
> of the cover letter for a new series touching just the USBC PHY
> driver. DP changes don't have anything in common with the PHY changes,
> so you can split the series into two.
> 
Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.

We identified that DP and USB share some common controls for phy_mode and orientation.
Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
It would be more efficient for a single driver to manage these controls. 

Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
we still decided to base it on the USBC extension.
>>
>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
>> ---
>>  drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h |    1 +
>>  drivers/phy/qualcomm/phy-qcom-qmp-usbc.c   | 1453 ++++++++++++++++++++++++----
> 
> Too many changes for a single patch. Please split into logical chunks.
> 
Ok.
Once we have clarified the overall direction, 
we can then discuss whether to split on current list or create a new list for the split.
>>  2 files changed, 1254 insertions(+), 200 deletions(-)
>>
>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h
>> index 0ebd405bcaf0cac8215550bfc9b226f30cc43a59..59885616405f878885d0837838a0bac1899fb69f 100644
>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h
>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h
>> @@ -25,6 +25,7 @@
>>  #define QSERDES_DP_PHY_AUX_CFG7                                0x03c
>>  #define QSERDES_DP_PHY_AUX_CFG8                                0x040
>>  #define QSERDES_DP_PHY_AUX_CFG9                                0x044
>> +#define QSERDES_DP_PHY_VCO_DIV                         0x068
>>
>>  /* QSERDES COM_BIAS_EN_CLKBUFLR_EN bits */
>>  # define QSERDES_V3_COM_BIAS_EN                                0x0001
>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
>> index cf12a6f12134dc77ff032f967b2efa43e3de4b21..7fece9d7dc959ed5a7c62077d8552324c3734859 100644
>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
>> @@ -22,13 +22,20 @@
>>  #include <linux/slab.h>
>>  #include <linux/usb/typec.h>
>>  #include <linux/usb/typec_mux.h>
>> +#include <dt-bindings/phy/phy-qcom-qmp.h>
>> +#include <drm/bridge/aux-bridge.h>
>>
>>  #include "phy-qcom-qmp-common.h"
>>
>>  #include "phy-qcom-qmp.h"
>>  #include "phy-qcom-qmp-pcs-misc-v3.h"
>>
>> +#include "phy-qcom-qmp-dp-phy.h"
>> +#include "phy-qcom-qmp-dp-phy-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 {
>> @@ -284,7 +291,26 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = {
>>         QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88),
>>  };
>>
>> -struct qmp_usbc_offsets {
>> +enum qmp_phy_usbc_type {
>> +       QMP_PHY_USBC_INVALID,
> 
> How can a type be invalid?
> 
I thought that platformdata must specify a type, so I set the default value to ‘invalid’.
I will remove this in a future patch.
>> +       QMP_PHY_USBC_USB,
>> +       QMP_PHY_USBC_DP,
>> +};
>> +
>> +/* list of regulators */
>> +struct qmp_regulator_data {
>> +       const char *name;
>> +       unsigned int enable_load;
>> +};
>> +
>> +struct dev_cfg {
>> +       int type;
>> +       const void *cfg;
>> +};
>> +
>> +struct qmp_usbc;
>> +
>> +struct qmp_usbc_usb_offsets {
>>         u16 serdes;
>>         u16 pcs;
>>         u16 pcs_misc;
>> @@ -295,9 +321,9 @@ struct qmp_usbc_offsets {
>>         u16 rx2;
>>  };
>>
>> -/* struct qmp_phy_cfg - per-PHY initialization config */
>> -struct qmp_phy_cfg {
>> -       const struct qmp_usbc_offsets *offsets;
>> +/* struct qmp_phy_usb_cfg - per-usb PHY initialization config */
> 
> what is "per-usb PHY"?
> 
Each usb phy in which defined in platform data.
Shall I remove this annotation?
>> +struct qmp_phy_usb_cfg {
>> +       const struct qmp_usbc_usb_offsets *offsets;
>>
>>         /* Init sequence for PHY blocks - serdes, tx, rx, pcs */
>>         const struct qmp_phy_init_tbl *serdes_tbl;
>> @@ -317,11 +343,7 @@ struct qmp_phy_cfg {
>>         const unsigned int *regs;
>>  };
>>
>> -struct qmp_usbc {
>> -       struct device *dev;
>> -
>> -       const struct qmp_phy_cfg *cfg;
>> -
>> +struct qmp_phy_usb_layout {
>>         void __iomem *serdes;
>>         void __iomem *pcs;
>>         void __iomem *pcs_misc;
>> @@ -329,28 +351,67 @@ struct qmp_usbc {
>>         void __iomem *rx;
>>         void __iomem *tx2;
>>         void __iomem *rx2;
>> -
>>         struct regmap *tcsr_map;
>>         u32 vls_clamp_reg;
>> -
>> +       enum phy_mode mode;
>> +       struct typec_switch_dev *sw;
>>         struct clk *pipe_clk;
>> +       struct clk_fixed_rate pipe_clk_fixed;
>> +};
>> +
>> +struct qmp_usbc_dp_offsets {
>> +       u16 dp_serdes;
>> +       u16 dp_txa;
>> +       u16 dp_txb;
>> +       u16 dp_phy;
>> +};
>> +
>> +/* struct qmp_phy_dp_cfg - per-dp PHY initialization config */
>> +struct qmp_phy_dp_cfg {
>> +       const struct qmp_usbc_dp_offsets *offsets;
>> +
>> +       /* DP PHY swing and pre_emphasis tables */
>> +       const u8 (*swing_tbl)[4][4];
>> +       const u8 (*pre_emphasis_tbl)[4][4];
>> +
>> +       // /* DP PHY callbacks */
>> +       int (*dp_aux_init)(struct qmp_usbc *qmp);
>> +       int (*configure_dp_serdes)(struct qmp_usbc *qmp);
>> +       int (*configure_dp_voltages)(struct qmp_usbc *qmp);
>> +       int (*configure_dp_phy)(struct qmp_usbc *qmp);
>> +       int (*calibrate_dp_phy)(struct qmp_usbc *qmp);
>> +
>> +       const struct qmp_regulator_data *vreg_list;
>> +       int num_vregs;
>> +};
>> +
>> +struct qmp_phy_dp_layout {
>> +       void __iomem *dp_phy;
>> +       void __iomem *dp_tx;
>> +       void __iomem *dp_tx2;
>> +       void __iomem *dp_serdes;
>> +       struct regmap *tcsr_map;
>> +       u32 dp_phy_mode;
>> +       unsigned int dp_aux_cfg;
>> +       struct phy_configure_opts_dp dp_opts;
>> +       struct clk_hw dp_link_hw;
>> +       struct clk_hw dp_pixel_hw;
>> +};
>> +
>> +struct qmp_usbc {
>> +       struct device *dev;
>> +       int type;
>>         struct clk_bulk_data *clks;
>>         int num_clks;
>>         int num_resets;
>>         struct reset_control_bulk_data *resets;
>>         struct regulator_bulk_data *vregs;
>> -
>>         struct mutex phy_mutex;
>> -
>> -       enum phy_mode mode;
>> -       unsigned int usb_init_count;
>> -
>>         struct phy *phy;
>> -
>> -       struct clk_fixed_rate pipe_clk_fixed;
>> -
>> -       struct typec_switch_dev *sw;
>>         enum typec_orientation orientation;
>> +       unsigned int init_count;
>> +       const void *cfg;
>> +       void *layout;
> 
> The patch contains a mixture of renames bundled with actual changes.
> Please explain why old names are bad in a separate patch.
> 
Ok, The renaming is mainly to distinguish which structures are for USB or DP, which are fixed configurations, and which are dynamically parsed variables.
After we clarify the overall direction, If still implement in usbc, 
will seperate to below 4 patchsets.
1.renaming and structural adjustments for the USB driver
2.structure definitions for DP extension.
3.common callback functions for DP.
4.platform-related functions for DP.

>>  };
>>
>>  static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
>> @@ -391,12 +452,21 @@ static const char * const usb3phy_reset_l[] = {
>>         "phy_phy", "phy",
>>  };
>>
>> +static const char * const dp_usb3phy_reset_l[] = {
>> +       "phy",
>> +};
>> +
>>  /* list of regulators */
>> -static const char * const qmp_phy_vreg_l[] = {
>> +static const char * const qmp_phy_usb_vreg_l[] = {
>>         "vdda-phy", "vdda-pll",
>>  };
>>
>> -static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {
>> +static struct qmp_regulator_data qmp_phy_dp_vreg_l[] = {
>> +       { .name = "vdda-phy", .enable_load = 21800 },
>> +       { .name = "vdda-pll", .enable_load = 36000 },
>> +};
>> +
>> +static const struct qmp_usbc_usb_offsets qmp_usbc_usb_offsets_v3_qcm2290 = {
>>         .serdes         = 0x0,
>>         .pcs            = 0xc00,
>>         .pcs_misc       = 0xa00,
>> @@ -406,8 +476,15 @@ static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {
>>         .rx2            = 0x800,
>>  };
>>
>> -static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
>> -       .offsets                = &qmp_usbc_offsets_v3_qcm2290,
>> +static const struct qmp_usbc_dp_offsets qmp_usbc_dp_offsets_qcs615 = {
>> +       .dp_serdes      = 0x0C00,
>> +       .dp_txa         = 0x0400,
>> +       .dp_txb         = 0x0800,
>> +       .dp_phy         = 0x0000,
>> +};
>> +
>> +static const struct qmp_phy_usb_cfg msm8998_usb3phy_cfg = {
>> +       .offsets                = &qmp_usbc_usb_offsets_v3_qcm2290,
>>
>>         .serdes_tbl             = msm8998_usb3_serdes_tbl,
>>         .serdes_tbl_num         = ARRAY_SIZE(msm8998_usb3_serdes_tbl),
>> @@ -417,13 +494,13 @@ 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_usb_vreg_l,
>> +       .num_vregs              = ARRAY_SIZE(qmp_phy_usb_vreg_l),
>>         .regs                   = qmp_v3_usb3phy_regs_layout,
>>  };
>>
>> -static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = {
>> -       .offsets                = &qmp_usbc_offsets_v3_qcm2290,
>> +static const struct qmp_phy_usb_cfg qcm2290_usb3phy_cfg = {
>> +       .offsets                = &qmp_usbc_usb_offsets_v3_qcm2290,
>>
>>         .serdes_tbl             = qcm2290_usb3_serdes_tbl,
>>         .serdes_tbl_num         = ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
>> @@ -433,13 +510,13 @@ 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_usb_vreg_l,
>> +       .num_vregs              = ARRAY_SIZE(qmp_phy_usb_vreg_l),
>>         .regs                   = qmp_v3_usb3phy_regs_layout_qcm2290,
>>  };
>>
>> -static const struct qmp_phy_cfg sdm660_usb3phy_cfg = {
>> -       .offsets                = &qmp_usbc_offsets_v3_qcm2290,
>> +static const struct qmp_phy_usb_cfg sdm660_usb3phy_cfg = {
>> +       .offsets                = &qmp_usbc_usb_offsets_v3_qcm2290,
>>
>>         .serdes_tbl             = qcm2290_usb3_serdes_tbl,
>>         .serdes_tbl_num         = ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
>> @@ -449,20 +526,352 @@ 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_usb_vreg_l,
>> +       .num_vregs              = ARRAY_SIZE(qmp_phy_usb_vreg_l),
>>         .regs                   = qmp_v3_usb3phy_regs_layout_qcm2290,
>>  };
>>
>> -static int qmp_usbc_init(struct phy *phy)
>> +static const u8 qmp_dp_pre_emphasis_hbr2_rbr[4][4] = {
>> +       {0x00, 0x0B, 0x12, 0xFF},       /* pe0, 0 db */
>> +       {0x00, 0x0A, 0x12, 0xFF},       /* pe1, 3.5 db */
>> +       {0x00, 0x0C, 0xFF, 0xFF},       /* pe2, 6.0 db */
>> +       {0xFF, 0xFF, 0xFF, 0xFF}        /* pe3, 9.5 db */
>> +};
>> +
>> +static const u8 qmp_dp_voltage_swing_hbr2_rbr[4][4] = {
>> +       {0x07, 0x0F, 0x14, 0xFF}, /* sw0, 0.4v  */
>> +       {0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */
>> +       {0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */
>> +       {0xFF, 0xFF, 0xFF, 0xFF}  /* sw1, 1.2 v, optional */
>> +};
>> +
>> +static int qcs615_qmp_dp_aux_init(struct qmp_usbc *qmp);
>> +static int qcs615_qmp_configure_dp_serdes(struct qmp_usbc *qmp);
>> +static int qcs615_qmp_configure_dp_voltages(struct qmp_usbc *qmp);
>> +static int qcs615_qmp_configure_dp_phy(struct qmp_usbc *qmp);
>> +static int qcs615_qmp_calibrate_dp_phy(struct qmp_usbc *qmp);
> 
> Are those functions really platform-specific?
> 
I mainly compared the driver of the combo PHY to identify reusable functions. 
I extracted the dp_aux_init, configure_dp_phy and calibrate_dp_phy,
and based on the differences in the flow of the HPG in the 14nm DP PHY, 
I separated out the configure_dp_voltages and configure_dp_serdes functions.

Detailed explanation is provided in the following comment.
>> +
>> +static void qmp_usbc_check_dp_phy(struct qmp_usbc *qmp, const char *pos);
>> +
>> +static const struct qmp_phy_dp_cfg qcs615_dpphy_cfg = {
>> +       .offsets                = &qmp_usbc_dp_offsets_qcs615,
>> +
>> +       .swing_tbl              = &qmp_dp_voltage_swing_hbr2_rbr,
>> +       .pre_emphasis_tbl       = &qmp_dp_pre_emphasis_hbr2_rbr,
>> +
>> +       .dp_aux_init            = qcs615_qmp_dp_aux_init,
>> +       .configure_dp_serdes    = qcs615_qmp_configure_dp_serdes,
>> +       .configure_dp_voltages  = qcs615_qmp_configure_dp_voltages,
>> +       .configure_dp_phy   = qcs615_qmp_configure_dp_phy,
>> +       .calibrate_dp_phy       = qcs615_qmp_calibrate_dp_phy,
>> +
>> +       .vreg_list              = qmp_phy_dp_vreg_l,
>> +       .num_vregs              = ARRAY_SIZE(qmp_phy_dp_vreg_l),
>> +};
>> +
>> +#define to_usb_cfg(x) ((struct qmp_phy_usb_cfg *)(x->cfg))
>> +#define to_dp_cfg(x) ((struct qmp_phy_dp_cfg *)(x->cfg))
>> +#define to_usb_layout(x) ((struct qmp_phy_usb_layout *)(x->layout))
>> +#define to_dp_layout(x) ((struct qmp_phy_dp_layout *)(x->layout))
>> +
>> +static int qcs615_qmp_dp_aux_init(struct qmp_usbc *qmp)
>> +{
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +
>> +       regmap_write(layout->tcsr_map, layout->dp_phy_mode, 0x1);
>> +
>> +       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,
>> +              layout->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,
>> +              layout->dp_phy + QSERDES_DP_PHY_PD_CTL);
>> +
>> +       writel(0x00, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG0);
>> +       writel(0x13, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG1);
>> +       writel(0x00, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG2);
>> +       writel(0x00, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG3);
>> +       writel(0x0a, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG4);
>> +       writel(0x26, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG5);
>> +       writel(0x0a, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG6);
>> +       writel(0x03, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG7);
>> +       writel(0xbb, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG8);
>> +       writel(0x03, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG9);
>> +       layout->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,
>> +              layout->dp_phy + QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK);
>> +       return 0;
>> +}
> 
> We've had DP PHY implementation in QMP Combo PHY and in eDP PHY.
> Please review them and work on extracting common bits into some kind
> of a library. At least -combo and your -usbc implementation seem close
> enough to warrant common library code.
> 
Initially, I intended to reference the register tables of combo. 
However, I discovered some flow differences in the 14nm PHY, 
So, I only kept the sw and pe tables, and the rest was implemented as functions.

1.configure_dp_serdes: 
The configuration of dp_serdes in the 14nm PHY is similar to that of eDP. 
The configurations corresponding to RBR to HBR2 need to be set in the middle of the dp_serdes.
Therefore, I didn’t split it into five tables, but instead referenced the eDP implementation such like com_configure_pll.

2.configure_dp_voltages:
14nm DP phy have only one pair of reference swing table and pre_emphasis_tbl.
Similar implement with combo V3.

3.configure_dp_phy & power_on:
This PHY requires alternating configurations among the dp_phy, dp_serdes, and dp_tx, dp_tx2 register groups,
which makes grouped configuration less convenient.
>> +
>> +static int qcs615_qmp_configure_dp_serdes(struct qmp_usbc *qmp)
>> +{
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +       void __iomem *serdes = layout->dp_serdes;
>> +       const struct phy_configure_opts_dp *dp_opts = &layout->dp_opts;
>> +       u8 hsclk_sel;
>> +       u8 dec_start_mode0;
>> +       u8 div_frac_start1_mode0;
>> +       u8 div_frac_start2_mode0;
>> +       u8 div_frac_start3_mode0;
>> +       u8 lock_cmp1_mode0;
>> +       u8 lock_cmp2_mode0;
>> +       u8 lock_cmp3_mode0;
>> +
>> +       switch (dp_opts->link_rate) {
>> +       case 1620:
>> +               hsclk_sel = 0x2c;
>> +               dec_start_mode0 = 0x69;
>> +               div_frac_start1_mode0 = 0x00;
>> +               div_frac_start2_mode0 = 0x80;
>> +               div_frac_start3_mode0 = 0x07;
>> +               lock_cmp1_mode0 = 0xbf;
>> +               lock_cmp2_mode0 = 0x21;
>> +               lock_cmp3_mode0 = 0x00;
>> +               break;
>> +       case 2700:
>> +               hsclk_sel = 0x24;
>> +               dec_start_mode0 = 0x69;
>> +               div_frac_start1_mode0 = 0x00;
>> +               div_frac_start2_mode0 = 0x80;
>> +               div_frac_start3_mode0 = 0x07;
>> +               lock_cmp1_mode0 = 0x3f;
>> +               lock_cmp2_mode0 = 0x38;
>> +               lock_cmp3_mode0 = 0x00;
>> +               break;
>> +       case 5400:
>> +               hsclk_sel = 0x20;
>> +               dec_start_mode0 = 0x8c;
>> +               div_frac_start1_mode0 = 0x00;
>> +               div_frac_start2_mode0 = 0x00;
>> +               div_frac_start3_mode0 = 0x0a;
>> +               lock_cmp1_mode0 = 0x7f;
>> +               lock_cmp2_mode0 = 0x70;
>> +               lock_cmp3_mode0 = 0x00;
>> +               break;
>> +       default:
>> +               /* Other link rates aren't supported */
>> +               return -EINVAL;
>> +       }
>> +
>> +       writel(0x01, serdes + QSERDES_COM_SVS_MODE_CLK_SEL);
>> +       writel(0x37, serdes + QSERDES_COM_SYSCLK_EN_SEL);
>> +       writel(0x00, serdes + QSERDES_COM_CLK_SELECT);
>> +       writel(0x06, serdes + QSERDES_COM_SYS_CLK_CTRL);
>> +       writel(0x3f, serdes + QSERDES_COM_BIAS_EN_CLKBUFLR_EN);
>> +       writel(0x0e, serdes + QSERDES_COM_CLK_ENABLE1);
>> +       writel(0x0f, serdes + QSERDES_COM_BG_CTRL);
>> +       writel(0x06, serdes + QSERDES_COM_SYSCLK_BUF_ENABLE);
>> +       writel(0x30, serdes + QSERDES_COM_CLK_SELECT);
>> +       writel(0x0f, serdes + QSERDES_COM_PLL_IVCO);
>> +       writel(0x28, serdes + QSERDES_COM_PLL_CCTRL_MODE0);
>> +       writel(0x16, serdes + QSERDES_COM_PLL_RCTRL_MODE0);
>> +       writel(0x0b, serdes + QSERDES_COM_CP_CTRL_MODE0);
>> +
>> +       writel(hsclk_sel, serdes + QSERDES_COM_HSCLK_SEL);
>> +       writel(dec_start_mode0, serdes + QSERDES_COM_DEC_START_MODE0);
>> +       writel(div_frac_start1_mode0, serdes + QSERDES_COM_DIV_FRAC_START1_MODE0);
>> +       writel(div_frac_start2_mode0, serdes + QSERDES_COM_DIV_FRAC_START2_MODE0);
>> +       writel(div_frac_start3_mode0, serdes + QSERDES_COM_DIV_FRAC_START3_MODE0);
>> +       writel(lock_cmp1_mode0, serdes + QSERDES_COM_LOCK_CMP1_MODE0);
>> +       writel(lock_cmp2_mode0, serdes + QSERDES_COM_LOCK_CMP2_MODE0);
>> +       writel(lock_cmp3_mode0, serdes + QSERDES_COM_LOCK_CMP3_MODE0);
>> +
>> +       writel(0x40, serdes + QSERDES_COM_INTEGLOOP_GAIN0_MODE0);
>> +       writel(0x00, serdes + QSERDES_COM_INTEGLOOP_GAIN1_MODE0);
>> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE_MAP);
>> +       writel(0x08, serdes + QSERDES_COM_BG_TIMER);
>> +       writel(0x05, serdes + QSERDES_COM_CORECLK_DIV);
>> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE_CTRL);
>> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE1_MODE0);
>> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE2_MODE0);
>> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE_CTRL);
>> +
>> +       writel(0x0f, serdes + QSERDES_COM_CORE_CLK_EN);
>> +
>> +       return 0;
>> +}
>> +
>> +static int qcs615_qmp_configure_dp_voltages(struct qmp_usbc *qmp)
>> +{
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +       struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
>> +       const struct phy_configure_opts_dp *dp_opts = &layout->dp_opts;
>> +       void __iomem *tx = layout->dp_tx;
>> +       void __iomem *tx2 = layout->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) || (pre_emphasis_cfg > 4)) {
>> +               dev_err(qmp->dev, "Invalid v(%d) | p(%d) level)\n",
>> +                       v_level, pre_emphasis_cfg);
>> +               return -EINVAL;
>> +       }
>> +
>> +       voltage_swing_cfg = (*cfg->swing_tbl)[v_level][p_level];
>> +       pre_emphasis_cfg = (*cfg->pre_emphasis_tbl)[v_level][p_level];
>> +
>> +       /* Enable MUX to use Cursor values from these registers */
>> +       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;
>> +
>> +       /* program default setting first */
>> +       writel(0x2A, tx + QSERDES_V3_TX_TX_DRV_LVL);
>> +       writel(0x20, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
>> +       writel(0x2A, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
>> +       writel(0x20, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> 
> Lowercase all hex numbers.
> 
Ok, will update in next patch.
>> +
>> +       writel(voltage_swing_cfg, tx + QSERDES_V3_TX_TX_DRV_LVL);
>> +       writel(pre_emphasis_cfg, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
>> +       writel(voltage_swing_cfg, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
>> +       writel(pre_emphasis_cfg, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
>> +
>> +       return 0;
>> +}
>> +
>> +static int qcs615_qmp_configure_dp_phy(struct qmp_usbc *qmp)
>> +{
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +       u32 status;
>> +
>> +       writel(0x01, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +       writel(0x05, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +       writel(0x01, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +       writel(0x09, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +
>> +       writel(0x20, layout->dp_serdes + QSERDES_COM_RESETSM_CNTRL);
>> +
>> +       // C_READY
>> +       if (readl_poll_timeout(layout->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;
>> +       }
>> +
>> +       // FREQ_DONE
>> +       if (readl_poll_timeout(layout->dp_serdes + QSERDES_COM_CMN_STATUS,
>> +                       status,
>> +                       ((status & BIT(0)) > 0),
>> +                       500,
>> +                       10000)){
>> +               dev_err(qmp->dev, "FREQ_DONE not ready\n");
>> +               return -ETIMEDOUT;
>> +       }
>> +
>> +       // PLL_LOCKED
>> +       if (readl_poll_timeout(layout->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, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +       udelay(10);
>> +
>> +       // TSYNC_DONE
>> +       if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS,
>> +                       status,
>> +                       ((status & BIT(0)) > 0),
>> +                       500,
>> +                       10000)){
>> +               dev_err(qmp->dev, "TSYNC_DONE not ready\n");
>> +               return -ETIMEDOUT;
>> +       }
>> +
>> +       // PHY_READY
>> +       if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS,
>> +                       status,
>> +                       ((status & BIT(1)) > 0),
>> +                       500,
>> +                       10000)){
>> +               dev_err(qmp->dev, "PHY_READY not ready\n");
>> +               return -ETIMEDOUT;
>> +       }
>> +
>> +       writel(0x3f, layout->dp_tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
>> +       writel(0x10, layout->dp_tx + QSERDES_V3_TX_HIGHZ_DRVR_EN);
>> +       writel(0x0a, layout->dp_tx + QSERDES_V3_TX_TX_POL_INV);
>> +       writel(0x3f, layout->dp_tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
>> +       writel(0x10, layout->dp_tx2 + QSERDES_V3_TX_HIGHZ_DRVR_EN);
>> +       writel(0x0a, layout->dp_tx2 + QSERDES_V3_TX_TX_POL_INV);
>> +
>> +       writel(0x18, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +       writel(0x19, layout->dp_phy + QSERDES_DP_PHY_CFG);
>> +
>> +       if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_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 qcs615_qmp_calibrate_dp_phy(struct qmp_usbc *qmp)
>> +{
>> +       static const u8 cfg1_settings[] = {0x13, 0x23, 0x1d};
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +       u8 val;
>> +
>> +       layout->dp_aux_cfg++;
>> +       layout->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
>> +       val = cfg1_settings[layout->dp_aux_cfg];
>> +
>> +       writel(val, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG1);
>> +
>> +       qmp_usbc_check_dp_phy(qmp, "pos_calibrate");
>> +
>> +       return 0;
>> +}
>> +
>> +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;
>> +       int num_vregs;
>>         u32 val = 0;
>>         int ret;
>> +       unsigned int reg_pwr_dn;
>>
>> -       ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
>> +       if (qmp->type == QMP_PHY_USBC_USB) {
>> +               struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
>> +
>> +               num_vregs = cfg->num_vregs;
>> +               reg_pwr_dn = cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL];
>> +       } else {
>> +               struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
>> +
>> +               num_vregs = cfg->num_vregs;
>> +       }
>> +
>> +       ret = regulator_bulk_enable(num_vregs, qmp->vregs);
>>         if (ret) {
>>                 dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
>>                 return ret;
>> @@ -484,73 +893,85 @@ static int qmp_usbc_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);
>> +
>> +       if (qmp->type == QMP_PHY_USBC_USB) {
> 
> Why?
> 
On QCS615 ADP AIR platform, Type-C DP orientation is fixed in one direction due to connected to the external video-out expansion board through the expansion slot.
Therefore, we cannot validate DP orientation behaviour. 
As a result, the orientation part remains consistent with the original implementation of the USB-C driver and only applies to USB devices.
>> +               struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>> +
>> +               qphy_setbits(layout->pcs, reg_pwr_dn, SW_PWRDN);
>> +               writel(val, layout->pcs_misc);
>> +       }
>>
>>         return 0;
>>
>>  err_assert_reset:
>>         reset_control_bulk_assert(qmp->num_resets, qmp->resets);
>>  err_disable_regulators:
>> -       regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
>> +       regulator_bulk_disable(num_vregs, qmp->vregs);
>>
>>         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;
>> +       int num_vregs;
>>
>>         reset_control_bulk_assert(qmp->num_resets, qmp->resets);
>>
>>         clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
>>
>> -       regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
>> +       if (qmp->type == QMP_PHY_USBC_USB) {
>> +               struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
>> +
>> +               num_vregs = cfg->num_vregs;
>> +       } else {
>> +               struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
>> +
>> +               num_vregs = cfg->num_vregs;
>> +       }
>> +       regulator_bulk_disable(num_vregs, qmp->vregs);
>>
>>         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;
>> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
>> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>>         void __iomem *status;
>>         unsigned int val;
>>         int ret;
>>
>> -       qmp_configure(qmp->dev, qmp->serdes, cfg->serdes_tbl,
>> +       qmp_configure(qmp->dev, layout->serdes, cfg->serdes_tbl,
>>                       cfg->serdes_tbl_num);
>>
>> -       ret = clk_prepare_enable(qmp->pipe_clk);
>> +       ret = clk_prepare_enable(layout->pipe_clk);
>>         if (ret) {
>>                 dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret);
>>                 return ret;
>>         }
>>
>>         /* Tx, Rx, and PCS configurations */
>> -       qmp_configure_lane(qmp->dev, qmp->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
>> -       qmp_configure_lane(qmp->dev, qmp->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
>> +       qmp_configure_lane(qmp->dev, layout->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
>> +       qmp_configure_lane(qmp->dev, layout->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
>>
>> -       qmp_configure_lane(qmp->dev, qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);
>> -       qmp_configure_lane(qmp->dev, qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
>> +       qmp_configure_lane(qmp->dev, layout->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);
>> +       qmp_configure_lane(qmp->dev, layout->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
>>
>> -       qmp_configure(qmp->dev, qmp->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
>> +       qmp_configure(qmp->dev, layout->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
>>
>>         /* Pull PHY out of reset state */
>> -       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
>> +       qphy_clrbits(layout->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
>>
>>         /* start SerDes and Phy-Coding-Sublayer */
>> -       qphy_setbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START);
>> +       qphy_setbits(layout->pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START);
>>
>> -       status = qmp->pcs + cfg->regs[QPHY_PCS_STATUS];
>> +       status = layout->pcs + cfg->regs[QPHY_PCS_STATUS];
>>         ret = readl_poll_timeout(status, val, !(val & PHYSTATUS), 200,
>>                                  PHY_INIT_COMPLETE_TIMEOUT);
>>         if (ret) {
>> @@ -561,92 +982,348 @@ static int qmp_usbc_power_on(struct phy *phy)
>>         return 0;
>>
>>  err_disable_pipe_clk:
>> -       clk_disable_unprepare(qmp->pipe_clk);
>> +       clk_disable_unprepare(layout->pipe_clk);
>>
>>         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;
>> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
>> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>>
>> -       clk_disable_unprepare(qmp->pipe_clk);
>> +       clk_disable_unprepare(layout->pipe_clk);
>>
>>         /* PHY reset */
>> -       qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
>> +       qphy_setbits(layout->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
>>
>>         /* stop SerDes and Phy-Coding-Sublayer */
>> -       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL],
>> +       qphy_clrbits(layout->pcs, cfg->regs[QPHY_START_CTRL],
>>                         SERDES_START | PCS_START);
>>
>>         /* Put PHY into POWER DOWN state: active low */
>> -       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
>> +       qphy_clrbits(layout->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
>>                         SW_PWRDN);
>>
>>         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;
>>         }
>>
>> -       qmp->usb_init_count++;
>> +       qmp->init_count++;
>>  out_unlock:
>>         mutex_unlock(&qmp->phy_mutex);
>>
>>         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);
>> +       qmp->init_count--;
>> +       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_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode)
>> +{
>> +       struct qmp_usbc *qmp = phy_get_drvdata(phy);
>> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>> +
>> +       layout->mode = mode;
>> +
>> +       return 0;
>> +}
>> +
>> +static int qmp_usbc_dp_init(struct phy *phy)
>> +{
>> +       struct qmp_usbc *qmp = phy_get_drvdata(phy);
>> +       const struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
>> +       int ret;
>> +
>> +       if (qmp->init_count) {
>> +               dev_err(qmp->dev, "type(%d) inited(%d)\n", qmp->type, qmp->init_count);
>> +               return 0;
>> +       }
>> +
>> +       mutex_lock(&qmp->phy_mutex);
>> +
>> +       ret = qmp_usbc_com_init(phy);
>> +       if (ret) {
>> +               dev_err(qmp->dev, "type(%d) com_init fail\n", qmp->type);
>> +               goto dp_init_unlock;
>> +       }
>> +
>> +       cfg->dp_aux_init(qmp);
>> +
>> +       qmp->init_count++;
>> +
>> +dp_init_unlock:
>> +       mutex_unlock(&qmp->phy_mutex);
>> +       return ret;
>> +}
>> +
>> +static int qmp_usbc_dp_exit(struct phy *phy)
>> +{
>> +       struct qmp_usbc *qmp = phy_get_drvdata(phy);
>> +
>> +       mutex_lock(&qmp->phy_mutex);
>> +
>> +       qmp_usbc_com_exit(phy);
>> +
>> +       qmp->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);
>> +       struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +       int ret;
>> +
>> +       mutex_lock(&qmp->phy_mutex);
>> +
>> +       memcpy(&layout->dp_opts, dp_opts, sizeof(*dp_opts));
>> +       if (layout->dp_opts.set_voltages) {
>> +               ret = cfg->configure_dp_voltages(qmp);
>> +               if (ret) {
>> +                       dev_err(qmp->dev, "type(%d) err(%d)\n", qmp->type, ret);
>> +                       mutex_unlock(&qmp->phy_mutex);
>> +                       return ret;
>> +               }
>> +
>> +               layout->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);
>> +       struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
>> +       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, "type(%d) err(%d)\n", qmp->type, ret);
>> +                       mutex_unlock(&qmp->phy_mutex);
>> +                       return ret;
>> +               }
>> +       }
>> +
>> +       mutex_unlock(&qmp->phy_mutex);
>> +       return 0;
>>  }
>>
>> -static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode)
>> +static int qmp_usbc_configure_dp_clocks(struct qmp_usbc *qmp)
>> +{
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +       const struct phy_configure_opts_dp *dp_opts = &layout->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;
>> +       case 8100:
>> +               phy_vco_div = 0x0;
>> +               pixel_freq = 8100000000UL / 6;
>> +               break;
>> +       default:
>> +               /* Other link rates aren't supported */
>> +               return -EINVAL;
>> +       }
>> +       writel(phy_vco_div, layout->dp_phy + QSERDES_DP_PHY_VCO_DIV);
>> +
>> +       clk_set_rate(layout->dp_link_hw.clk, dp_opts->link_rate * 100000);
>> +       clk_set_rate(layout->dp_pixel_hw.clk, pixel_freq);
>> +
>> +       return 0;
>> +}
>> +
>> +static void qmp_usbc_check_dp_phy(struct qmp_usbc *qmp, const char *pos)
>> +{
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +       u8 c_ready, cmn_status, phy_status;
>> +
>> +       c_ready = readl(layout->dp_serdes + QSERDES_COM_C_READY_STATUS);
>> +       cmn_status = readl(layout->dp_serdes + QSERDES_COM_CMN_STATUS);
>> +       phy_status = readl(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS);
>> +
>> +       dev_dbg(qmp->dev, "pos(%s) c_ready(0x%x) cmn_status(0x%x) phy_status(0x%x)\n",
>> +               pos, c_ready, cmn_status, phy_status);
>> +}
>> +
>> +static int qmp_usbc_dp_power_on(struct phy *phy)
>> +{
>> +       struct qmp_usbc *qmp = phy_get_drvdata(phy);
>> +       const struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +       const struct phy_configure_opts_dp *dp_opts = &layout->dp_opts;
>> +       bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
>> +       void __iomem *tx = layout->dp_tx;
>> +       void __iomem *tx2 = layout->dp_tx2;
>> +       u8 lane_mode_1;
>> +       int ret = 0;
>> +
>> +       mutex_lock(&qmp->phy_mutex);
>> +
>> +       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,
>> +               layout->dp_phy + QSERDES_DP_PHY_PD_CTL);
>> +
>> +       ret = cfg->configure_dp_serdes(qmp);
>> +       if (ret) {
>> +               dev_err(qmp->dev, "failed to config pll\n");
>> +               goto power_on_unlock;
>> +       }
>> +
>> +       if (dp_opts->link_rate >= 2700)
>> +               lane_mode_1 = 0xc4;
>> +       else
>> +               lane_mode_1 = 0xc6;
>> +
>> +       writel(lane_mode_1, tx + QSERDES_V3_TX_LANE_MODE_1);
>> +       writel(lane_mode_1, tx2 + QSERDES_V3_TX_LANE_MODE_1);
>> +
>> +       if (reverse)
>> +               writel(0xc9, layout->dp_phy + QSERDES_DP_PHY_MODE);
>> +       else
>> +               writel(0xd9, layout->dp_phy + QSERDES_DP_PHY_MODE);
>> +
>> +       writel(0x05, layout->dp_phy + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL);
>> +       writel(0x05, layout->dp_phy + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL);
>> +
>> +       writel(0x1a, tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
>> +       writel(0x40, tx + QSERDES_V3_TX_VMODE_CTRL1);
>> +       writel(0x30, tx + QSERDES_V3_TX_PRE_STALL_LDO_BOOST_EN);
>> +       writel(0x3d, tx + QSERDES_V3_TX_INTERFACE_SELECT);
>> +       writel(0x0f, tx + QSERDES_V3_TX_CLKBUF_ENABLE);
>> +       writel(0x03, tx + QSERDES_V3_TX_RESET_TSYNC_EN);
>> +       writel(0x03, tx + QSERDES_V3_TX_TRAN_DRVR_EMP_EN);
>> +       writel(0x00, tx + QSERDES_V3_TX_PARRATE_REC_DETECT_IDLE_EN);
>> +       writel(0x00, tx + QSERDES_V3_TX_TX_INTERFACE_MODE);
>> +       writel(0x2b, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
>> +       writel(0x2f, tx + QSERDES_V3_TX_TX_DRV_LVL);
>> +       writel(0x04, tx + QSERDES_V3_TX_TX_BAND);
>> +       writel(0x12, tx + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX);
>> +       writel(0x12, tx + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX);
>> +
>> +       writel(0x1a, tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
>> +       writel(0x40, tx2 + QSERDES_V3_TX_VMODE_CTRL1);
>> +       writel(0x30, tx2 + QSERDES_V3_TX_PRE_STALL_LDO_BOOST_EN);
>> +       writel(0x3d, tx2 + QSERDES_V3_TX_INTERFACE_SELECT);
>> +       writel(0x0f, tx2 + QSERDES_V3_TX_CLKBUF_ENABLE);
>> +       writel(0x03, tx2 + QSERDES_V3_TX_RESET_TSYNC_EN);
>> +       writel(0x03, tx2 + QSERDES_V3_TX_TRAN_DRVR_EMP_EN);
>> +       writel(0x00, tx2 + QSERDES_V3_TX_PARRATE_REC_DETECT_IDLE_EN);
>> +       writel(0x00, tx2 + QSERDES_V3_TX_TX_INTERFACE_MODE);
>> +       writel(0x2b, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
>> +       writel(0x2f, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
>> +       writel(0x04, tx2 + QSERDES_V3_TX_TX_BAND);
>> +       writel(0x12, tx2 + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX);
>> +       writel(0x12, tx2 + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX);
>> +
>> +       writel(0x02, layout->dp_serdes + QSERDES_COM_CMN_CONFIG);
>> +       qmp_usbc_configure_dp_clocks(qmp);
>> +
>> +       ret = cfg->configure_dp_phy(qmp);
>> +       if (ret) {
>> +               dev_err(qmp->dev, "failed to config dp phy\n");
>> +               goto power_on_unlock;
>> +       }
>> +
>> +       qmp_usbc_check_dp_phy(qmp, "usbc_dp_power_on_finish");
>> +
>> +power_on_unlock:
>> +       mutex_unlock(&qmp->phy_mutex);
>> +
>> +       return ret;
>> +}
>> +
>> +static int qmp_usbc_dp_power_off(struct phy *phy)
>>  {
>>         struct qmp_usbc *qmp = phy_get_drvdata(phy);
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +
>> +       mutex_lock(&qmp->phy_mutex);
>>
>> -       qmp->mode = mode;
>> +       /* Assert DP PHY power down */
>> +       writel(DP_PHY_PD_CTL_PSR_PWRDN, layout->dp_phy + QSERDES_DP_PHY_PD_CTL);
>> +
>> +       mutex_unlock(&qmp->phy_mutex);
>>
>>         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,
>> +};
>> +
>> +static const struct phy_ops qmp_usbc_dp_phy_ops = {
>> +       .init           = qmp_usbc_dp_init,
>> +       .exit           = qmp_usbc_dp_exit,
>> +       .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;
>> -       void __iomem *pcs = qmp->pcs;
>> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
>> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>> +       void __iomem *pcs = layout->pcs;
>>         u32 intr_mask;
>>
>> -       if (qmp->mode == PHY_MODE_USB_HOST_SS ||
>> -           qmp->mode == PHY_MODE_USB_DEVICE_SS)
>> +       if (layout->mode == PHY_MODE_USB_HOST_SS ||
>> +           layout->mode == PHY_MODE_USB_DEVICE_SS)
>>                 intr_mask = ARCVR_DTCT_EN | ALFPS_DTCT_EN;
>>         else
>>                 intr_mask = ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL;
>> @@ -663,18 +1340,19 @@ static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp)
>>         qphy_setbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask);
>>
>>         /* Enable i/o clamp_n for autonomous mode */
>> -       if (qmp->tcsr_map && qmp->vls_clamp_reg)
>> -               regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 1);
>> +       if (layout->tcsr_map && layout->vls_clamp_reg)
>> +               regmap_write(layout->tcsr_map, layout->vls_clamp_reg, 1);
>>  }
>>
>>  static void qmp_usbc_disable_autonomous_mode(struct qmp_usbc *qmp)
>>  {
>> -       const struct qmp_phy_cfg *cfg = qmp->cfg;
>> -       void __iomem *pcs = qmp->pcs;
>> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
>> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>> +       void __iomem *pcs = layout->pcs;
>>
>>         /* Disable i/o clamp_n on resume for normal mode */
>> -       if (qmp->tcsr_map && qmp->vls_clamp_reg)
>> -               regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 0);
>> +       if (layout->tcsr_map && layout->vls_clamp_reg)
>> +               regmap_write(layout->tcsr_map, layout->vls_clamp_reg, 0);
>>
>>         qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL],
>>                      ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL | ALFPS_DTCT_EN);
>> @@ -688,16 +1366,19 @@ static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev)
>>  {
>>         struct qmp_usbc *qmp = dev_get_drvdata(dev);
>>
>> -       dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode);
>> -
>>         if (!qmp->phy->init_count) {
>>                 dev_vdbg(dev, "PHY not initialized, bailing out\n");
>>                 return 0;
>>         }
>>
>> -       qmp_usbc_enable_autonomous_mode(qmp);
>> +       if (qmp->type == QMP_PHY_USBC_USB) {
>> +               struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>> +
>> +               dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", layout->mode);
>> +               qmp_usbc_enable_autonomous_mode(qmp);
>> +               clk_disable_unprepare(layout->pipe_clk);
>> +       }
>>
>> -       clk_disable_unprepare(qmp->pipe_clk);
>>         clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
>>
>>         return 0;
>> @@ -708,8 +1389,6 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev)
>>         struct qmp_usbc *qmp = dev_get_drvdata(dev);
>>         int ret = 0;
>>
>> -       dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode);
>> -
>>         if (!qmp->phy->init_count) {
>>                 dev_vdbg(dev, "PHY not initialized, bailing out\n");
>>                 return 0;
>> @@ -719,14 +1398,19 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev)
>>         if (ret)
>>                 return ret;
>>
>> -       ret = clk_prepare_enable(qmp->pipe_clk);
>> -       if (ret) {
>> -               dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);
>> -               clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
>> -               return ret;
>> -       }
>> +       if (qmp->type == QMP_PHY_USBC_USB) {
>> +               struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>>
>> -       qmp_usbc_disable_autonomous_mode(qmp);
>> +               dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", layout->mode);
>> +               ret = clk_prepare_enable(layout->pipe_clk);
>> +               if (ret) {
>> +                       dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);
>> +                       clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
>> +                       return ret;
>> +               }
>> +
>> +               qmp_usbc_disable_autonomous_mode(qmp);
>> +       }
>>
>>         return 0;
>>  }
>> @@ -738,19 +1422,54 @@ static const struct dev_pm_ops qmp_usbc_pm_ops = {
>>
>>  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;
>> +       int ret, i;
>>
>> -       qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL);
>> -       if (!qmp->vregs)
>> -               return -ENOMEM;
>> +       if (qmp->type == QMP_PHY_USBC_USB) {
>> +               struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
>> +               int num = cfg->num_vregs;
>>
>> -       for (i = 0; i < num; i++)
>> -               qmp->vregs[i].supply = cfg->vreg_list[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);
>> +               ret = devm_regulator_bulk_get(dev, num, qmp->vregs);
>> +               if (ret) {
>> +                       dev_err(dev, "failed at devm_regulator_bulk_get\n");
>> +                       return ret;
>> +               }
>> +       } else {
>> +               struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
>> +               int num = cfg->num_vregs;
>> +
>> +               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].name;
>> +
>> +               ret = devm_regulator_bulk_get(dev, num, qmp->vregs);
>> +               if (ret) {
>> +                       dev_err(dev, "failed at devm_regulator_bulk_get\n");
>> +                       return ret;
>> +               }
>> +
>> +               for (i = 0; i < num; i++) {
>> +                       ret = regulator_set_load(qmp->vregs[i].consumer,
>> +                                               cfg->vreg_list[i].enable_load);
>> +                       if (ret) {
>> +                               dev_err(dev, "failed to set load at %s\n",
>> +                                       qmp->vregs[i].supply);
>> +                               return ret;
>> +                       }
>> +               }
>> +       }
>> +
>> +       return 0;
>>  }
>>
>>  static int qmp_usbc_reset_init(struct qmp_usbc *qmp,
>> @@ -821,7 +1540,9 @@ static void phy_clk_release_provider(void *res)
>>   */
>>  static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np)
>>  {
>> -       struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed;
>> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>> +
>> +       struct clk_fixed_rate *fixed = &layout->pipe_clk_fixed;
>>         struct clk_init_data init = { };
>>         int ret;
>>
>> @@ -864,12 +1585,12 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw,
>>         mutex_lock(&qmp->phy_mutex);
>>         qmp->orientation = orientation;
>>
>> -       if (qmp->usb_init_count) {
>> -               qmp_usbc_power_off(qmp->phy);
>> -               qmp_usbc_exit(qmp->phy);
>> +       if (qmp->init_count) {
>> +               qmp_usbc_usb_power_off(qmp->phy);
>> +               qmp_usbc_com_exit(qmp->phy);
>>
>> -               qmp_usbc_init(qmp->phy);
>> -               qmp_usbc_power_on(qmp->phy);
>> +               qmp_usbc_com_init(qmp->phy);
>> +               qmp_usbc_usb_power_on(qmp->phy);
>>         }
>>
>>         mutex_unlock(&qmp->phy_mutex);
>> @@ -880,22 +1601,24 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw,
>>  static void qmp_usbc_typec_unregister(void *data)
>>  {
>>         struct qmp_usbc *qmp = data;
>> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>>
>> -       typec_switch_unregister(qmp->sw);
>> +       typec_switch_unregister(layout->sw);
>>  }
>>
>>  static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp)
>>  {
>>         struct typec_switch_desc sw_desc = {};
>>         struct device *dev = qmp->dev;
>> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>>
>>         sw_desc.drvdata = qmp;
>>         sw_desc.fwnode = dev->fwnode;
>>         sw_desc.set = qmp_usbc_typec_switch_set;
>> -       qmp->sw = typec_switch_register(dev, &sw_desc);
>> -       if (IS_ERR(qmp->sw)) {
>> -               dev_err(dev, "Unable to register typec switch: %pe\n", qmp->sw);
>> -               return PTR_ERR(qmp->sw);
>> +       layout->sw = typec_switch_register(dev, &sw_desc);
>> +       if (IS_ERR(layout->sw)) {
>> +               dev_err(dev, "Unable to register typec switch: %pe\n", layout->sw);
>> +               return PTR_ERR(layout->sw);
>>         }
>>
>>         return devm_add_action_or_reset(dev, qmp_usbc_typec_unregister, qmp);
>> @@ -907,15 +1630,16 @@ static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp)
>>  }
>>  #endif
>>
>> -static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np)
>> +static int qmp_usbc_parse_usb_dt_legacy(struct qmp_usbc *qmp, struct device_node *np)
>>  {
>>         struct platform_device *pdev = to_platform_device(qmp->dev);
>>         struct device *dev = qmp->dev;
>> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>>         int ret;
>>
>> -       qmp->serdes = devm_platform_ioremap_resource(pdev, 0);
>> -       if (IS_ERR(qmp->serdes))
>> -               return PTR_ERR(qmp->serdes);
>> +       layout->serdes = devm_platform_ioremap_resource(pdev, 0);
>> +       if (IS_ERR(layout->serdes))
>> +               return PTR_ERR(layout->serdes);
>>
>>         /*
>>          * Get memory resources for the PHY:
>> @@ -923,35 +1647,35 @@ static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np
>>          * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5
>>          * For single lane PHYs: pcs_misc (optional) -> 3.
>>          */
>> -       qmp->tx = devm_of_iomap(dev, np, 0, NULL);
>> -       if (IS_ERR(qmp->tx))
>> -               return PTR_ERR(qmp->tx);
>> +       layout->tx = devm_of_iomap(dev, np, 0, NULL);
>> +       if (IS_ERR(layout->tx))
>> +               return PTR_ERR(layout->tx);
>>
>> -       qmp->rx = devm_of_iomap(dev, np, 1, NULL);
>> -       if (IS_ERR(qmp->rx))
>> -               return PTR_ERR(qmp->rx);
>> +       layout->rx = devm_of_iomap(dev, np, 1, NULL);
>> +       if (IS_ERR(layout->rx))
>> +               return PTR_ERR(layout->rx);
>>
>> -       qmp->pcs = devm_of_iomap(dev, np, 2, NULL);
>> -       if (IS_ERR(qmp->pcs))
>> -               return PTR_ERR(qmp->pcs);
>> +       layout->pcs = devm_of_iomap(dev, np, 2, NULL);
>> +       if (IS_ERR(layout->pcs))
>> +               return PTR_ERR(layout->pcs);
>>
>> -       qmp->tx2 = devm_of_iomap(dev, np, 3, NULL);
>> -       if (IS_ERR(qmp->tx2))
>> -               return PTR_ERR(qmp->tx2);
>> +       layout->tx2 = devm_of_iomap(dev, np, 3, NULL);
>> +       if (IS_ERR(layout->tx2))
>> +               return PTR_ERR(layout->tx2);
>>
>> -       qmp->rx2 = devm_of_iomap(dev, np, 4, NULL);
>> -       if (IS_ERR(qmp->rx2))
>> -               return PTR_ERR(qmp->rx2);
>> +       layout->rx2 = devm_of_iomap(dev, np, 4, NULL);
>> +       if (IS_ERR(layout->rx2))
>> +               return PTR_ERR(layout->rx2);
>>
>> -       qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
>> -       if (IS_ERR(qmp->pcs_misc)) {
>> +       layout->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
>> +       if (IS_ERR(layout->pcs_misc)) {
>>                 dev_vdbg(dev, "PHY pcs_misc-reg not used\n");
>> -               qmp->pcs_misc = NULL;
>> +               layout->pcs_misc = NULL;
>>         }
>>
>> -       qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
>> -       if (IS_ERR(qmp->pipe_clk)) {
>> -               return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
>> +       layout->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
>> +       if (IS_ERR(layout->pipe_clk)) {
>> +               return dev_err_probe(dev, PTR_ERR(layout->pipe_clk),
>>                                      "failed to get pipe clock\n");
>>         }
>>
>> @@ -969,11 +1693,12 @@ static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np
>>         return 0;
>>  }
>>
>> -static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
>> +static int qmp_usbc_parse_usb_dt(struct qmp_usbc *qmp)
>>  {
>>         struct platform_device *pdev = to_platform_device(qmp->dev);
>> -       const struct qmp_phy_cfg *cfg = qmp->cfg;
>> -       const struct qmp_usbc_offsets *offs = cfg->offsets;
>> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
>> +       const struct qmp_usbc_usb_offsets *offs = cfg->offsets;
>> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>>         struct device *dev = qmp->dev;
>>         void __iomem *base;
>>         int ret;
>> @@ -985,23 +1710,23 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
>>         if (IS_ERR(base))
>>                 return PTR_ERR(base);
>>
>> -       qmp->serdes = base + offs->serdes;
>> -       qmp->pcs = base + offs->pcs;
>> +       layout->serdes = base + offs->serdes;
>> +       layout->pcs = base + offs->pcs;
>>         if (offs->pcs_misc)
>> -               qmp->pcs_misc = base + offs->pcs_misc;
>> -       qmp->tx = base + offs->tx;
>> -       qmp->rx = base + offs->rx;
>> +               layout->pcs_misc = base + offs->pcs_misc;
>> +       layout->tx = base + offs->tx;
>> +       layout->rx = base + offs->rx;
>>
>> -       qmp->tx2 = base + offs->tx2;
>> -       qmp->rx2 = base + offs->rx2;
>> +       layout->tx2 = base + offs->tx2;
>> +       layout->rx2 = base + offs->rx2;
>>
>>         ret = qmp_usbc_clk_init(qmp);
>>         if (ret)
>>                 return ret;
>>
>> -       qmp->pipe_clk = devm_clk_get(dev, "pipe");
>> -       if (IS_ERR(qmp->pipe_clk)) {
>> -               return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
>> +       layout->pipe_clk = devm_clk_get(dev, "pipe");
>> +       if (IS_ERR(layout->pipe_clk)) {
>> +               return dev_err_probe(dev, PTR_ERR(layout->pipe_clk),
>>                                      "failed to get pipe clock\n");
>>         }
>>
>> @@ -1013,10 +1738,11 @@ 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_usb_vls_clamp(struct qmp_usbc *qmp)
>>  {
>>         struct of_phandle_args tcsr_args;
>>         struct device *dev = qmp->dev;
>> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
>>         int ret;
>>
>>         /*  for backwards compatibility ignore if there is no property */
>> @@ -1027,22 +1753,280 @@ static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp)
>>         else if (ret < 0)
>>                 return dev_err_probe(dev, ret, "Failed to parse qcom,tcsr-reg\n");
>>
>> -       qmp->tcsr_map = syscon_node_to_regmap(tcsr_args.np);
>> +       layout->tcsr_map = syscon_node_to_regmap(tcsr_args.np);
>>         of_node_put(tcsr_args.np);
>> -       if (IS_ERR(qmp->tcsr_map))
>> -               return PTR_ERR(qmp->tcsr_map);
>> +       if (IS_ERR(layout->tcsr_map))
>> +               return PTR_ERR(layout->tcsr_map);
>>
>> -       qmp->vls_clamp_reg = tcsr_args.args[0];
>> +       layout->vls_clamp_reg = tcsr_args.args[0];
>>
>>         return 0;
>>  }
>>
>> +static int qmp_usbc_parse_dp_phy_mode(struct qmp_usbc *qmp)
>> +{
>> +       struct of_phandle_args tcsr_args;
>> +       struct device *dev = qmp->dev;
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +       int ret;
>> +
>> +       /*  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);
>> +       if (ret < 0)
>> +               return dev_err_probe(dev, ret, "Failed to parse qcom,tcsr-reg\n");
>> +
>> +       layout->tcsr_map = syscon_node_to_regmap(tcsr_args.np);
>> +       of_node_put(tcsr_args.np);
>> +       if (IS_ERR(layout->tcsr_map))
>> +               return PTR_ERR(layout->tcsr_map);
>> +
>> +       layout->dp_phy_mode = tcsr_args.args[0];
>> +
>> +       return 0;
>> +}
>> +
>> +static int qmp_usbc_parse_dp_dt(struct qmp_usbc *qmp)
>> +{
>> +       struct platform_device *pdev = to_platform_device(qmp->dev);
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +       struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
>> +       const struct qmp_usbc_dp_offsets *offs = cfg->offsets;
>> +       struct device *dev = qmp->dev;
>> +       void __iomem *base;
>> +       int ret;
>> +
>> +       base = devm_platform_ioremap_resource(pdev, 0);
>> +       if (IS_ERR(base)) {
>> +               dev_err(dev, "get resource fail, ret:%d\n", ret);
>> +               return PTR_ERR(base);
>> +       }
>> +
>> +       layout->dp_serdes = base + offs->dp_serdes;
>> +       layout->dp_tx = base + offs->dp_txa;
>> +       layout->dp_tx2 = base + offs->dp_txb;
>> +       layout->dp_phy = base + offs->dp_phy;
>> +
>> +       ret = qmp_usbc_clk_init(qmp);
>> +       if (ret) {
>> +               dev_err(dev, "clk init fail, ret:%d\n", ret);
>> +               return ret;
>> +       }
>> +
>> +       ret = qmp_usbc_reset_init(qmp, dp_usb3phy_reset_l,
>> +                                ARRAY_SIZE(dp_usb3phy_reset_l));
>> +       if (ret)
>> +               return ret;
>> +
>> +       return 0;
>> +}
>> +
>> +/*
>> + * 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 and 8.1 GHz are same link rate as 2.7GHz, i.e. div 4 and div 6 */
>> +               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;
>> +       struct qmp_phy_dp_layout *layout;
>> +       const struct phy_configure_opts_dp *dp_opts;
>> +
>> +       layout = container_of(hw, struct qmp_phy_dp_layout, dp_pixel_hw);
>> +
>> +       dp_opts = &layout->dp_opts;
>> +
>> +       switch (dp_opts->link_rate) {
>> +       case 1620:
>> +               return 1620000000UL / 2;
>> +       case 2700:
>> +               return 2700000000UL / 2;
>> +       case 5400:
>> +               return 5400000000UL / 4;
>> +       case 8100:
>> +               return 8100000000UL / 6;
>> +       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:
>> +       case 810000000:
>> +               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_combo *qmp;
>> +       struct qmp_phy_dp_layout *layout;
>> +       const struct phy_configure_opts_dp *dp_opts;
>> +
>> +       layout = container_of(hw, struct qmp_phy_dp_layout, dp_link_hw);
>> +       dp_opts = &layout->dp_opts;
>> +
>> +       switch (dp_opts->link_rate) {
>> +       case 1620:
>> +       case 2700:
>> +       case 5400:
>> +       case 8100:
>> +               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 = { };
>> +       int ret = 0;
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +
>> +       ret = of_property_read_string_index(np, "clock-output-names", 0, &init.name);
>> +       if (ret < 0) {
>> +               dev_err(qmp->dev, "%pOFn: No link clock-output-names\n", np);
>> +               return ret;
>> +       }
>> +
>> +       init.ops = &qmp_dp_link_clk_ops;
>> +       layout->dp_link_hw.init = &init;
>> +       ret = devm_clk_hw_register(qmp->dev, &layout->dp_link_hw);
>> +       if (ret < 0) {
>> +               dev_err(qmp->dev, "link clk reg fail ret=%d\n", ret);
>> +               return ret;
>> +       }
>> +
>> +       ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
>> +       if (ret) {
>> +               dev_err(qmp->dev, "%pOFn: No div clock-output-names\n", np);
>> +               return ret;
>> +       }
>> +
>> +       init.ops = &qmp_dp_pixel_clk_ops;
>> +       layout->dp_pixel_hw.init = &init;
>> +       ret = devm_clk_hw_register(qmp->dev, &layout->dp_pixel_hw);
>> +       if (ret) {
>> +               dev_err(qmp->dev, "pxl clk reg fail ret=%d\n", ret);
>> +               return ret;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static struct clk_hw *qmp_dp_clks_hw_get(struct of_phandle_args *clkspec, void *data)
>> +{
>> +       struct qmp_usbc *qmp = data;
>> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
>> +
>> +       switch (clkspec->args[0]) {
>> +       case QMP_USB43DP_DP_LINK_CLK:
>> +               return &layout->dp_link_hw;
>> +       case QMP_USB43DP_DP_VCO_DIV_CLK:
>> +               return &layout->dp_pixel_hw;
>> +       }
>> +
>> +       return ERR_PTR(-EINVAL);
>> +}
>> +
>> +static int qmp_dp_register_clocks(struct qmp_usbc *qmp, struct device_node *dp_np)
>> +{
>> +       int ret;
>> +
>> +       ret = phy_dp_clks_register(qmp, dp_np);
>> +       if (ret) {
>> +               dev_err(qmp->dev, "dp clk reg fail ret:%d\n", ret);
>> +               return ret;
>> +       }
>> +
>> +       ret = of_clk_add_hw_provider(dp_np, qmp_dp_clks_hw_get, qmp);
>> +       if (ret) {
>> +               dev_err(qmp->dev, "add provider fail ret:%d\n", ret);
>> +               return ret;
>> +       }
>> +
>> +       return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, dp_np);
>> +}
>> +
>>  static int qmp_usbc_probe(struct platform_device *pdev)
>>  {
>>         struct device *dev = &pdev->dev;
>>         struct phy_provider *phy_provider;
>>         struct device_node *np;
>>         struct qmp_usbc *qmp;
>> +       const struct dev_cfg *data_cfg;
>>         int ret;
>>
>>         qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL);
>> @@ -1050,38 +2034,74 @@ static int qmp_usbc_probe(struct platform_device *pdev)
>>                 return -ENOMEM;
>>
>>         qmp->dev = dev;
>> -       dev_set_drvdata(dev, qmp);
>>
>>         qmp->orientation = TYPEC_ORIENTATION_NORMAL;
>>
>> -       qmp->cfg = of_device_get_match_data(dev);
>> -       if (!qmp->cfg)
>> +       qmp->init_count = 0;
>> +
>> +       data_cfg = of_device_get_match_data(dev);
>> +       if (!data_cfg) {
>> +               dev_err(qmp->dev, "get data fail\n");
>>                 return -EINVAL;
>> +       }
>>
>>         mutex_init(&qmp->phy_mutex);
>>
>> -       ret = qmp_usbc_vreg_init(qmp);
>> -       if (ret)
>> -               return ret;
>> +       qmp->type = data_cfg->type;
>> +       qmp->cfg = data_cfg->cfg;
>>
>> -       ret = qmp_usbc_typec_switch_register(qmp);
>> -       if (ret)
>> +       ret = qmp_usbc_vreg_init(qmp);
>> +       if (ret) {
>> +               dev_err(qmp->dev, "qmp_type(%d) vreg init fail\n", qmp->type);
>>                 return ret;
>> +       }
>>
>> -       ret = qmp_usbc_parse_vls_clamp(qmp);
>> -       if (ret)
>> -               return ret;
>> +       if (qmp->type == QMP_PHY_USBC_USB) {
>> +               qmp->layout = devm_kzalloc(dev, sizeof(struct qmp_phy_usb_layout), GFP_KERNEL);
>> +               if (!qmp->layout)
>> +                       return -ENOMEM;
>> +
>> +               ret = qmp_usbc_typec_switch_register(qmp);
>> +               if (ret)
>> +                       return ret;
>> +
>> +               ret = qmp_usbc_parse_usb_vls_clamp(qmp);
>> +               if (ret)
>> +                       return ret;
>> +
>> +               /* Check for legacy binding with child node. */
>> +               np = of_get_child_by_name(dev->of_node, "phy");
>> +               if (np) {
>> +                       ret = qmp_usbc_parse_usb_dt_legacy(qmp, np);
>> +               } else {
>> +                       np = of_node_get(dev->of_node);
>> +                       ret = qmp_usbc_parse_usb_dt(qmp);
>> +               }
>> +               if (ret)
>> +                       goto err_node_put;
>> +       } else if (qmp->type == QMP_PHY_USBC_DP) {
>> +               qmp->layout = devm_kzalloc(dev, sizeof(struct qmp_phy_dp_layout), GFP_KERNEL);
>> +               if (!qmp->layout)
>> +                       return -ENOMEM;
>>
>> -       /* Check for legacy binding with child node. */
>> -       np = of_get_child_by_name(dev->of_node, "phy");
>> -       if (np) {
>> -               ret = qmp_usbc_parse_dt_legacy(qmp, np);
>> -       } else {
>>                 np = of_node_get(dev->of_node);
>> -               ret = qmp_usbc_parse_dt(qmp);
>> -       }
>> -       if (ret)
>> +               ret = qmp_usbc_parse_dp_phy_mode(qmp);
>> +               if (ret)
>> +                       goto err_node_put;
>> +
>> +               ret = qmp_usbc_parse_dp_dt(qmp);
>> +               if (ret)
>> +                       goto err_node_put;
>> +
>> +               ret = drm_aux_bridge_register(dev);
>> +               if (ret) {
>> +                       dev_err(qmp->dev, "aux bridge reg fail ret=%d\n", ret);
>> +                       goto err_node_put;
>> +               }
>> +       } else {
>> +               dev_err(dev, "invalid phy type: %d\n", qmp->type);
>>                 goto err_node_put;
>> +       }
>>
>>         pm_runtime_set_active(dev);
>>         ret = devm_pm_runtime_enable(dev);
>> @@ -1093,19 +2113,33 @@ static int qmp_usbc_probe(struct platform_device *pdev)
>>          */
>>         pm_runtime_forbid(dev);
>>
>> -       ret = phy_pipe_clk_register(qmp, np);
>> -       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);
>> -               dev_err(dev, "failed to create PHY: %d\n", ret);
>> -               goto err_node_put;
>> +       if (qmp->type == QMP_PHY_USBC_USB) {
>> +               // pipe clk process
>> +               ret = phy_pipe_clk_register(qmp, np);
>> +               if (ret)
>> +                       goto err_node_put;
>> +
>> +               qmp->phy = devm_phy_create(dev, np, &qmp_usbc_usb_phy_ops);
>> +               if (IS_ERR(qmp->phy)) {
>> +                       ret = PTR_ERR(qmp->phy);
>> +                       dev_err(dev, "failed to create PHY: %d\n", ret);
>> +                       goto err_node_put;
>> +               }
>> +       } else {
>> +               ret = qmp_dp_register_clocks(qmp, np);
>> +               if (ret)
>> +                       goto err_node_put;
>> +
>> +               qmp->phy = devm_phy_create(dev, np, &qmp_usbc_dp_phy_ops);
>> +               if (IS_ERR(qmp->phy)) {
>> +                       ret = PTR_ERR(qmp->phy);
>> +                       dev_err(dev, "failed to create PHY: %d\n", ret);
>> +                       goto err_node_put;
>> +               }
>>         }
>>
>>         phy_set_drvdata(qmp->phy, qmp);
>> -
>> +       dev_set_drvdata(dev, qmp);
>>         of_node_put(np);
>>
>>         phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
>> @@ -1120,19 +2154,38 @@ static int qmp_usbc_probe(struct platform_device *pdev)
>>  static const struct of_device_id qmp_usbc_of_match_table[] = {
>>         {
>>                 .compatible = "qcom,msm8998-qmp-usb3-phy",
>> -               .data = &msm8998_usb3phy_cfg,
>> +               .data =  &(struct dev_cfg) {
>> +                       .type = QMP_PHY_USBC_USB,
>> +                       .cfg = &msm8998_usb3phy_cfg,
>> +               },
>>         }, {
>>                 .compatible = "qcom,qcm2290-qmp-usb3-phy",
>> -               .data = &qcm2290_usb3phy_cfg,
>> +               .data =  &(struct dev_cfg) {
>> +                       .type = QMP_PHY_USBC_USB,
>> +                       .cfg = &qcm2290_usb3phy_cfg,
>> +               },
>> +       }, {
>> +               .compatible = "qcom,qcs615-qmp-dp-phy",
>> +               .data =  &(struct dev_cfg) {
>> +                       .type = QMP_PHY_USBC_DP,
>> +                       .cfg = &qcs615_dpphy_cfg,
>> +               },
>>         }, {
>>                 .compatible = "qcom,sdm660-qmp-usb3-phy",
>> -               .data = &sdm660_usb3phy_cfg,
>> +               .data =  &(struct dev_cfg) {
>> +                       .type = QMP_PHY_USBC_USB,
>> +                       .cfg = &sdm660_usb3phy_cfg,
>> +               },
>>         }, {
>>                 .compatible = "qcom,sm6115-qmp-usb3-phy",
>> -               .data = &qcm2290_usb3phy_cfg,
>> +               .data =  &(struct dev_cfg) {
>> +                       .type = QMP_PHY_USBC_USB,
>> +                       .cfg = &qcm2290_usb3phy_cfg,
>> +               },
>>         },
>>         { },
>>  };
>> +
>>  MODULE_DEVICE_TABLE(of, qmp_usbc_of_match_table);
>>
>>  static struct platform_driver qmp_usbc_driver = {
>>
>> --
>> 2.25.1
>>
> 
> 


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-12-05 13:26     ` Xiangxu Yin
@ 2024-12-05 18:31       ` Dmitry Baryshkov
  2024-12-10 15:09         ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-12-05 18:31 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Thu, Dec 05, 2024 at 09:26:47PM +0800, Xiangxu Yin wrote:
> 
> 
> On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
> > On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>
> >> Extended DP support for QCS615 USB or DP phy. Differentiated between
> >> USBC and DP PHY using the match table’s type, dynamically generating
> >> different types of cfg and layout attributes during initialization based
> >> on this type. Static variables are stored in cfg, while parsed values
> >> are organized into the layout structure.
> > 
> > We didn't have an understanding / conclusion whether
> > qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
> > or two PHYs being placed next to each other. Could you please start
> > your commit message by explaining it? Or even better, make that a part
> > of the cover letter for a new series touching just the USBC PHY
> > driver. DP changes don't have anything in common with the PHY changes,
> > so you can split the series into two.
> > 
> Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.

What is "DP extension"?

> 
> We identified that DP and USB share some common controls for phy_mode and orientation.
> Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
> while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
> It would be more efficient for a single driver to manage these controls. 

The question is about the hardware, not about the driver.

> Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
> Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
> we still decided to base it on the USBC extension.

Could you please clarify, do usb3-or-dp PHYs support DP-over-USB-C? I
thought that usbc-or-dp platforms support that, but they don't
support DP+USB pin configuration. Note, the question is broader than
just QCS615, it covers the PHY type itself.

Also, is TCSR configuration read/write or read-only? Are we supposed to
set the register from OS or are we supposed to read it and thus detemine
the PHY mode?

Anyway, judging on my understanding the platform configuration should
contain both USB and DP bits with the driver registering a single PHY
which supports switching between USB and DP (TCSR register is R/W) or
a single PHY which provides USBC or DP functionality depending on the
TCSR register contents (if it is R/O)

Andwhat is "USBC extension", BTW?

> >>
> >> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> >> ---
> >>  drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h |    1 +
> >>  drivers/phy/qualcomm/phy-qcom-qmp-usbc.c   | 1453 ++++++++++++++++++++++++----
> > 
> > Too many changes for a single patch. Please split into logical chunks.
> > 
> Ok.
> Once we have clarified the overall direction, 
> we can then discuss whether to split on current list or create a new list for the split.
> >>  2 files changed, 1254 insertions(+), 200 deletions(-)
> >>
> >> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h
> >> index 0ebd405bcaf0cac8215550bfc9b226f30cc43a59..59885616405f878885d0837838a0bac1899fb69f 100644
> >> --- a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h
> >> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h
> >> @@ -25,6 +25,7 @@
> >>  #define QSERDES_DP_PHY_AUX_CFG7                                0x03c
> >>  #define QSERDES_DP_PHY_AUX_CFG8                                0x040
> >>  #define QSERDES_DP_PHY_AUX_CFG9                                0x044
> >> +#define QSERDES_DP_PHY_VCO_DIV                         0x068
> >>
> >>  /* QSERDES COM_BIAS_EN_CLKBUFLR_EN bits */
> >>  # define QSERDES_V3_COM_BIAS_EN                                0x0001
> >> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
> >> index cf12a6f12134dc77ff032f967b2efa43e3de4b21..7fece9d7dc959ed5a7c62077d8552324c3734859 100644
> >> --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
> >> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
> >> @@ -22,13 +22,20 @@
> >>  #include <linux/slab.h>
> >>  #include <linux/usb/typec.h>
> >>  #include <linux/usb/typec_mux.h>
> >> +#include <dt-bindings/phy/phy-qcom-qmp.h>
> >> +#include <drm/bridge/aux-bridge.h>
> >>
> >>  #include "phy-qcom-qmp-common.h"
> >>
> >>  #include "phy-qcom-qmp.h"
> >>  #include "phy-qcom-qmp-pcs-misc-v3.h"
> >>
> >> +#include "phy-qcom-qmp-dp-phy.h"
> >> +#include "phy-qcom-qmp-dp-phy-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 {
> >> @@ -284,7 +291,26 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = {
> >>         QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88),
> >>  };
> >>
> >> -struct qmp_usbc_offsets {
> >> +enum qmp_phy_usbc_type {
> >> +       QMP_PHY_USBC_INVALID,
> > 
> > How can a type be invalid?
> > 
> I thought that platformdata must specify a type, so I set the default value to ‘invalid’.
> I will remove this in a future patch.
> >> +       QMP_PHY_USBC_USB,
> >> +       QMP_PHY_USBC_DP,
> >> +};
> >> +
> >> +/* list of regulators */
> >> +struct qmp_regulator_data {
> >> +       const char *name;
> >> +       unsigned int enable_load;
> >> +};
> >> +
> >> +struct dev_cfg {
> >> +       int type;
> >> +       const void *cfg;
> >> +};
> >> +
> >> +struct qmp_usbc;
> >> +
> >> +struct qmp_usbc_usb_offsets {
> >>         u16 serdes;
> >>         u16 pcs;
> >>         u16 pcs_misc;
> >> @@ -295,9 +321,9 @@ struct qmp_usbc_offsets {
> >>         u16 rx2;
> >>  };
> >>
> >> -/* struct qmp_phy_cfg - per-PHY initialization config */
> >> -struct qmp_phy_cfg {
> >> -       const struct qmp_usbc_offsets *offsets;
> >> +/* struct qmp_phy_usb_cfg - per-usb PHY initialization config */
> > 
> > what is "per-usb PHY"?
> > 
> Each usb phy in which defined in platform data.
> Shall I remove this annotation?

I don't know how to answer your question, I can not understand the
comment at all. First of all, it's USB not usb. Then, dropping "per"
makes that sound more logically.

> >> +struct qmp_phy_usb_cfg {
> >> +       const struct qmp_usbc_usb_offsets *offsets;
> >>
> >>         /* Init sequence for PHY blocks - serdes, tx, rx, pcs */
> >>         const struct qmp_phy_init_tbl *serdes_tbl;
> >> @@ -317,11 +343,7 @@ struct qmp_phy_cfg {
> >>         const unsigned int *regs;
> >>  };
> >>
> >> -struct qmp_usbc {
> >> -       struct device *dev;
> >> -
> >> -       const struct qmp_phy_cfg *cfg;
> >> -
> >> +struct qmp_phy_usb_layout {
> >>         void __iomem *serdes;
> >>         void __iomem *pcs;
> >>         void __iomem *pcs_misc;
> >> @@ -329,28 +351,67 @@ struct qmp_usbc {
> >>         void __iomem *rx;
> >>         void __iomem *tx2;
> >>         void __iomem *rx2;
> >> -
> >>         struct regmap *tcsr_map;
> >>         u32 vls_clamp_reg;
> >> -
> >> +       enum phy_mode mode;
> >> +       struct typec_switch_dev *sw;
> >>         struct clk *pipe_clk;
> >> +       struct clk_fixed_rate pipe_clk_fixed;
> >> +};
> >> +
> >> +struct qmp_usbc_dp_offsets {
> >> +       u16 dp_serdes;
> >> +       u16 dp_txa;
> >> +       u16 dp_txb;
> >> +       u16 dp_phy;
> >> +};
> >> +
> >> +/* struct qmp_phy_dp_cfg - per-dp PHY initialization config */

Likewise. There is no per-DP, because there are no multiple DP PHYs.
It's just a DP PHY config.

> >> +struct qmp_phy_dp_cfg {
> >> +       const struct qmp_usbc_dp_offsets *offsets;
> >> +
> >> +       /* DP PHY swing and pre_emphasis tables */
> >> +       const u8 (*swing_tbl)[4][4];
> >> +       const u8 (*pre_emphasis_tbl)[4][4];
> >> +
> >> +       // /* DP PHY callbacks */
> >> +       int (*dp_aux_init)(struct qmp_usbc *qmp);
> >> +       int (*configure_dp_serdes)(struct qmp_usbc *qmp);
> >> +       int (*configure_dp_voltages)(struct qmp_usbc *qmp);
> >> +       int (*configure_dp_phy)(struct qmp_usbc *qmp);
> >> +       int (*calibrate_dp_phy)(struct qmp_usbc *qmp);
> >> +
> >> +       const struct qmp_regulator_data *vreg_list;
> >> +       int num_vregs;
> >> +};
> >> +
> >> +struct qmp_phy_dp_layout {
> >> +       void __iomem *dp_phy;
> >> +       void __iomem *dp_tx;
> >> +       void __iomem *dp_tx2;
> >> +       void __iomem *dp_serdes;
> >> +       struct regmap *tcsr_map;
> >> +       u32 dp_phy_mode;
> >> +       unsigned int dp_aux_cfg;
> >> +       struct phy_configure_opts_dp dp_opts;
> >> +       struct clk_hw dp_link_hw;
> >> +       struct clk_hw dp_pixel_hw;
> >> +};
> >> +
> >> +struct qmp_usbc {
> >> +       struct device *dev;
> >> +       int type;
> >>         struct clk_bulk_data *clks;
> >>         int num_clks;
> >>         int num_resets;
> >>         struct reset_control_bulk_data *resets;
> >>         struct regulator_bulk_data *vregs;
> >> -
> >>         struct mutex phy_mutex;
> >> -
> >> -       enum phy_mode mode;
> >> -       unsigned int usb_init_count;
> >> -
> >>         struct phy *phy;
> >> -
> >> -       struct clk_fixed_rate pipe_clk_fixed;
> >> -
> >> -       struct typec_switch_dev *sw;
> >>         enum typec_orientation orientation;
> >> +       unsigned int init_count;
> >> +       const void *cfg;
> >> +       void *layout;
> > 
> > The patch contains a mixture of renames bundled with actual changes.
> > Please explain why old names are bad in a separate patch.
> > 
> Ok, The renaming is mainly to distinguish which structures are for USB or DP, which are fixed configurations, and which are dynamically parsed variables.
> After we clarify the overall direction, If still implement in usbc, 
> will seperate to below 4 patchsets.
> 1.renaming and structural adjustments for the USB driver
> 2.structure definitions for DP extension.
> 3.common callback functions for DP.
> 4.platform-related functions for DP.
> 
> >>  };
> >>
> >>  static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
> >> @@ -391,12 +452,21 @@ static const char * const usb3phy_reset_l[] = {
> >>         "phy_phy", "phy",
> >>  };
> >>
> >> +static const char * const dp_usb3phy_reset_l[] = {
> >> +       "phy",
> >> +};
> >> +
> >>  /* list of regulators */
> >> -static const char * const qmp_phy_vreg_l[] = {
> >> +static const char * const qmp_phy_usb_vreg_l[] = {
> >>         "vdda-phy", "vdda-pll",
> >>  };
> >>
> >> -static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {
> >> +static struct qmp_regulator_data qmp_phy_dp_vreg_l[] = {
> >> +       { .name = "vdda-phy", .enable_load = 21800 },
> >> +       { .name = "vdda-pll", .enable_load = 36000 },
> >> +};
> >> +
> >> +static const struct qmp_usbc_usb_offsets qmp_usbc_usb_offsets_v3_qcm2290 = {
> >>         .serdes         = 0x0,
> >>         .pcs            = 0xc00,
> >>         .pcs_misc       = 0xa00,
> >> @@ -406,8 +476,15 @@ static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {
> >>         .rx2            = 0x800,
> >>  };
> >>
> >> -static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
> >> -       .offsets                = &qmp_usbc_offsets_v3_qcm2290,
> >> +static const struct qmp_usbc_dp_offsets qmp_usbc_dp_offsets_qcs615 = {
> >> +       .dp_serdes      = 0x0C00,
> >> +       .dp_txa         = 0x0400,
> >> +       .dp_txb         = 0x0800,
> >> +       .dp_phy         = 0x0000,
> >> +};
> >> +
> >> +static const struct qmp_phy_usb_cfg msm8998_usb3phy_cfg = {
> >> +       .offsets                = &qmp_usbc_usb_offsets_v3_qcm2290,
> >>
> >>         .serdes_tbl             = msm8998_usb3_serdes_tbl,
> >>         .serdes_tbl_num         = ARRAY_SIZE(msm8998_usb3_serdes_tbl),
> >> @@ -417,13 +494,13 @@ 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_usb_vreg_l,
> >> +       .num_vregs              = ARRAY_SIZE(qmp_phy_usb_vreg_l),
> >>         .regs                   = qmp_v3_usb3phy_regs_layout,
> >>  };
> >>
> >> -static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = {
> >> -       .offsets                = &qmp_usbc_offsets_v3_qcm2290,
> >> +static const struct qmp_phy_usb_cfg qcm2290_usb3phy_cfg = {
> >> +       .offsets                = &qmp_usbc_usb_offsets_v3_qcm2290,
> >>
> >>         .serdes_tbl             = qcm2290_usb3_serdes_tbl,
> >>         .serdes_tbl_num         = ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
> >> @@ -433,13 +510,13 @@ 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_usb_vreg_l,
> >> +       .num_vregs              = ARRAY_SIZE(qmp_phy_usb_vreg_l),
> >>         .regs                   = qmp_v3_usb3phy_regs_layout_qcm2290,
> >>  };
> >>
> >> -static const struct qmp_phy_cfg sdm660_usb3phy_cfg = {
> >> -       .offsets                = &qmp_usbc_offsets_v3_qcm2290,
> >> +static const struct qmp_phy_usb_cfg sdm660_usb3phy_cfg = {
> >> +       .offsets                = &qmp_usbc_usb_offsets_v3_qcm2290,
> >>
> >>         .serdes_tbl             = qcm2290_usb3_serdes_tbl,
> >>         .serdes_tbl_num         = ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
> >> @@ -449,20 +526,352 @@ 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_usb_vreg_l,
> >> +       .num_vregs              = ARRAY_SIZE(qmp_phy_usb_vreg_l),
> >>         .regs                   = qmp_v3_usb3phy_regs_layout_qcm2290,
> >>  };
> >>
> >> -static int qmp_usbc_init(struct phy *phy)
> >> +static const u8 qmp_dp_pre_emphasis_hbr2_rbr[4][4] = {
> >> +       {0x00, 0x0B, 0x12, 0xFF},       /* pe0, 0 db */
> >> +       {0x00, 0x0A, 0x12, 0xFF},       /* pe1, 3.5 db */
> >> +       {0x00, 0x0C, 0xFF, 0xFF},       /* pe2, 6.0 db */
> >> +       {0xFF, 0xFF, 0xFF, 0xFF}        /* pe3, 9.5 db */
> >> +};
> >> +
> >> +static const u8 qmp_dp_voltage_swing_hbr2_rbr[4][4] = {
> >> +       {0x07, 0x0F, 0x14, 0xFF}, /* sw0, 0.4v  */
> >> +       {0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */
> >> +       {0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */
> >> +       {0xFF, 0xFF, 0xFF, 0xFF}  /* sw1, 1.2 v, optional */
> >> +};
> >> +
> >> +static int qcs615_qmp_dp_aux_init(struct qmp_usbc *qmp);
> >> +static int qcs615_qmp_configure_dp_serdes(struct qmp_usbc *qmp);
> >> +static int qcs615_qmp_configure_dp_voltages(struct qmp_usbc *qmp);
> >> +static int qcs615_qmp_configure_dp_phy(struct qmp_usbc *qmp);
> >> +static int qcs615_qmp_calibrate_dp_phy(struct qmp_usbc *qmp);
> > 
> > Are those functions really platform-specific?
> > 
> I mainly compared the driver of the combo PHY to identify reusable functions. 
> I extracted the dp_aux_init, configure_dp_phy and calibrate_dp_phy,
> and based on the differences in the flow of the HPG in the 14nm DP PHY, 
> I separated out the configure_dp_voltages and configure_dp_serdes functions.

Could you please answer the question that has been answered, not some
other random question?

> 
> Detailed explanation is provided in the following comment.
> >> +
> >> +static void qmp_usbc_check_dp_phy(struct qmp_usbc *qmp, const char *pos);
> >> +
> >> +static const struct qmp_phy_dp_cfg qcs615_dpphy_cfg = {
> >> +       .offsets                = &qmp_usbc_dp_offsets_qcs615,
> >> +
> >> +       .swing_tbl              = &qmp_dp_voltage_swing_hbr2_rbr,
> >> +       .pre_emphasis_tbl       = &qmp_dp_pre_emphasis_hbr2_rbr,
> >> +
> >> +       .dp_aux_init            = qcs615_qmp_dp_aux_init,
> >> +       .configure_dp_serdes    = qcs615_qmp_configure_dp_serdes,
> >> +       .configure_dp_voltages  = qcs615_qmp_configure_dp_voltages,
> >> +       .configure_dp_phy   = qcs615_qmp_configure_dp_phy,
> >> +       .calibrate_dp_phy       = qcs615_qmp_calibrate_dp_phy,
> >> +
> >> +       .vreg_list              = qmp_phy_dp_vreg_l,
> >> +       .num_vregs              = ARRAY_SIZE(qmp_phy_dp_vreg_l),
> >> +};
> >> +
> >> +#define to_usb_cfg(x) ((struct qmp_phy_usb_cfg *)(x->cfg))
> >> +#define to_dp_cfg(x) ((struct qmp_phy_dp_cfg *)(x->cfg))
> >> +#define to_usb_layout(x) ((struct qmp_phy_usb_layout *)(x->layout))
> >> +#define to_dp_layout(x) ((struct qmp_phy_dp_layout *)(x->layout))
> >> +
> >> +static int qcs615_qmp_dp_aux_init(struct qmp_usbc *qmp)
> >> +{
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +
> >> +       regmap_write(layout->tcsr_map, layout->dp_phy_mode, 0x1);
> >> +
> >> +       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,
> >> +              layout->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,
> >> +              layout->dp_phy + QSERDES_DP_PHY_PD_CTL);
> >> +
> >> +       writel(0x00, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG0);
> >> +       writel(0x13, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG1);
> >> +       writel(0x00, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG2);
> >> +       writel(0x00, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG3);
> >> +       writel(0x0a, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG4);
> >> +       writel(0x26, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG5);
> >> +       writel(0x0a, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG6);
> >> +       writel(0x03, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG7);
> >> +       writel(0xbb, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG8);
> >> +       writel(0x03, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG9);
> >> +       layout->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,
> >> +              layout->dp_phy + QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK);
> >> +       return 0;
> >> +}
> > 
> > We've had DP PHY implementation in QMP Combo PHY and in eDP PHY.
> > Please review them and work on extracting common bits into some kind
> > of a library. At least -combo and your -usbc implementation seem close
> > enough to warrant common library code.
> > 
> Initially, I intended to reference the register tables of combo. 
> However, I discovered some flow differences in the 14nm PHY, 
> So, I only kept the sw and pe tables, and the rest was implemented as functions.
> 
> 1.configure_dp_serdes: 
> The configuration of dp_serdes in the 14nm PHY is similar to that of eDP. 
> The configurations corresponding to RBR to HBR2 need to be set in the middle of the dp_serdes.
> Therefore, I didn’t split it into five tables, but instead referenced the eDP implementation such like com_configure_pll.

Usually there is no difference in the order of SERDES register writes
between power down and power up.

> 
> 2.configure_dp_voltages:
> 14nm DP phy have only one pair of reference swing table and pre_emphasis_tbl.
> Similar implement with combo V3.
> 
> 3.configure_dp_phy & power_on:
> This PHY requires alternating configurations among the dp_phy, dp_serdes, and dp_tx, dp_tx2 register groups,
> which makes grouped configuration less convenient.

I don't think I follow the comment.

> >> +
> >> +static int qcs615_qmp_configure_dp_serdes(struct qmp_usbc *qmp)
> >> +{
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +       void __iomem *serdes = layout->dp_serdes;
> >> +       const struct phy_configure_opts_dp *dp_opts = &layout->dp_opts;
> >> +       u8 hsclk_sel;
> >> +       u8 dec_start_mode0;
> >> +       u8 div_frac_start1_mode0;
> >> +       u8 div_frac_start2_mode0;
> >> +       u8 div_frac_start3_mode0;
> >> +       u8 lock_cmp1_mode0;
> >> +       u8 lock_cmp2_mode0;
> >> +       u8 lock_cmp3_mode0;
> >> +
> >> +       switch (dp_opts->link_rate) {
> >> +       case 1620:
> >> +               hsclk_sel = 0x2c;
> >> +               dec_start_mode0 = 0x69;
> >> +               div_frac_start1_mode0 = 0x00;
> >> +               div_frac_start2_mode0 = 0x80;
> >> +               div_frac_start3_mode0 = 0x07;
> >> +               lock_cmp1_mode0 = 0xbf;
> >> +               lock_cmp2_mode0 = 0x21;
> >> +               lock_cmp3_mode0 = 0x00;
> >> +               break;
> >> +       case 2700:
> >> +               hsclk_sel = 0x24;
> >> +               dec_start_mode0 = 0x69;
> >> +               div_frac_start1_mode0 = 0x00;
> >> +               div_frac_start2_mode0 = 0x80;
> >> +               div_frac_start3_mode0 = 0x07;
> >> +               lock_cmp1_mode0 = 0x3f;
> >> +               lock_cmp2_mode0 = 0x38;
> >> +               lock_cmp3_mode0 = 0x00;
> >> +               break;
> >> +       case 5400:
> >> +               hsclk_sel = 0x20;
> >> +               dec_start_mode0 = 0x8c;
> >> +               div_frac_start1_mode0 = 0x00;
> >> +               div_frac_start2_mode0 = 0x00;
> >> +               div_frac_start3_mode0 = 0x0a;
> >> +               lock_cmp1_mode0 = 0x7f;
> >> +               lock_cmp2_mode0 = 0x70;
> >> +               lock_cmp3_mode0 = 0x00;
> >> +               break;
> >> +       default:
> >> +               /* Other link rates aren't supported */
> >> +               return -EINVAL;
> >> +       }
> >> +
> >> +       writel(0x01, serdes + QSERDES_COM_SVS_MODE_CLK_SEL);
> >> +       writel(0x37, serdes + QSERDES_COM_SYSCLK_EN_SEL);
> >> +       writel(0x00, serdes + QSERDES_COM_CLK_SELECT);
> >> +       writel(0x06, serdes + QSERDES_COM_SYS_CLK_CTRL);
> >> +       writel(0x3f, serdes + QSERDES_COM_BIAS_EN_CLKBUFLR_EN);
> >> +       writel(0x0e, serdes + QSERDES_COM_CLK_ENABLE1);
> >> +       writel(0x0f, serdes + QSERDES_COM_BG_CTRL);
> >> +       writel(0x06, serdes + QSERDES_COM_SYSCLK_BUF_ENABLE);
> >> +       writel(0x30, serdes + QSERDES_COM_CLK_SELECT);
> >> +       writel(0x0f, serdes + QSERDES_COM_PLL_IVCO);
> >> +       writel(0x28, serdes + QSERDES_COM_PLL_CCTRL_MODE0);
> >> +       writel(0x16, serdes + QSERDES_COM_PLL_RCTRL_MODE0);
> >> +       writel(0x0b, serdes + QSERDES_COM_CP_CTRL_MODE0);
> >> +
> >> +       writel(hsclk_sel, serdes + QSERDES_COM_HSCLK_SEL);
> >> +       writel(dec_start_mode0, serdes + QSERDES_COM_DEC_START_MODE0);
> >> +       writel(div_frac_start1_mode0, serdes + QSERDES_COM_DIV_FRAC_START1_MODE0);
> >> +       writel(div_frac_start2_mode0, serdes + QSERDES_COM_DIV_FRAC_START2_MODE0);
> >> +       writel(div_frac_start3_mode0, serdes + QSERDES_COM_DIV_FRAC_START3_MODE0);
> >> +       writel(lock_cmp1_mode0, serdes + QSERDES_COM_LOCK_CMP1_MODE0);
> >> +       writel(lock_cmp2_mode0, serdes + QSERDES_COM_LOCK_CMP2_MODE0);
> >> +       writel(lock_cmp3_mode0, serdes + QSERDES_COM_LOCK_CMP3_MODE0);
> >> +
> >> +       writel(0x40, serdes + QSERDES_COM_INTEGLOOP_GAIN0_MODE0);
> >> +       writel(0x00, serdes + QSERDES_COM_INTEGLOOP_GAIN1_MODE0);
> >> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE_MAP);
> >> +       writel(0x08, serdes + QSERDES_COM_BG_TIMER);
> >> +       writel(0x05, serdes + QSERDES_COM_CORECLK_DIV);
> >> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE_CTRL);
> >> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE1_MODE0);
> >> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE2_MODE0);
> >> +       writel(0x00, serdes + QSERDES_COM_VCO_TUNE_CTRL);
> >> +
> >> +       writel(0x0f, serdes + QSERDES_COM_CORE_CLK_EN);
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int qcs615_qmp_configure_dp_voltages(struct qmp_usbc *qmp)
> >> +{
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +       struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> >> +       const struct phy_configure_opts_dp *dp_opts = &layout->dp_opts;
> >> +       void __iomem *tx = layout->dp_tx;
> >> +       void __iomem *tx2 = layout->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) || (pre_emphasis_cfg > 4)) {
> >> +               dev_err(qmp->dev, "Invalid v(%d) | p(%d) level)\n",
> >> +                       v_level, pre_emphasis_cfg);
> >> +               return -EINVAL;
> >> +       }
> >> +
> >> +       voltage_swing_cfg = (*cfg->swing_tbl)[v_level][p_level];
> >> +       pre_emphasis_cfg = (*cfg->pre_emphasis_tbl)[v_level][p_level];
> >> +
> >> +       /* Enable MUX to use Cursor values from these registers */
> >> +       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;
> >> +
> >> +       /* program default setting first */
> >> +       writel(0x2A, tx + QSERDES_V3_TX_TX_DRV_LVL);
> >> +       writel(0x20, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> >> +       writel(0x2A, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
> >> +       writel(0x20, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> > 
> > Lowercase all hex numbers.
> > 
> Ok, will update in next patch.
> >> +
> >> +       writel(voltage_swing_cfg, tx + QSERDES_V3_TX_TX_DRV_LVL);
> >> +       writel(pre_emphasis_cfg, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> >> +       writel(voltage_swing_cfg, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
> >> +       writel(pre_emphasis_cfg, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int qcs615_qmp_configure_dp_phy(struct qmp_usbc *qmp)
> >> +{
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +       u32 status;
> >> +
> >> +       writel(0x01, layout->dp_phy + QSERDES_DP_PHY_CFG);
> >> +       writel(0x05, layout->dp_phy + QSERDES_DP_PHY_CFG);
> >> +       writel(0x01, layout->dp_phy + QSERDES_DP_PHY_CFG);
> >> +       writel(0x09, layout->dp_phy + QSERDES_DP_PHY_CFG);
> >> +
> >> +       writel(0x20, layout->dp_serdes + QSERDES_COM_RESETSM_CNTRL);
> >> +
> >> +       // C_READY
> >> +       if (readl_poll_timeout(layout->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;
> >> +       }
> >> +
> >> +       // FREQ_DONE
> >> +       if (readl_poll_timeout(layout->dp_serdes + QSERDES_COM_CMN_STATUS,
> >> +                       status,
> >> +                       ((status & BIT(0)) > 0),
> >> +                       500,
> >> +                       10000)){
> >> +               dev_err(qmp->dev, "FREQ_DONE not ready\n");
> >> +               return -ETIMEDOUT;
> >> +       }
> >> +
> >> +       // PLL_LOCKED
> >> +       if (readl_poll_timeout(layout->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, layout->dp_phy + QSERDES_DP_PHY_CFG);
> >> +       udelay(10);
> >> +
> >> +       // TSYNC_DONE
> >> +       if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS,
> >> +                       status,
> >> +                       ((status & BIT(0)) > 0),
> >> +                       500,
> >> +                       10000)){
> >> +               dev_err(qmp->dev, "TSYNC_DONE not ready\n");
> >> +               return -ETIMEDOUT;
> >> +       }
> >> +
> >> +       // PHY_READY
> >> +       if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS,
> >> +                       status,
> >> +                       ((status & BIT(1)) > 0),
> >> +                       500,
> >> +                       10000)){
> >> +               dev_err(qmp->dev, "PHY_READY not ready\n");
> >> +               return -ETIMEDOUT;
> >> +       }
> >> +
> >> +       writel(0x3f, layout->dp_tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
> >> +       writel(0x10, layout->dp_tx + QSERDES_V3_TX_HIGHZ_DRVR_EN);
> >> +       writel(0x0a, layout->dp_tx + QSERDES_V3_TX_TX_POL_INV);
> >> +       writel(0x3f, layout->dp_tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
> >> +       writel(0x10, layout->dp_tx2 + QSERDES_V3_TX_HIGHZ_DRVR_EN);
> >> +       writel(0x0a, layout->dp_tx2 + QSERDES_V3_TX_TX_POL_INV);
> >> +
> >> +       writel(0x18, layout->dp_phy + QSERDES_DP_PHY_CFG);
> >> +       writel(0x19, layout->dp_phy + QSERDES_DP_PHY_CFG);
> >> +
> >> +       if (readl_poll_timeout(layout->dp_phy + QSERDES_V3_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 qcs615_qmp_calibrate_dp_phy(struct qmp_usbc *qmp)
> >> +{
> >> +       static const u8 cfg1_settings[] = {0x13, 0x23, 0x1d};
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +       u8 val;
> >> +
> >> +       layout->dp_aux_cfg++;
> >> +       layout->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
> >> +       val = cfg1_settings[layout->dp_aux_cfg];
> >> +
> >> +       writel(val, layout->dp_phy + QSERDES_DP_PHY_AUX_CFG1);
> >> +
> >> +       qmp_usbc_check_dp_phy(qmp, "pos_calibrate");
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +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;
> >> +       int num_vregs;
> >>         u32 val = 0;
> >>         int ret;
> >> +       unsigned int reg_pwr_dn;
> >>
> >> -       ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
> >> +       if (qmp->type == QMP_PHY_USBC_USB) {
> >> +               struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> >> +
> >> +               num_vregs = cfg->num_vregs;
> >> +               reg_pwr_dn = cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL];
> >> +       } else {
> >> +               struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> >> +
> >> +               num_vregs = cfg->num_vregs;
> >> +       }
> >> +
> >> +       ret = regulator_bulk_enable(num_vregs, qmp->vregs);
> >>         if (ret) {
> >>                 dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
> >>                 return ret;
> >> @@ -484,73 +893,85 @@ static int qmp_usbc_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);
> >> +
> >> +       if (qmp->type == QMP_PHY_USBC_USB) {
> > 
> > Why?
> > 
> On QCS615 ADP AIR platform, Type-C DP orientation is fixed in one direction due to connected to the external video-out expansion board through the expansion slot.
> Therefore, we cannot validate DP orientation behaviour. 
> As a result, the orientation part remains consistent with the original implementation of the USB-C driver and only applies to USB devices.

1) You've also put SW_PWRDN under the if(). If that's intended, please
explain, why.

2) I don't get the DP orientation part. You've wrote that there is no DP
AltMode support. What is DP orientation in such a case? If the SoC
supports swapping lanes 0/1 vs 2/3, then just keep the register write
here.

> >> +               struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >> +
> >> +               qphy_setbits(layout->pcs, reg_pwr_dn, SW_PWRDN);
> >> +               writel(val, layout->pcs_misc);
> >> +       }
> >>
> >>         return 0;
> >>
> >>  err_assert_reset:
> >>         reset_control_bulk_assert(qmp->num_resets, qmp->resets);
> >>  err_disable_regulators:
> >> -       regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
> >> +       regulator_bulk_disable(num_vregs, qmp->vregs);
> >>
> >>         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;
> >> +       int num_vregs;
> >>
> >>         reset_control_bulk_assert(qmp->num_resets, qmp->resets);
> >>
> >>         clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
> >>
> >> -       regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
> >> +       if (qmp->type == QMP_PHY_USBC_USB) {
> >> +               struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> >> +
> >> +               num_vregs = cfg->num_vregs;
> >> +       } else {
> >> +               struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> >> +
> >> +               num_vregs = cfg->num_vregs;
> >> +       }
> >> +       regulator_bulk_disable(num_vregs, qmp->vregs);
> >>
> >>         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;
> >> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> >> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >>         void __iomem *status;
> >>         unsigned int val;
> >>         int ret;
> >>
> >> -       qmp_configure(qmp->dev, qmp->serdes, cfg->serdes_tbl,
> >> +       qmp_configure(qmp->dev, layout->serdes, cfg->serdes_tbl,
> >>                       cfg->serdes_tbl_num);
> >>
> >> -       ret = clk_prepare_enable(qmp->pipe_clk);
> >> +       ret = clk_prepare_enable(layout->pipe_clk);
> >>         if (ret) {
> >>                 dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret);
> >>                 return ret;
> >>         }
> >>
> >>         /* Tx, Rx, and PCS configurations */
> >> -       qmp_configure_lane(qmp->dev, qmp->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
> >> -       qmp_configure_lane(qmp->dev, qmp->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
> >> +       qmp_configure_lane(qmp->dev, layout->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
> >> +       qmp_configure_lane(qmp->dev, layout->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
> >>
> >> -       qmp_configure_lane(qmp->dev, qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);
> >> -       qmp_configure_lane(qmp->dev, qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
> >> +       qmp_configure_lane(qmp->dev, layout->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);
> >> +       qmp_configure_lane(qmp->dev, layout->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
> >>
> >> -       qmp_configure(qmp->dev, qmp->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
> >> +       qmp_configure(qmp->dev, layout->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
> >>
> >>         /* Pull PHY out of reset state */
> >> -       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
> >> +       qphy_clrbits(layout->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
> >>
> >>         /* start SerDes and Phy-Coding-Sublayer */
> >> -       qphy_setbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START);
> >> +       qphy_setbits(layout->pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START);
> >>
> >> -       status = qmp->pcs + cfg->regs[QPHY_PCS_STATUS];
> >> +       status = layout->pcs + cfg->regs[QPHY_PCS_STATUS];
> >>         ret = readl_poll_timeout(status, val, !(val & PHYSTATUS), 200,
> >>                                  PHY_INIT_COMPLETE_TIMEOUT);
> >>         if (ret) {
> >> @@ -561,92 +982,348 @@ static int qmp_usbc_power_on(struct phy *phy)
> >>         return 0;
> >>
> >>  err_disable_pipe_clk:
> >> -       clk_disable_unprepare(qmp->pipe_clk);
> >> +       clk_disable_unprepare(layout->pipe_clk);
> >>
> >>         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;
> >> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> >> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >>
> >> -       clk_disable_unprepare(qmp->pipe_clk);
> >> +       clk_disable_unprepare(layout->pipe_clk);
> >>
> >>         /* PHY reset */
> >> -       qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
> >> +       qphy_setbits(layout->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
> >>
> >>         /* stop SerDes and Phy-Coding-Sublayer */
> >> -       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL],
> >> +       qphy_clrbits(layout->pcs, cfg->regs[QPHY_START_CTRL],
> >>                         SERDES_START | PCS_START);
> >>
> >>         /* Put PHY into POWER DOWN state: active low */
> >> -       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
> >> +       qphy_clrbits(layout->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
> >>                         SW_PWRDN);
> >>
> >>         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;
> >>         }
> >>
> >> -       qmp->usb_init_count++;
> >> +       qmp->init_count++;
> >>  out_unlock:
> >>         mutex_unlock(&qmp->phy_mutex);
> >>
> >>         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);
> >> +       qmp->init_count--;
> >> +       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_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode)
> >> +{
> >> +       struct qmp_usbc *qmp = phy_get_drvdata(phy);
> >> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >> +
> >> +       layout->mode = mode;
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int qmp_usbc_dp_init(struct phy *phy)
> >> +{
> >> +       struct qmp_usbc *qmp = phy_get_drvdata(phy);
> >> +       const struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> >> +       int ret;
> >> +
> >> +       if (qmp->init_count) {
> >> +               dev_err(qmp->dev, "type(%d) inited(%d)\n", qmp->type, qmp->init_count);
> >> +               return 0;
> >> +       }
> >> +
> >> +       mutex_lock(&qmp->phy_mutex);
> >> +
> >> +       ret = qmp_usbc_com_init(phy);
> >> +       if (ret) {
> >> +               dev_err(qmp->dev, "type(%d) com_init fail\n", qmp->type);
> >> +               goto dp_init_unlock;
> >> +       }
> >> +
> >> +       cfg->dp_aux_init(qmp);
> >> +
> >> +       qmp->init_count++;
> >> +
> >> +dp_init_unlock:
> >> +       mutex_unlock(&qmp->phy_mutex);
> >> +       return ret;
> >> +}
> >> +
> >> +static int qmp_usbc_dp_exit(struct phy *phy)
> >> +{
> >> +       struct qmp_usbc *qmp = phy_get_drvdata(phy);
> >> +
> >> +       mutex_lock(&qmp->phy_mutex);
> >> +
> >> +       qmp_usbc_com_exit(phy);
> >> +
> >> +       qmp->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);
> >> +       struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +       int ret;
> >> +
> >> +       mutex_lock(&qmp->phy_mutex);
> >> +
> >> +       memcpy(&layout->dp_opts, dp_opts, sizeof(*dp_opts));
> >> +       if (layout->dp_opts.set_voltages) {
> >> +               ret = cfg->configure_dp_voltages(qmp);
> >> +               if (ret) {
> >> +                       dev_err(qmp->dev, "type(%d) err(%d)\n", qmp->type, ret);
> >> +                       mutex_unlock(&qmp->phy_mutex);
> >> +                       return ret;
> >> +               }
> >> +
> >> +               layout->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);
> >> +       struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> >> +       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, "type(%d) err(%d)\n", qmp->type, ret);
> >> +                       mutex_unlock(&qmp->phy_mutex);
> >> +                       return ret;
> >> +               }
> >> +       }
> >> +
> >> +       mutex_unlock(&qmp->phy_mutex);
> >> +       return 0;
> >>  }
> >>
> >> -static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode)
> >> +static int qmp_usbc_configure_dp_clocks(struct qmp_usbc *qmp)
> >> +{
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +       const struct phy_configure_opts_dp *dp_opts = &layout->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;
> >> +       case 8100:
> >> +               phy_vco_div = 0x0;
> >> +               pixel_freq = 8100000000UL / 6;
> >> +               break;
> >> +       default:
> >> +               /* Other link rates aren't supported */
> >> +               return -EINVAL;
> >> +       }
> >> +       writel(phy_vco_div, layout->dp_phy + QSERDES_DP_PHY_VCO_DIV);
> >> +
> >> +       clk_set_rate(layout->dp_link_hw.clk, dp_opts->link_rate * 100000);
> >> +       clk_set_rate(layout->dp_pixel_hw.clk, pixel_freq);
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static void qmp_usbc_check_dp_phy(struct qmp_usbc *qmp, const char *pos)
> >> +{
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +       u8 c_ready, cmn_status, phy_status;
> >> +
> >> +       c_ready = readl(layout->dp_serdes + QSERDES_COM_C_READY_STATUS);
> >> +       cmn_status = readl(layout->dp_serdes + QSERDES_COM_CMN_STATUS);
> >> +       phy_status = readl(layout->dp_phy + QSERDES_V3_DP_PHY_STATUS);
> >> +
> >> +       dev_dbg(qmp->dev, "pos(%s) c_ready(0x%x) cmn_status(0x%x) phy_status(0x%x)\n",
> >> +               pos, c_ready, cmn_status, phy_status);
> >> +}
> >> +
> >> +static int qmp_usbc_dp_power_on(struct phy *phy)
> >> +{
> >> +       struct qmp_usbc *qmp = phy_get_drvdata(phy);
> >> +       const struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +       const struct phy_configure_opts_dp *dp_opts = &layout->dp_opts;
> >> +       bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
> >> +       void __iomem *tx = layout->dp_tx;
> >> +       void __iomem *tx2 = layout->dp_tx2;
> >> +       u8 lane_mode_1;
> >> +       int ret = 0;
> >> +
> >> +       mutex_lock(&qmp->phy_mutex);
> >> +
> >> +       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,
> >> +               layout->dp_phy + QSERDES_DP_PHY_PD_CTL);
> >> +
> >> +       ret = cfg->configure_dp_serdes(qmp);
> >> +       if (ret) {
> >> +               dev_err(qmp->dev, "failed to config pll\n");
> >> +               goto power_on_unlock;
> >> +       }
> >> +
> >> +       if (dp_opts->link_rate >= 2700)
> >> +               lane_mode_1 = 0xc4;
> >> +       else
> >> +               lane_mode_1 = 0xc6;
> >> +
> >> +       writel(lane_mode_1, tx + QSERDES_V3_TX_LANE_MODE_1);
> >> +       writel(lane_mode_1, tx2 + QSERDES_V3_TX_LANE_MODE_1);
> >> +
> >> +       if (reverse)
> >> +               writel(0xc9, layout->dp_phy + QSERDES_DP_PHY_MODE);
> >> +       else
> >> +               writel(0xd9, layout->dp_phy + QSERDES_DP_PHY_MODE);
> >> +
> >> +       writel(0x05, layout->dp_phy + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL);
> >> +       writel(0x05, layout->dp_phy + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL);
> >> +
> >> +       writel(0x1a, tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
> >> +       writel(0x40, tx + QSERDES_V3_TX_VMODE_CTRL1);
> >> +       writel(0x30, tx + QSERDES_V3_TX_PRE_STALL_LDO_BOOST_EN);
> >> +       writel(0x3d, tx + QSERDES_V3_TX_INTERFACE_SELECT);
> >> +       writel(0x0f, tx + QSERDES_V3_TX_CLKBUF_ENABLE);
> >> +       writel(0x03, tx + QSERDES_V3_TX_RESET_TSYNC_EN);
> >> +       writel(0x03, tx + QSERDES_V3_TX_TRAN_DRVR_EMP_EN);
> >> +       writel(0x00, tx + QSERDES_V3_TX_PARRATE_REC_DETECT_IDLE_EN);
> >> +       writel(0x00, tx + QSERDES_V3_TX_TX_INTERFACE_MODE);
> >> +       writel(0x2b, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> >> +       writel(0x2f, tx + QSERDES_V3_TX_TX_DRV_LVL);
> >> +       writel(0x04, tx + QSERDES_V3_TX_TX_BAND);
> >> +       writel(0x12, tx + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX);
> >> +       writel(0x12, tx + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX);
> >> +
> >> +       writel(0x1a, tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
> >> +       writel(0x40, tx2 + QSERDES_V3_TX_VMODE_CTRL1);
> >> +       writel(0x30, tx2 + QSERDES_V3_TX_PRE_STALL_LDO_BOOST_EN);
> >> +       writel(0x3d, tx2 + QSERDES_V3_TX_INTERFACE_SELECT);
> >> +       writel(0x0f, tx2 + QSERDES_V3_TX_CLKBUF_ENABLE);
> >> +       writel(0x03, tx2 + QSERDES_V3_TX_RESET_TSYNC_EN);
> >> +       writel(0x03, tx2 + QSERDES_V3_TX_TRAN_DRVR_EMP_EN);
> >> +       writel(0x00, tx2 + QSERDES_V3_TX_PARRATE_REC_DETECT_IDLE_EN);
> >> +       writel(0x00, tx2 + QSERDES_V3_TX_TX_INTERFACE_MODE);
> >> +       writel(0x2b, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
> >> +       writel(0x2f, tx2 + QSERDES_V3_TX_TX_DRV_LVL);
> >> +       writel(0x04, tx2 + QSERDES_V3_TX_TX_BAND);
> >> +       writel(0x12, tx2 + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX);
> >> +       writel(0x12, tx2 + QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX);
> >> +
> >> +       writel(0x02, layout->dp_serdes + QSERDES_COM_CMN_CONFIG);
> >> +       qmp_usbc_configure_dp_clocks(qmp);
> >> +
> >> +       ret = cfg->configure_dp_phy(qmp);
> >> +       if (ret) {
> >> +               dev_err(qmp->dev, "failed to config dp phy\n");
> >> +               goto power_on_unlock;
> >> +       }
> >> +
> >> +       qmp_usbc_check_dp_phy(qmp, "usbc_dp_power_on_finish");
> >> +
> >> +power_on_unlock:
> >> +       mutex_unlock(&qmp->phy_mutex);
> >> +
> >> +       return ret;
> >> +}
> >> +
> >> +static int qmp_usbc_dp_power_off(struct phy *phy)
> >>  {
> >>         struct qmp_usbc *qmp = phy_get_drvdata(phy);
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +
> >> +       mutex_lock(&qmp->phy_mutex);
> >>
> >> -       qmp->mode = mode;
> >> +       /* Assert DP PHY power down */
> >> +       writel(DP_PHY_PD_CTL_PSR_PWRDN, layout->dp_phy + QSERDES_DP_PHY_PD_CTL);
> >> +
> >> +       mutex_unlock(&qmp->phy_mutex);
> >>
> >>         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,
> >> +};
> >> +
> >> +static const struct phy_ops qmp_usbc_dp_phy_ops = {
> >> +       .init           = qmp_usbc_dp_init,
> >> +       .exit           = qmp_usbc_dp_exit,
> >> +       .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;
> >> -       void __iomem *pcs = qmp->pcs;
> >> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> >> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >> +       void __iomem *pcs = layout->pcs;
> >>         u32 intr_mask;
> >>
> >> -       if (qmp->mode == PHY_MODE_USB_HOST_SS ||
> >> -           qmp->mode == PHY_MODE_USB_DEVICE_SS)
> >> +       if (layout->mode == PHY_MODE_USB_HOST_SS ||
> >> +           layout->mode == PHY_MODE_USB_DEVICE_SS)
> >>                 intr_mask = ARCVR_DTCT_EN | ALFPS_DTCT_EN;
> >>         else
> >>                 intr_mask = ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL;
> >> @@ -663,18 +1340,19 @@ static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp)
> >>         qphy_setbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask);
> >>
> >>         /* Enable i/o clamp_n for autonomous mode */
> >> -       if (qmp->tcsr_map && qmp->vls_clamp_reg)
> >> -               regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 1);
> >> +       if (layout->tcsr_map && layout->vls_clamp_reg)
> >> +               regmap_write(layout->tcsr_map, layout->vls_clamp_reg, 1);
> >>  }
> >>
> >>  static void qmp_usbc_disable_autonomous_mode(struct qmp_usbc *qmp)
> >>  {
> >> -       const struct qmp_phy_cfg *cfg = qmp->cfg;
> >> -       void __iomem *pcs = qmp->pcs;
> >> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> >> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >> +       void __iomem *pcs = layout->pcs;
> >>
> >>         /* Disable i/o clamp_n on resume for normal mode */
> >> -       if (qmp->tcsr_map && qmp->vls_clamp_reg)
> >> -               regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 0);
> >> +       if (layout->tcsr_map && layout->vls_clamp_reg)
> >> +               regmap_write(layout->tcsr_map, layout->vls_clamp_reg, 0);
> >>
> >>         qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL],
> >>                      ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL | ALFPS_DTCT_EN);
> >> @@ -688,16 +1366,19 @@ static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev)
> >>  {
> >>         struct qmp_usbc *qmp = dev_get_drvdata(dev);
> >>
> >> -       dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode);
> >> -
> >>         if (!qmp->phy->init_count) {
> >>                 dev_vdbg(dev, "PHY not initialized, bailing out\n");
> >>                 return 0;
> >>         }
> >>
> >> -       qmp_usbc_enable_autonomous_mode(qmp);
> >> +       if (qmp->type == QMP_PHY_USBC_USB) {
> >> +               struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >> +
> >> +               dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", layout->mode);
> >> +               qmp_usbc_enable_autonomous_mode(qmp);
> >> +               clk_disable_unprepare(layout->pipe_clk);
> >> +       }
> >>
> >> -       clk_disable_unprepare(qmp->pipe_clk);
> >>         clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
> >>
> >>         return 0;
> >> @@ -708,8 +1389,6 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev)
> >>         struct qmp_usbc *qmp = dev_get_drvdata(dev);
> >>         int ret = 0;
> >>
> >> -       dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode);
> >> -
> >>         if (!qmp->phy->init_count) {
> >>                 dev_vdbg(dev, "PHY not initialized, bailing out\n");
> >>                 return 0;
> >> @@ -719,14 +1398,19 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev)
> >>         if (ret)
> >>                 return ret;
> >>
> >> -       ret = clk_prepare_enable(qmp->pipe_clk);
> >> -       if (ret) {
> >> -               dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);
> >> -               clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
> >> -               return ret;
> >> -       }
> >> +       if (qmp->type == QMP_PHY_USBC_USB) {
> >> +               struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >>
> >> -       qmp_usbc_disable_autonomous_mode(qmp);
> >> +               dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", layout->mode);
> >> +               ret = clk_prepare_enable(layout->pipe_clk);
> >> +               if (ret) {
> >> +                       dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);
> >> +                       clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
> >> +                       return ret;
> >> +               }
> >> +
> >> +               qmp_usbc_disable_autonomous_mode(qmp);
> >> +       }
> >>
> >>         return 0;
> >>  }
> >> @@ -738,19 +1422,54 @@ static const struct dev_pm_ops qmp_usbc_pm_ops = {
> >>
> >>  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;
> >> +       int ret, i;
> >>
> >> -       qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL);
> >> -       if (!qmp->vregs)
> >> -               return -ENOMEM;
> >> +       if (qmp->type == QMP_PHY_USBC_USB) {
> >> +               struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> >> +               int num = cfg->num_vregs;
> >>
> >> -       for (i = 0; i < num; i++)
> >> -               qmp->vregs[i].supply = cfg->vreg_list[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);
> >> +               ret = devm_regulator_bulk_get(dev, num, qmp->vregs);
> >> +               if (ret) {
> >> +                       dev_err(dev, "failed at devm_regulator_bulk_get\n");
> >> +                       return ret;
> >> +               }
> >> +       } else {
> >> +               struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> >> +               int num = cfg->num_vregs;
> >> +
> >> +               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].name;
> >> +
> >> +               ret = devm_regulator_bulk_get(dev, num, qmp->vregs);
> >> +               if (ret) {
> >> +                       dev_err(dev, "failed at devm_regulator_bulk_get\n");
> >> +                       return ret;
> >> +               }
> >> +
> >> +               for (i = 0; i < num; i++) {
> >> +                       ret = regulator_set_load(qmp->vregs[i].consumer,
> >> +                                               cfg->vreg_list[i].enable_load);
> >> +                       if (ret) {
> >> +                               dev_err(dev, "failed to set load at %s\n",
> >> +                                       qmp->vregs[i].supply);
> >> +                               return ret;
> >> +                       }
> >> +               }
> >> +       }
> >> +
> >> +       return 0;
> >>  }
> >>
> >>  static int qmp_usbc_reset_init(struct qmp_usbc *qmp,
> >> @@ -821,7 +1540,9 @@ static void phy_clk_release_provider(void *res)
> >>   */
> >>  static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np)
> >>  {
> >> -       struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed;
> >> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >> +
> >> +       struct clk_fixed_rate *fixed = &layout->pipe_clk_fixed;
> >>         struct clk_init_data init = { };
> >>         int ret;
> >>
> >> @@ -864,12 +1585,12 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw,
> >>         mutex_lock(&qmp->phy_mutex);
> >>         qmp->orientation = orientation;
> >>
> >> -       if (qmp->usb_init_count) {
> >> -               qmp_usbc_power_off(qmp->phy);
> >> -               qmp_usbc_exit(qmp->phy);
> >> +       if (qmp->init_count) {
> >> +               qmp_usbc_usb_power_off(qmp->phy);
> >> +               qmp_usbc_com_exit(qmp->phy);
> >>
> >> -               qmp_usbc_init(qmp->phy);
> >> -               qmp_usbc_power_on(qmp->phy);
> >> +               qmp_usbc_com_init(qmp->phy);
> >> +               qmp_usbc_usb_power_on(qmp->phy);
> >>         }
> >>
> >>         mutex_unlock(&qmp->phy_mutex);
> >> @@ -880,22 +1601,24 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw,
> >>  static void qmp_usbc_typec_unregister(void *data)
> >>  {
> >>         struct qmp_usbc *qmp = data;
> >> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >>
> >> -       typec_switch_unregister(qmp->sw);
> >> +       typec_switch_unregister(layout->sw);
> >>  }
> >>
> >>  static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp)
> >>  {
> >>         struct typec_switch_desc sw_desc = {};
> >>         struct device *dev = qmp->dev;
> >> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >>
> >>         sw_desc.drvdata = qmp;
> >>         sw_desc.fwnode = dev->fwnode;
> >>         sw_desc.set = qmp_usbc_typec_switch_set;
> >> -       qmp->sw = typec_switch_register(dev, &sw_desc);
> >> -       if (IS_ERR(qmp->sw)) {
> >> -               dev_err(dev, "Unable to register typec switch: %pe\n", qmp->sw);
> >> -               return PTR_ERR(qmp->sw);
> >> +       layout->sw = typec_switch_register(dev, &sw_desc);
> >> +       if (IS_ERR(layout->sw)) {
> >> +               dev_err(dev, "Unable to register typec switch: %pe\n", layout->sw);
> >> +               return PTR_ERR(layout->sw);
> >>         }
> >>
> >>         return devm_add_action_or_reset(dev, qmp_usbc_typec_unregister, qmp);
> >> @@ -907,15 +1630,16 @@ static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp)
> >>  }
> >>  #endif
> >>
> >> -static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np)
> >> +static int qmp_usbc_parse_usb_dt_legacy(struct qmp_usbc *qmp, struct device_node *np)
> >>  {
> >>         struct platform_device *pdev = to_platform_device(qmp->dev);
> >>         struct device *dev = qmp->dev;
> >> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >>         int ret;
> >>
> >> -       qmp->serdes = devm_platform_ioremap_resource(pdev, 0);
> >> -       if (IS_ERR(qmp->serdes))
> >> -               return PTR_ERR(qmp->serdes);
> >> +       layout->serdes = devm_platform_ioremap_resource(pdev, 0);
> >> +       if (IS_ERR(layout->serdes))
> >> +               return PTR_ERR(layout->serdes);
> >>
> >>         /*
> >>          * Get memory resources for the PHY:
> >> @@ -923,35 +1647,35 @@ static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np
> >>          * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5
> >>          * For single lane PHYs: pcs_misc (optional) -> 3.
> >>          */
> >> -       qmp->tx = devm_of_iomap(dev, np, 0, NULL);
> >> -       if (IS_ERR(qmp->tx))
> >> -               return PTR_ERR(qmp->tx);
> >> +       layout->tx = devm_of_iomap(dev, np, 0, NULL);
> >> +       if (IS_ERR(layout->tx))
> >> +               return PTR_ERR(layout->tx);
> >>
> >> -       qmp->rx = devm_of_iomap(dev, np, 1, NULL);
> >> -       if (IS_ERR(qmp->rx))
> >> -               return PTR_ERR(qmp->rx);
> >> +       layout->rx = devm_of_iomap(dev, np, 1, NULL);
> >> +       if (IS_ERR(layout->rx))
> >> +               return PTR_ERR(layout->rx);
> >>
> >> -       qmp->pcs = devm_of_iomap(dev, np, 2, NULL);
> >> -       if (IS_ERR(qmp->pcs))
> >> -               return PTR_ERR(qmp->pcs);
> >> +       layout->pcs = devm_of_iomap(dev, np, 2, NULL);
> >> +       if (IS_ERR(layout->pcs))
> >> +               return PTR_ERR(layout->pcs);
> >>
> >> -       qmp->tx2 = devm_of_iomap(dev, np, 3, NULL);
> >> -       if (IS_ERR(qmp->tx2))
> >> -               return PTR_ERR(qmp->tx2);
> >> +       layout->tx2 = devm_of_iomap(dev, np, 3, NULL);
> >> +       if (IS_ERR(layout->tx2))
> >> +               return PTR_ERR(layout->tx2);
> >>
> >> -       qmp->rx2 = devm_of_iomap(dev, np, 4, NULL);
> >> -       if (IS_ERR(qmp->rx2))
> >> -               return PTR_ERR(qmp->rx2);
> >> +       layout->rx2 = devm_of_iomap(dev, np, 4, NULL);
> >> +       if (IS_ERR(layout->rx2))
> >> +               return PTR_ERR(layout->rx2);
> >>
> >> -       qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
> >> -       if (IS_ERR(qmp->pcs_misc)) {
> >> +       layout->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
> >> +       if (IS_ERR(layout->pcs_misc)) {
> >>                 dev_vdbg(dev, "PHY pcs_misc-reg not used\n");
> >> -               qmp->pcs_misc = NULL;
> >> +               layout->pcs_misc = NULL;
> >>         }
> >>
> >> -       qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
> >> -       if (IS_ERR(qmp->pipe_clk)) {
> >> -               return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
> >> +       layout->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
> >> +       if (IS_ERR(layout->pipe_clk)) {
> >> +               return dev_err_probe(dev, PTR_ERR(layout->pipe_clk),
> >>                                      "failed to get pipe clock\n");
> >>         }
> >>
> >> @@ -969,11 +1693,12 @@ static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np
> >>         return 0;
> >>  }
> >>
> >> -static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
> >> +static int qmp_usbc_parse_usb_dt(struct qmp_usbc *qmp)
> >>  {
> >>         struct platform_device *pdev = to_platform_device(qmp->dev);
> >> -       const struct qmp_phy_cfg *cfg = qmp->cfg;
> >> -       const struct qmp_usbc_offsets *offs = cfg->offsets;
> >> +       const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp);
> >> +       const struct qmp_usbc_usb_offsets *offs = cfg->offsets;
> >> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >>         struct device *dev = qmp->dev;
> >>         void __iomem *base;
> >>         int ret;
> >> @@ -985,23 +1710,23 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
> >>         if (IS_ERR(base))
> >>                 return PTR_ERR(base);
> >>
> >> -       qmp->serdes = base + offs->serdes;
> >> -       qmp->pcs = base + offs->pcs;
> >> +       layout->serdes = base + offs->serdes;
> >> +       layout->pcs = base + offs->pcs;
> >>         if (offs->pcs_misc)
> >> -               qmp->pcs_misc = base + offs->pcs_misc;
> >> -       qmp->tx = base + offs->tx;
> >> -       qmp->rx = base + offs->rx;
> >> +               layout->pcs_misc = base + offs->pcs_misc;
> >> +       layout->tx = base + offs->tx;
> >> +       layout->rx = base + offs->rx;
> >>
> >> -       qmp->tx2 = base + offs->tx2;
> >> -       qmp->rx2 = base + offs->rx2;
> >> +       layout->tx2 = base + offs->tx2;
> >> +       layout->rx2 = base + offs->rx2;
> >>
> >>         ret = qmp_usbc_clk_init(qmp);
> >>         if (ret)
> >>                 return ret;
> >>
> >> -       qmp->pipe_clk = devm_clk_get(dev, "pipe");
> >> -       if (IS_ERR(qmp->pipe_clk)) {
> >> -               return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
> >> +       layout->pipe_clk = devm_clk_get(dev, "pipe");
> >> +       if (IS_ERR(layout->pipe_clk)) {
> >> +               return dev_err_probe(dev, PTR_ERR(layout->pipe_clk),
> >>                                      "failed to get pipe clock\n");
> >>         }
> >>
> >> @@ -1013,10 +1738,11 @@ 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_usb_vls_clamp(struct qmp_usbc *qmp)
> >>  {
> >>         struct of_phandle_args tcsr_args;
> >>         struct device *dev = qmp->dev;
> >> +       struct qmp_phy_usb_layout *layout = to_usb_layout(qmp);
> >>         int ret;
> >>
> >>         /*  for backwards compatibility ignore if there is no property */
> >> @@ -1027,22 +1753,280 @@ static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp)
> >>         else if (ret < 0)
> >>                 return dev_err_probe(dev, ret, "Failed to parse qcom,tcsr-reg\n");
> >>
> >> -       qmp->tcsr_map = syscon_node_to_regmap(tcsr_args.np);
> >> +       layout->tcsr_map = syscon_node_to_regmap(tcsr_args.np);
> >>         of_node_put(tcsr_args.np);
> >> -       if (IS_ERR(qmp->tcsr_map))
> >> -               return PTR_ERR(qmp->tcsr_map);
> >> +       if (IS_ERR(layout->tcsr_map))
> >> +               return PTR_ERR(layout->tcsr_map);
> >>
> >> -       qmp->vls_clamp_reg = tcsr_args.args[0];
> >> +       layout->vls_clamp_reg = tcsr_args.args[0];
> >>
> >>         return 0;
> >>  }
> >>
> >> +static int qmp_usbc_parse_dp_phy_mode(struct qmp_usbc *qmp)
> >> +{
> >> +       struct of_phandle_args tcsr_args;
> >> +       struct device *dev = qmp->dev;
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +       int ret;
> >> +
> >> +       /*  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);
> >> +       if (ret < 0)
> >> +               return dev_err_probe(dev, ret, "Failed to parse qcom,tcsr-reg\n");
> >> +
> >> +       layout->tcsr_map = syscon_node_to_regmap(tcsr_args.np);
> >> +       of_node_put(tcsr_args.np);
> >> +       if (IS_ERR(layout->tcsr_map))
> >> +               return PTR_ERR(layout->tcsr_map);
> >> +
> >> +       layout->dp_phy_mode = tcsr_args.args[0];
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int qmp_usbc_parse_dp_dt(struct qmp_usbc *qmp)
> >> +{
> >> +       struct platform_device *pdev = to_platform_device(qmp->dev);
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +       struct qmp_phy_dp_cfg *cfg = to_dp_cfg(qmp);
> >> +       const struct qmp_usbc_dp_offsets *offs = cfg->offsets;
> >> +       struct device *dev = qmp->dev;
> >> +       void __iomem *base;
> >> +       int ret;
> >> +
> >> +       base = devm_platform_ioremap_resource(pdev, 0);
> >> +       if (IS_ERR(base)) {
> >> +               dev_err(dev, "get resource fail, ret:%d\n", ret);
> >> +               return PTR_ERR(base);
> >> +       }
> >> +
> >> +       layout->dp_serdes = base + offs->dp_serdes;
> >> +       layout->dp_tx = base + offs->dp_txa;
> >> +       layout->dp_tx2 = base + offs->dp_txb;
> >> +       layout->dp_phy = base + offs->dp_phy;
> >> +
> >> +       ret = qmp_usbc_clk_init(qmp);
> >> +       if (ret) {
> >> +               dev_err(dev, "clk init fail, ret:%d\n", ret);
> >> +               return ret;
> >> +       }
> >> +
> >> +       ret = qmp_usbc_reset_init(qmp, dp_usb3phy_reset_l,
> >> +                                ARRAY_SIZE(dp_usb3phy_reset_l));
> >> +       if (ret)
> >> +               return ret;
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +/*
> >> + * 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 and 8.1 GHz are same link rate as 2.7GHz, i.e. div 4 and div 6 */
> >> +               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;
> >> +       struct qmp_phy_dp_layout *layout;
> >> +       const struct phy_configure_opts_dp *dp_opts;
> >> +
> >> +       layout = container_of(hw, struct qmp_phy_dp_layout, dp_pixel_hw);
> >> +
> >> +       dp_opts = &layout->dp_opts;
> >> +
> >> +       switch (dp_opts->link_rate) {
> >> +       case 1620:
> >> +               return 1620000000UL / 2;
> >> +       case 2700:
> >> +               return 2700000000UL / 2;
> >> +       case 5400:
> >> +               return 5400000000UL / 4;
> >> +       case 8100:
> >> +               return 8100000000UL / 6;
> >> +       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:
> >> +       case 810000000:
> >> +               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_combo *qmp;
> >> +       struct qmp_phy_dp_layout *layout;
> >> +       const struct phy_configure_opts_dp *dp_opts;
> >> +
> >> +       layout = container_of(hw, struct qmp_phy_dp_layout, dp_link_hw);
> >> +       dp_opts = &layout->dp_opts;
> >> +
> >> +       switch (dp_opts->link_rate) {
> >> +       case 1620:
> >> +       case 2700:
> >> +       case 5400:
> >> +       case 8100:
> >> +               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 = { };
> >> +       int ret = 0;
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +
> >> +       ret = of_property_read_string_index(np, "clock-output-names", 0, &init.name);
> >> +       if (ret < 0) {
> >> +               dev_err(qmp->dev, "%pOFn: No link clock-output-names\n", np);
> >> +               return ret;
> >> +       }
> >> +
> >> +       init.ops = &qmp_dp_link_clk_ops;
> >> +       layout->dp_link_hw.init = &init;
> >> +       ret = devm_clk_hw_register(qmp->dev, &layout->dp_link_hw);
> >> +       if (ret < 0) {
> >> +               dev_err(qmp->dev, "link clk reg fail ret=%d\n", ret);
> >> +               return ret;
> >> +       }
> >> +
> >> +       ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
> >> +       if (ret) {
> >> +               dev_err(qmp->dev, "%pOFn: No div clock-output-names\n", np);
> >> +               return ret;
> >> +       }
> >> +
> >> +       init.ops = &qmp_dp_pixel_clk_ops;
> >> +       layout->dp_pixel_hw.init = &init;
> >> +       ret = devm_clk_hw_register(qmp->dev, &layout->dp_pixel_hw);
> >> +       if (ret) {
> >> +               dev_err(qmp->dev, "pxl clk reg fail ret=%d\n", ret);
> >> +               return ret;
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static struct clk_hw *qmp_dp_clks_hw_get(struct of_phandle_args *clkspec, void *data)
> >> +{
> >> +       struct qmp_usbc *qmp = data;
> >> +       struct qmp_phy_dp_layout *layout = to_dp_layout(qmp);
> >> +
> >> +       switch (clkspec->args[0]) {
> >> +       case QMP_USB43DP_DP_LINK_CLK:
> >> +               return &layout->dp_link_hw;
> >> +       case QMP_USB43DP_DP_VCO_DIV_CLK:
> >> +               return &layout->dp_pixel_hw;
> >> +       }
> >> +
> >> +       return ERR_PTR(-EINVAL);
> >> +}
> >> +
> >> +static int qmp_dp_register_clocks(struct qmp_usbc *qmp, struct device_node *dp_np)
> >> +{
> >> +       int ret;
> >> +
> >> +       ret = phy_dp_clks_register(qmp, dp_np);
> >> +       if (ret) {
> >> +               dev_err(qmp->dev, "dp clk reg fail ret:%d\n", ret);
> >> +               return ret;
> >> +       }
> >> +
> >> +       ret = of_clk_add_hw_provider(dp_np, qmp_dp_clks_hw_get, qmp);
> >> +       if (ret) {
> >> +               dev_err(qmp->dev, "add provider fail ret:%d\n", ret);
> >> +               return ret;
> >> +       }
> >> +
> >> +       return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, dp_np);
> >> +}
> >> +
> >>  static int qmp_usbc_probe(struct platform_device *pdev)
> >>  {
> >>         struct device *dev = &pdev->dev;
> >>         struct phy_provider *phy_provider;
> >>         struct device_node *np;
> >>         struct qmp_usbc *qmp;
> >> +       const struct dev_cfg *data_cfg;
> >>         int ret;
> >>
> >>         qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL);
> >> @@ -1050,38 +2034,74 @@ static int qmp_usbc_probe(struct platform_device *pdev)
> >>                 return -ENOMEM;
> >>
> >>         qmp->dev = dev;
> >> -       dev_set_drvdata(dev, qmp);
> >>
> >>         qmp->orientation = TYPEC_ORIENTATION_NORMAL;
> >>
> >> -       qmp->cfg = of_device_get_match_data(dev);
> >> -       if (!qmp->cfg)
> >> +       qmp->init_count = 0;
> >> +
> >> +       data_cfg = of_device_get_match_data(dev);
> >> +       if (!data_cfg) {
> >> +               dev_err(qmp->dev, "get data fail\n");
> >>                 return -EINVAL;
> >> +       }
> >>
> >>         mutex_init(&qmp->phy_mutex);
> >>
> >> -       ret = qmp_usbc_vreg_init(qmp);
> >> -       if (ret)
> >> -               return ret;
> >> +       qmp->type = data_cfg->type;
> >> +       qmp->cfg = data_cfg->cfg;
> >>
> >> -       ret = qmp_usbc_typec_switch_register(qmp);
> >> -       if (ret)
> >> +       ret = qmp_usbc_vreg_init(qmp);
> >> +       if (ret) {
> >> +               dev_err(qmp->dev, "qmp_type(%d) vreg init fail\n", qmp->type);
> >>                 return ret;
> >> +       }
> >>
> >> -       ret = qmp_usbc_parse_vls_clamp(qmp);
> >> -       if (ret)
> >> -               return ret;
> >> +       if (qmp->type == QMP_PHY_USBC_USB) {
> >> +               qmp->layout = devm_kzalloc(dev, sizeof(struct qmp_phy_usb_layout), GFP_KERNEL);
> >> +               if (!qmp->layout)
> >> +                       return -ENOMEM;
> >> +
> >> +               ret = qmp_usbc_typec_switch_register(qmp);
> >> +               if (ret)
> >> +                       return ret;
> >> +
> >> +               ret = qmp_usbc_parse_usb_vls_clamp(qmp);
> >> +               if (ret)
> >> +                       return ret;
> >> +
> >> +               /* Check for legacy binding with child node. */
> >> +               np = of_get_child_by_name(dev->of_node, "phy");
> >> +               if (np) {
> >> +                       ret = qmp_usbc_parse_usb_dt_legacy(qmp, np);
> >> +               } else {
> >> +                       np = of_node_get(dev->of_node);
> >> +                       ret = qmp_usbc_parse_usb_dt(qmp);
> >> +               }
> >> +               if (ret)
> >> +                       goto err_node_put;
> >> +       } else if (qmp->type == QMP_PHY_USBC_DP) {
> >> +               qmp->layout = devm_kzalloc(dev, sizeof(struct qmp_phy_dp_layout), GFP_KERNEL);
> >> +               if (!qmp->layout)
> >> +                       return -ENOMEM;
> >>
> >> -       /* Check for legacy binding with child node. */
> >> -       np = of_get_child_by_name(dev->of_node, "phy");
> >> -       if (np) {
> >> -               ret = qmp_usbc_parse_dt_legacy(qmp, np);
> >> -       } else {
> >>                 np = of_node_get(dev->of_node);
> >> -               ret = qmp_usbc_parse_dt(qmp);
> >> -       }
> >> -       if (ret)
> >> +               ret = qmp_usbc_parse_dp_phy_mode(qmp);
> >> +               if (ret)
> >> +                       goto err_node_put;
> >> +
> >> +               ret = qmp_usbc_parse_dp_dt(qmp);
> >> +               if (ret)
> >> +                       goto err_node_put;
> >> +
> >> +               ret = drm_aux_bridge_register(dev);
> >> +               if (ret) {
> >> +                       dev_err(qmp->dev, "aux bridge reg fail ret=%d\n", ret);
> >> +                       goto err_node_put;
> >> +               }
> >> +       } else {
> >> +               dev_err(dev, "invalid phy type: %d\n", qmp->type);
> >>                 goto err_node_put;
> >> +       }
> >>
> >>         pm_runtime_set_active(dev);
> >>         ret = devm_pm_runtime_enable(dev);
> >> @@ -1093,19 +2113,33 @@ static int qmp_usbc_probe(struct platform_device *pdev)
> >>          */
> >>         pm_runtime_forbid(dev);
> >>
> >> -       ret = phy_pipe_clk_register(qmp, np);
> >> -       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);
> >> -               dev_err(dev, "failed to create PHY: %d\n", ret);
> >> -               goto err_node_put;
> >> +       if (qmp->type == QMP_PHY_USBC_USB) {
> >> +               // pipe clk process
> >> +               ret = phy_pipe_clk_register(qmp, np);
> >> +               if (ret)
> >> +                       goto err_node_put;
> >> +
> >> +               qmp->phy = devm_phy_create(dev, np, &qmp_usbc_usb_phy_ops);
> >> +               if (IS_ERR(qmp->phy)) {
> >> +                       ret = PTR_ERR(qmp->phy);
> >> +                       dev_err(dev, "failed to create PHY: %d\n", ret);
> >> +                       goto err_node_put;
> >> +               }
> >> +       } else {
> >> +               ret = qmp_dp_register_clocks(qmp, np);
> >> +               if (ret)
> >> +                       goto err_node_put;
> >> +
> >> +               qmp->phy = devm_phy_create(dev, np, &qmp_usbc_dp_phy_ops);
> >> +               if (IS_ERR(qmp->phy)) {
> >> +                       ret = PTR_ERR(qmp->phy);
> >> +                       dev_err(dev, "failed to create PHY: %d\n", ret);
> >> +                       goto err_node_put;
> >> +               }
> >>         }
> >>
> >>         phy_set_drvdata(qmp->phy, qmp);
> >> -
> >> +       dev_set_drvdata(dev, qmp);
> >>         of_node_put(np);
> >>
> >>         phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> >> @@ -1120,19 +2154,38 @@ static int qmp_usbc_probe(struct platform_device *pdev)
> >>  static const struct of_device_id qmp_usbc_of_match_table[] = {
> >>         {
> >>                 .compatible = "qcom,msm8998-qmp-usb3-phy",
> >> -               .data = &msm8998_usb3phy_cfg,
> >> +               .data =  &(struct dev_cfg) {
> >> +                       .type = QMP_PHY_USBC_USB,
> >> +                       .cfg = &msm8998_usb3phy_cfg,
> >> +               },
> >>         }, {
> >>                 .compatible = "qcom,qcm2290-qmp-usb3-phy",
> >> -               .data = &qcm2290_usb3phy_cfg,
> >> +               .data =  &(struct dev_cfg) {
> >> +                       .type = QMP_PHY_USBC_USB,
> >> +                       .cfg = &qcm2290_usb3phy_cfg,
> >> +               },
> >> +       }, {
> >> +               .compatible = "qcom,qcs615-qmp-dp-phy",
> >> +               .data =  &(struct dev_cfg) {
> >> +                       .type = QMP_PHY_USBC_DP,
> >> +                       .cfg = &qcs615_dpphy_cfg,
> >> +               },
> >>         }, {
> >>                 .compatible = "qcom,sdm660-qmp-usb3-phy",
> >> -               .data = &sdm660_usb3phy_cfg,
> >> +               .data =  &(struct dev_cfg) {
> >> +                       .type = QMP_PHY_USBC_USB,
> >> +                       .cfg = &sdm660_usb3phy_cfg,
> >> +               },
> >>         }, {
> >>                 .compatible = "qcom,sm6115-qmp-usb3-phy",
> >> -               .data = &qcm2290_usb3phy_cfg,
> >> +               .data =  &(struct dev_cfg) {
> >> +                       .type = QMP_PHY_USBC_USB,
> >> +                       .cfg = &qcm2290_usb3phy_cfg,
> >> +               },
> >>         },
> >>         { },
> >>  };
> >> +
> >>  MODULE_DEVICE_TABLE(of, qmp_usbc_of_match_table);
> >>
> >>  static struct platform_driver qmp_usbc_driver = {
> >>
> >> --
> >> 2.25.1
> >>
> > 
> > 
> 
> 
> -- 
> linux-phy mailing list
> linux-phy@lists.infradead.org
> https://lists.infradead.org/mailman/listinfo/linux-phy

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 6/8] drm/msm/dp: Add maximum width limitation for modes
  2024-12-03 13:58           ` Dmitry Baryshkov
@ 2024-12-06 20:13             ` Abhinav Kumar
  2024-12-09  1:57               ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Abhinav Kumar @ 2024-12-06 20:13 UTC (permalink / raw)
  To: Dmitry Baryshkov, Xiangxu Yin
  Cc: Rob Clark, Sean Paul, Marijn Suijten, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh,
	Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 12/3/2024 5:58 AM, Dmitry Baryshkov wrote:
> On Tue, Dec 03, 2024 at 03:41:53PM +0800, Xiangxu Yin wrote:
>>
>>
>> On 12/2/2024 5:32 PM, Dmitry Baryshkov wrote:
>>> On Mon, 2 Dec 2024 at 11:05, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>
>>>>
>>>>
>>>> On 11/29/2024 9:52 PM, Dmitry Baryshkov wrote:
>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>>
>>>>>> Introduce a maximum width constraint for modes during validation. This
>>>>>> ensures that the modes are filtered based on hardware capabilities,
>>>>>> specifically addressing the line buffer limitations of individual pipes.
>>>>>
>>>>> This doesn't describe, why this is necessary. What does "buffer
>>>>> limitations of individual pipes" mean?
>>>>> If the platforms have hw capabilities like being unable to support 8k
>>>>> or 10k, it should go to platform data
>>>>>
>>>> It's SSPP line buffer limitation for this platform and only support to 2160 mode width.
>>>> Then, shall I add max_width config to struct msm_dp_desc in next patch? for other platform will set defualt value to ‘DP_MAX_WIDTH 7680'
>>>
>>> SSPP line buffer limitations are to be handled in the DPU driver. The
>>> DP driver shouldn't care about those.
>>>
>> Ok, Will drop this part in next patch.
> 
> If you drop it, what will be left from the patch itself?
> 

Yes agree with Dmitry, max_width is really not a DP related terminology.

This patch should be dropped.

So there were two issues, overall in this series causing this patch:

1) In https://patchwork.freedesktop.org/patch/625822/, instead of using 
VIG_SDM845_MASK, we should be using VIG_SDM845_MASK_SDMA. Without that 
even 2k will not work, will leave a comment there.

2) 4k will still fail. I dont think we can even support 4k on QCS615 but 
the modes should be filtered out because there is no 3dmux.

I have submitted https://patchwork.freedesktop.org/patch/627694/ to 
address this.

Xiangxu, please let me know if that works for you.

Thanks

Abhinav
>>>>>>
>>>>>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
>>>>>> ---
>>>>>>   drivers/gpu/drm/msm/dp/dp_display.c |  3 +++
>>>>>>   drivers/gpu/drm/msm/dp/dp_display.h |  1 +
>>>>>>   drivers/gpu/drm/msm/dp/dp_panel.c   | 13 +++++++++++++
>>>>>>   drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
>>>>>>   4 files changed, 18 insertions(+)
>>>
>>>
>>
> 

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 6/8] drm/msm/dp: Add maximum width limitation for modes
  2024-12-06 20:13             ` Abhinav Kumar
@ 2024-12-09  1:57               ` Xiangxu Yin
  2024-12-09 20:18                 ` Abhinav Kumar
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-12-09  1:57 UTC (permalink / raw)
  To: Abhinav Kumar, Dmitry Baryshkov
  Cc: Rob Clark, Sean Paul, Marijn Suijten, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh,
	Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 12/7/2024 4:13 AM, Abhinav Kumar wrote:
> 
> 
> On 12/3/2024 5:58 AM, Dmitry Baryshkov wrote:
>> On Tue, Dec 03, 2024 at 03:41:53PM +0800, Xiangxu Yin wrote:
>>>
>>>
>>> On 12/2/2024 5:32 PM, Dmitry Baryshkov wrote:
>>>> On Mon, 2 Dec 2024 at 11:05, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>
>>>>>
>>>>>
>>>>> On 11/29/2024 9:52 PM, Dmitry Baryshkov wrote:
>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>>>
>>>>>>> Introduce a maximum width constraint for modes during validation. This
>>>>>>> ensures that the modes are filtered based on hardware capabilities,
>>>>>>> specifically addressing the line buffer limitations of individual pipes.
>>>>>>
>>>>>> This doesn't describe, why this is necessary. What does "buffer
>>>>>> limitations of individual pipes" mean?
>>>>>> If the platforms have hw capabilities like being unable to support 8k
>>>>>> or 10k, it should go to platform data
>>>>>>
>>>>> It's SSPP line buffer limitation for this platform and only support to 2160 mode width.
>>>>> Then, shall I add max_width config to struct msm_dp_desc in next patch? for other platform will set defualt value to ‘DP_MAX_WIDTH 7680'
>>>>
>>>> SSPP line buffer limitations are to be handled in the DPU driver. The
>>>> DP driver shouldn't care about those.
>>>>
>>> Ok, Will drop this part in next patch.
>>
>> If you drop it, what will be left from the patch itself?
>>
> 
> Yes agree with Dmitry, max_width is really not a DP related terminology.
> 
> This patch should be dropped.
> 
> So there were two issues, overall in this series causing this patch:
> 
> 1) In https://patchwork.freedesktop.org/patch/625822/, instead of using VIG_SDM845_MASK, we should be using VIG_SDM845_MASK_SDMA. Without that even 2k will not work, will leave a comment there.
> 
> 2) 4k will still fail. I dont think we can even support 4k on QCS615 but the modes should be filtered out because there is no 3dmux.
> 
> I have submitted https://patchwork.freedesktop.org/patch/627694/ to address this.
> 
> Xiangxu, please let me know if that works for you.
> 
> Thanks
> 
> Abhinav
Thanks for your patchsets,
After apply patch 625822 & 627694,mode filter works correctly on QCS615 platform with both 4k and 2k monitor.
work>>>>>>>
>>>>>>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
>>>>>>> ---
>>>>>>>   drivers/gpu/drm/msm/dp/dp_display.c |  3 +++
>>>>>>>   drivers/gpu/drm/msm/dp/dp_display.h |  1 +
>>>>>>>   drivers/gpu/drm/msm/dp/dp_panel.c   | 13 +++++++++++++
>>>>>>>   drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
>>>>>>>   4 files changed, 18 insertions(+)
>>>>
>>>>
>>>
>>


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 6/8] drm/msm/dp: Add maximum width limitation for modes
  2024-12-09  1:57               ` Xiangxu Yin
@ 2024-12-09 20:18                 ` Abhinav Kumar
  0 siblings, 0 replies; 60+ messages in thread
From: Abhinav Kumar @ 2024-12-09 20:18 UTC (permalink / raw)
  To: Xiangxu Yin, Dmitry Baryshkov
  Cc: Rob Clark, Sean Paul, Marijn Suijten, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh,
	Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 12/8/2024 5:57 PM, Xiangxu Yin wrote:
> 
> 
> On 12/7/2024 4:13 AM, Abhinav Kumar wrote:
>>
>>
>> On 12/3/2024 5:58 AM, Dmitry Baryshkov wrote:
>>> On Tue, Dec 03, 2024 at 03:41:53PM +0800, Xiangxu Yin wrote:
>>>>
>>>>
>>>> On 12/2/2024 5:32 PM, Dmitry Baryshkov wrote:
>>>>> On Mon, 2 Dec 2024 at 11:05, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 11/29/2024 9:52 PM, Dmitry Baryshkov wrote:
>>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>>>>
>>>>>>>> Introduce a maximum width constraint for modes during validation. This
>>>>>>>> ensures that the modes are filtered based on hardware capabilities,
>>>>>>>> specifically addressing the line buffer limitations of individual pipes.
>>>>>>>
>>>>>>> This doesn't describe, why this is necessary. What does "buffer
>>>>>>> limitations of individual pipes" mean?
>>>>>>> If the platforms have hw capabilities like being unable to support 8k
>>>>>>> or 10k, it should go to platform data
>>>>>>>
>>>>>> It's SSPP line buffer limitation for this platform and only support to 2160 mode width.
>>>>>> Then, shall I add max_width config to struct msm_dp_desc in next patch? for other platform will set defualt value to ‘DP_MAX_WIDTH 7680'
>>>>>
>>>>> SSPP line buffer limitations are to be handled in the DPU driver. The
>>>>> DP driver shouldn't care about those.
>>>>>
>>>> Ok, Will drop this part in next patch.
>>>
>>> If you drop it, what will be left from the patch itself?
>>>
>>
>> Yes agree with Dmitry, max_width is really not a DP related terminology.
>>
>> This patch should be dropped.
>>
>> So there were two issues, overall in this series causing this patch:
>>
>> 1) In https://patchwork.freedesktop.org/patch/625822/, instead of using VIG_SDM845_MASK, we should be using VIG_SDM845_MASK_SDMA. Without that even 2k will not work, will leave a comment there.
>>
>> 2) 4k will still fail. I dont think we can even support 4k on QCS615 but the modes should be filtered out because there is no 3dmux.
>>
>> I have submitted https://patchwork.freedesktop.org/patch/627694/ to address this.
>>
>> Xiangxu, please let me know if that works for you.
>>
>> Thanks
>>
>> Abhinav
> Thanks for your patchsets,
> After apply patch 625822 & 627694,mode filter works correctly on QCS615 platform with both 4k and 2k monitor.
> work>>>>>>>

Thanks. If you can give your Tested-by on 
https://patchwork.freedesktop.org/patch/627967/, that would be great.

>>>>>>>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
>>>>>>>> ---
>>>>>>>>    drivers/gpu/drm/msm/dp/dp_display.c |  3 +++
>>>>>>>>    drivers/gpu/drm/msm/dp/dp_display.h |  1 +
>>>>>>>>    drivers/gpu/drm/msm/dp/dp_panel.c   | 13 +++++++++++++
>>>>>>>>    drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
>>>>>>>>    4 files changed, 18 insertions(+)
>>>>>
>>>>>
>>>>
>>>
> 

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-12-05 18:31       ` Dmitry Baryshkov
@ 2024-12-10 15:09         ` Dmitry Baryshkov
  2024-12-11  0:46           ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-12-10 15:09 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Thu, Dec 05, 2024 at 08:31:24PM +0200, Dmitry Baryshkov wrote:
> On Thu, Dec 05, 2024 at 09:26:47PM +0800, Xiangxu Yin wrote:
> > 
> > 
> > On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
> > > On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> > >>
> > >> Extended DP support for QCS615 USB or DP phy. Differentiated between
> > >> USBC and DP PHY using the match table’s type, dynamically generating
> > >> different types of cfg and layout attributes during initialization based
> > >> on this type. Static variables are stored in cfg, while parsed values
> > >> are organized into the layout structure.
> > > 
> > > We didn't have an understanding / conclusion whether
> > > qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
> > > or two PHYs being placed next to each other. Could you please start
> > > your commit message by explaining it? Or even better, make that a part
> > > of the cover letter for a new series touching just the USBC PHY
> > > driver. DP changes don't have anything in common with the PHY changes,
> > > so you can split the series into two.
> > > 
> > Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.
> 
> What is "DP extension"?
> 
> > 
> > We identified that DP and USB share some common controls for phy_mode and orientation.
> > Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
> > while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
> > It would be more efficient for a single driver to manage these controls. 
> 
> The question is about the hardware, not about the driver.
> 
> > Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
> > Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
> > we still decided to base it on the USBC extension.
> 
> Could you please clarify, do usb3-or-dp PHYs support DP-over-USB-C? I
> thought that usbc-or-dp platforms support that, but they don't
> support DP+USB pin configuration. Note, the question is broader than
> just QCS615, it covers the PHY type itself.
> 
> Also, is TCSR configuration read/write or read-only? Are we supposed to
> set the register from OS or are we supposed to read it and thus detemine
> the PHY mode?

Any updates on these two topics?

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-12-10 15:09         ` Dmitry Baryshkov
@ 2024-12-11  0:46           ` Xiangxu Yin
  2024-12-11  9:46             ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-12-11  0:46 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 12/10/2024 11:09 PM, Dmitry Baryshkov wrote:
> On Thu, Dec 05, 2024 at 08:31:24PM +0200, Dmitry Baryshkov wrote:
>> On Thu, Dec 05, 2024 at 09:26:47PM +0800, Xiangxu Yin wrote:
>>>
>>>
>>> On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>
>>>>> Extended DP support for QCS615 USB or DP phy. Differentiated between
>>>>> USBC and DP PHY using the match table’s type, dynamically generating
>>>>> different types of cfg and layout attributes during initialization based
>>>>> on this type. Static variables are stored in cfg, while parsed values
>>>>> are organized into the layout structure.
>>>>
>>>> We didn't have an understanding / conclusion whether
>>>> qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
>>>> or two PHYs being placed next to each other. Could you please start
>>>> your commit message by explaining it? Or even better, make that a part
>>>> of the cover letter for a new series touching just the USBC PHY
>>>> driver. DP changes don't have anything in common with the PHY changes,
>>>> so you can split the series into two.
>>>>
>>> Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.
>>
>> What is "DP extension"?
>>
I'm sorry confusion casued by my description. It's means extend DP implemnt for USBC phy driver.
>>>
>>> We identified that DP and USB share some common controls for phy_mode and orientation.
>>> Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
>>> while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
>>> It would be more efficient for a single driver to manage these controls. 
>>
>> The question is about the hardware, not about the driver.
>>
>>> Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
>>> Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
>>> we still decided to base it on the USBC extension.
>>
>> Could you please clarify, do usb3-or-dp PHYs support DP-over-USB-C? I
>> thought that usbc-or-dp platforms support that, but they don't
>> support DP+USB pin configuration. Note, the question is broader than
>> just QCS615, it covers the PHY type itself.
>>
>> Also, is TCSR configuration read/write or read-only? Are we supposed to
>> set the register from OS or are we supposed to read it and thus detemine
>> the PHY mode?
> 
> Any updates on these two topics?
> 
Still confirming detail info with HW & design team.
I’ll update the information that has been confirmed so far.
This phy support DP-over-USB-C,but it's not support alt-mode which 2 lane work for DP, other 2 lane work for USB.
TCSR phy mode is read/write reg and we can read for determine phy mode.



^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-12-11  0:46           ` Xiangxu Yin
@ 2024-12-11  9:46             ` Dmitry Baryshkov
  2024-12-11 12:50               ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-12-11  9:46 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Wed, Dec 11, 2024 at 08:46:16AM +0800, Xiangxu Yin wrote:
> 
> 
> On 12/10/2024 11:09 PM, Dmitry Baryshkov wrote:
> > On Thu, Dec 05, 2024 at 08:31:24PM +0200, Dmitry Baryshkov wrote:
> >> On Thu, Dec 05, 2024 at 09:26:47PM +0800, Xiangxu Yin wrote:
> >>>
> >>>
> >>> On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
> >>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>>
> >>>>> Extended DP support for QCS615 USB or DP phy. Differentiated between
> >>>>> USBC and DP PHY using the match table’s type, dynamically generating
> >>>>> different types of cfg and layout attributes during initialization based
> >>>>> on this type. Static variables are stored in cfg, while parsed values
> >>>>> are organized into the layout structure.
> >>>>
> >>>> We didn't have an understanding / conclusion whether
> >>>> qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
> >>>> or two PHYs being placed next to each other. Could you please start
> >>>> your commit message by explaining it? Or even better, make that a part
> >>>> of the cover letter for a new series touching just the USBC PHY
> >>>> driver. DP changes don't have anything in common with the PHY changes,
> >>>> so you can split the series into two.
> >>>>
> >>> Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.
> >>
> >> What is "DP extension"?
> >>
> I'm sorry confusion casued by my description. It's means extend DP implemnt for USBC phy driver.
> >>>
> >>> We identified that DP and USB share some common controls for phy_mode and orientation.
> >>> Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
> >>> while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
> >>> It would be more efficient for a single driver to manage these controls. 
> >>
> >> The question is about the hardware, not about the driver.
> >>
> >>> Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
> >>> Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
> >>> we still decided to base it on the USBC extension.
> >>
> >> Could you please clarify, do usb3-or-dp PHYs support DP-over-USB-C? I
> >> thought that usbc-or-dp platforms support that, but they don't
> >> support DP+USB pin configuration. Note, the question is broader than
> >> just QCS615, it covers the PHY type itself.
> >>
> >> Also, is TCSR configuration read/write or read-only? Are we supposed to
> >> set the register from OS or are we supposed to read it and thus detemine
> >> the PHY mode?
> > 
> > Any updates on these two topics?
> > 
> Still confirming detail info with HW & design team.
> I’ll update the information that has been confirmed so far.
> This phy support DP-over-USB-C,but it's not support alt-mode which 2 lane work for DP, other 2 lane work for USB.
> TCSR phy mode is read/write reg and we can read for determine phy mode.

Ok, thanks for the explanation. From my point of view:

- Implement the DP PHY to be a part of the same driver. Each device
  supported by the usbc driver should get both PHYs.

- Make sure not to break the ABI: #phy-cells = <0> should still work and
  return USB PHY, keeping backwards compatibility. Newer devices or
  upgraded DT for old devices should return USB PHY for <... 0> and DP
  PHY for <... 1>.

- I'm not shure how to handle the USB and DP coexistence, especially in
  your case of the USB-or-DP PHY.

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-12-11  9:46             ` Dmitry Baryshkov
@ 2024-12-11 12:50               ` Xiangxu Yin
  2024-12-11 19:15                 ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-12-11 12:50 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 12/11/2024 5:46 PM, Dmitry Baryshkov wrote:
> On Wed, Dec 11, 2024 at 08:46:16AM +0800, Xiangxu Yin wrote:
>>
>>
>> On 12/10/2024 11:09 PM, Dmitry Baryshkov wrote:
>>> On Thu, Dec 05, 2024 at 08:31:24PM +0200, Dmitry Baryshkov wrote:
>>>> On Thu, Dec 05, 2024 at 09:26:47PM +0800, Xiangxu Yin wrote:
>>>>>
>>>>>
>>>>> On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>>>
>>>>>>> Extended DP support for QCS615 USB or DP phy. Differentiated between
>>>>>>> USBC and DP PHY using the match table’s type, dynamically generating
>>>>>>> different types of cfg and layout attributes during initialization based
>>>>>>> on this type. Static variables are stored in cfg, while parsed values
>>>>>>> are organized into the layout structure.
>>>>>>
>>>>>> We didn't have an understanding / conclusion whether
>>>>>> qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
>>>>>> or two PHYs being placed next to each other. Could you please start
>>>>>> your commit message by explaining it? Or even better, make that a part
>>>>>> of the cover letter for a new series touching just the USBC PHY
>>>>>> driver. DP changes don't have anything in common with the PHY changes,
>>>>>> so you can split the series into two.
>>>>>>
>>>>> Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.
>>>>
>>>> What is "DP extension"?
>>>>
>> I'm sorry confusion casued by my description. It's means extend DP implemnt for USBC phy driver.
>>>>>
>>>>> We identified that DP and USB share some common controls for phy_mode and orientation.
>>>>> Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
>>>>> while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
>>>>> It would be more efficient for a single driver to manage these controls. 
>>>>
>>>> The question is about the hardware, not about the driver.
>>>>
>>>>> Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
>>>>> Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
>>>>> we still decided to base it on the USBC extension.
>>>>
>>>> Could you please clarify, do usb3-or-dp PHYs support DP-over-USB-C? I
>>>> thought that usbc-or-dp platforms support that, but they don't
>>>> support DP+USB pin configuration. Note, the question is broader than
>>>> just QCS615, it covers the PHY type itself.
>>>>
>>>> Also, is TCSR configuration read/write or read-only? Are we supposed to
>>>> set the register from OS or are we supposed to read it and thus detemine
>>>> the PHY mode?
>>>
>>> Any updates on these two topics?
>>>
>> Still confirming detail info with HW & design team.
>> I’ll update the information that has been confirmed so far.
>> This phy support DP-over-USB-C,but it's not support alt-mode which 2 lane work for DP, other 2 lane work for USB.
>> TCSR phy mode is read/write reg and we can read for determine phy mode.
> 
> Ok, thanks for the explanation. From my point of view:
> 
> - Implement the DP PHY to be a part of the same driver. Each device
>   supported by the usbc driver should get both PHYs.
> 
> - Make sure not to break the ABI: #phy-cells = <0> should still work and
>   return USB PHY, keeping backwards compatibility. Newer devices or
>   upgraded DT for old devices should return USB PHY for <... 0> and DP
>   PHY for <... 1>.
> 
Yes, currently we have implemented like your description,
Each deivce shoud get both PHYs, DP PHY for <... 1> and USB PHY for <... 0>.
> - I'm not shure how to handle the USB and DP coexistence, especially in
>   your case of the USB-or-DP PHY.
> 
For coexistence process:

When we start implement DP part, usb driver team said only need config TCSR phy mode and orientation during switch in USB-C port.
Based on your previous comments avout SW_PWRDN, I'm confirming with the USB team whether SW_REST/SWPWRDN/START_CTRL registers might affect DP.

Anyway, even though the original SoC design supports DP or USB over Type-C,
but on QCS615 ADP AIR platform, there are only four USB-A port which works with 'qcs615-qmp-usb3-phy' driver, and no USB-C port.
DP port is mappped from usb pin to the video out sub-board.
so we are unable to verify the switching case between DP and USB devices under USB-C.

However, I'm also confirming whether anything other will affect USB and DP each other.



^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-12-11 12:50               ` Xiangxu Yin
@ 2024-12-11 19:15                 ` Dmitry Baryshkov
  2024-12-18 12:55                   ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-12-11 19:15 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Wed, Dec 11, 2024 at 08:50:02PM +0800, Xiangxu Yin wrote:
> 
> 
> On 12/11/2024 5:46 PM, Dmitry Baryshkov wrote:
> > On Wed, Dec 11, 2024 at 08:46:16AM +0800, Xiangxu Yin wrote:
> >>
> >>
> >> On 12/10/2024 11:09 PM, Dmitry Baryshkov wrote:
> >>> On Thu, Dec 05, 2024 at 08:31:24PM +0200, Dmitry Baryshkov wrote:
> >>>> On Thu, Dec 05, 2024 at 09:26:47PM +0800, Xiangxu Yin wrote:
> >>>>>
> >>>>>
> >>>>> On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
> >>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>>>>
> >>>>>>> Extended DP support for QCS615 USB or DP phy. Differentiated between
> >>>>>>> USBC and DP PHY using the match table’s type, dynamically generating
> >>>>>>> different types of cfg and layout attributes during initialization based
> >>>>>>> on this type. Static variables are stored in cfg, while parsed values
> >>>>>>> are organized into the layout structure.
> >>>>>>
> >>>>>> We didn't have an understanding / conclusion whether
> >>>>>> qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
> >>>>>> or two PHYs being placed next to each other. Could you please start
> >>>>>> your commit message by explaining it? Or even better, make that a part
> >>>>>> of the cover letter for a new series touching just the USBC PHY
> >>>>>> driver. DP changes don't have anything in common with the PHY changes,
> >>>>>> so you can split the series into two.
> >>>>>>
> >>>>> Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.
> >>>>
> >>>> What is "DP extension"?
> >>>>
> >> I'm sorry confusion casued by my description. It's means extend DP implemnt for USBC phy driver.
> >>>>>
> >>>>> We identified that DP and USB share some common controls for phy_mode and orientation.
> >>>>> Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
> >>>>> while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
> >>>>> It would be more efficient for a single driver to manage these controls. 
> >>>>
> >>>> The question is about the hardware, not about the driver.
> >>>>
> >>>>> Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
> >>>>> Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
> >>>>> we still decided to base it on the USBC extension.
> >>>>
> >>>> Could you please clarify, do usb3-or-dp PHYs support DP-over-USB-C? I
> >>>> thought that usbc-or-dp platforms support that, but they don't
> >>>> support DP+USB pin configuration. Note, the question is broader than
> >>>> just QCS615, it covers the PHY type itself.
> >>>>
> >>>> Also, is TCSR configuration read/write or read-only? Are we supposed to
> >>>> set the register from OS or are we supposed to read it and thus detemine
> >>>> the PHY mode?
> >>>
> >>> Any updates on these two topics?
> >>>
> >> Still confirming detail info with HW & design team.
> >> I’ll update the information that has been confirmed so far.
> >> This phy support DP-over-USB-C,but it's not support alt-mode which 2 lane work for DP, other 2 lane work for USB.
> >> TCSR phy mode is read/write reg and we can read for determine phy mode.
> > 
> > Ok, thanks for the explanation. From my point of view:
> > 
> > - Implement the DP PHY to be a part of the same driver. Each device
> >   supported by the usbc driver should get both PHYs.
> > 
> > - Make sure not to break the ABI: #phy-cells = <0> should still work and
> >   return USB PHY, keeping backwards compatibility. Newer devices or
> >   upgraded DT for old devices should return USB PHY for <... 0> and DP
> >   PHY for <... 1>.
> > 
> Yes, currently we have implemented like your description,
> Each deivce shoud get both PHYs, DP PHY for <... 1> and USB PHY for <... 0>.

Please note the backwards compatibility clause.

> > - I'm not shure how to handle the USB and DP coexistence, especially in
> >   your case of the USB-or-DP PHY.
> > 
> For coexistence process:
> 
> When we start implement DP part, usb driver team said only need config TCSR phy mode and orientation during switch in USB-C port.
> Based on your previous comments avout SW_PWRDN, I'm confirming with the USB team whether SW_REST/SWPWRDN/START_CTRL registers might affect DP.

Thanks!

> Anyway, even though the original SoC design supports DP or USB over Type-C,
> but on QCS615 ADP AIR platform, there are only four USB-A port which works with 'qcs615-qmp-usb3-phy' driver, and no USB-C port.
> DP port is mappped from usb pin to the video out sub-board.
> so we are unable to verify the switching case between DP and USB devices under USB-C.

That's also fine. We will get to that point once MSM8998 / SDM660
get USB-C support (the only current blocker is the support for the
TYPEC block of the PMI8998).

> However, I'm also confirming whether anything other will affect USB and DP each other.

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-12-11 19:15                 ` Dmitry Baryshkov
@ 2024-12-18 12:55                   ` Xiangxu Yin
  2024-12-19 21:38                     ` Dmitry Baryshkov
  2024-12-20  0:01                     ` Dmitry Baryshkov
  0 siblings, 2 replies; 60+ messages in thread
From: Xiangxu Yin @ 2024-12-18 12:55 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 12/12/2024 3:15 AM, Dmitry Baryshkov wrote:
> On Wed, Dec 11, 2024 at 08:50:02PM +0800, Xiangxu Yin wrote:
>>
>>
>> On 12/11/2024 5:46 PM, Dmitry Baryshkov wrote:
>>> On Wed, Dec 11, 2024 at 08:46:16AM +0800, Xiangxu Yin wrote:
>>>>
>>>>
>>>> On 12/10/2024 11:09 PM, Dmitry Baryshkov wrote:
>>>>> On Thu, Dec 05, 2024 at 08:31:24PM +0200, Dmitry Baryshkov wrote:
>>>>>> On Thu, Dec 05, 2024 at 09:26:47PM +0800, Xiangxu Yin wrote:
>>>>>>>
>>>>>>>
>>>>>>> On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
>>>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>>>>>
>>>>>>>>> Extended DP support for QCS615 USB or DP phy. Differentiated between
>>>>>>>>> USBC and DP PHY using the match table’s type, dynamically generating
>>>>>>>>> different types of cfg and layout attributes during initialization based
>>>>>>>>> on this type. Static variables are stored in cfg, while parsed values
>>>>>>>>> are organized into the layout structure.
>>>>>>>>
>>>>>>>> We didn't have an understanding / conclusion whether
>>>>>>>> qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
>>>>>>>> or two PHYs being placed next to each other. Could you please start
>>>>>>>> your commit message by explaining it? Or even better, make that a part
>>>>>>>> of the cover letter for a new series touching just the USBC PHY
>>>>>>>> driver. DP changes don't have anything in common with the PHY changes,
>>>>>>>> so you can split the series into two.
>>>>>>>>
>>>>>>> Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.
>>>>>>
>>>>>> What is "DP extension"?
>>>>>>
>>>> I'm sorry confusion casued by my description. It's means extend DP implemnt for USBC phy driver.
>>>>>>>
>>>>>>> We identified that DP and USB share some common controls for phy_mode and orientation.
>>>>>>> Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
>>>>>>> while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
>>>>>>> It would be more efficient for a single driver to manage these controls. 
>>>>>>
>>>>>> The question is about the hardware, not about the driver.
>>>>>>
>>>>>>> Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
>>>>>>> Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
>>>>>>> we still decided to base it on the USBC extension.
>>>>>>
>>>>>> Could you please clarify, do usb3-or-dp PHYs support DP-over-USB-C? I
>>>>>> thought that usbc-or-dp platforms support that, but they don't
>>>>>> support DP+USB pin configuration. Note, the question is broader than
>>>>>> just QCS615, it covers the PHY type itself.
>>>>>>
>>>>>> Also, is TCSR configuration read/write or read-only? Are we supposed to
>>>>>> set the register from OS or are we supposed to read it and thus detemine
>>>>>> the PHY mode?
>>>>>
>>>>> Any updates on these two topics?
>>>>>
>>>> Still confirming detail info with HW & design team.
>>>> I’ll update the information that has been confirmed so far.
>>>> This phy support DP-over-USB-C,but it's not support alt-mode which 2 lane work for DP, other 2 lane work for USB.
>>>> TCSR phy mode is read/write reg and we can read for determine phy mode.
>>>
>>> Ok, thanks for the explanation. From my point of view:
>>>
>>> - Implement the DP PHY to be a part of the same driver. Each device
>>>   supported by the usbc driver should get both PHYs.
>>>
>>> - Make sure not to break the ABI: #phy-cells = <0> should still work and
>>>   return USB PHY, keeping backwards compatibility. Newer devices or
>>>   upgraded DT for old devices should return USB PHY for <... 0> and DP
>>>   PHY for <... 1>.
>>>
>> Yes, currently we have implemented like your description,
>> Each deivce shoud get both PHYs, DP PHY for <... 1> and USB PHY for <... 0>.
> 
> Please note the backwards compatibility clause.
> 
For the USB node, we kept the same implementation as the original function interface, and the devicetree node definition also remains unchanged.
In subsequent patches, I will follow Krzysztof’s suggestion to use a separate DT-binding to describe the DP PHY configuration, 
without making changes to the USB devicetree and DT-binding implementation.
>>> - I'm not shure how to handle the USB and DP coexistence, especially in
>>>   your case of the USB-or-DP PHY.
>>>
>> For coexistence process:
>>
>> When we start implement DP part, usb driver team said only need config TCSR phy mode and orientation during switch in USB-C port.
>> Based on your previous comments avout SW_PWRDN, I'm confirming with the USB team whether SW_REST/SWPWRDN/START_CTRL registers might affect DP.
> 
> Thanks!
> 
>> Anyway, even though the original SoC design supports DP or USB over Type-C,
>> but on QCS615 ADP AIR platform, there are only four USB-A port which works with 'qcs615-qmp-usb3-phy' driver, and no USB-C port.
>> DP port is mappped from usb pin to the video out sub-board.
>> so we are unable to verify the switching case between DP and USB devices under USB-C.
> 
> That's also fine. We will get to that point once MSM8998 / SDM660
> get USB-C support (the only current blocker is the support for the
> TYPEC block of the PMI8998).
> 
I can't access MSM8998 / SDM660 documents now, but I have confirmed detail info about USB & DP phy design for sm6150.

The 'usb-ssphy-qmp-usb3-or-dp PHY' on the current platform is essentially composed of three sub-PHYs, 
which can even be considered as three separate PHYs: USB3 primary PHY, USB3 secondary PHY, and USB3 DP PHY.

On the QCS615, the USB primary PHY is currently used to handle USB 3.0 communication for the previously mentioned four USB Type-A ports, 
while the USB3 secondary PHY and USB3 DP PHY are used for the output of the Type-C port,
but since the Type-C port is forcibly pin-to-pin configured to the video out board, the Type-C port will always configure as DP PHY.

The internal registers of these three PHYs are independent of each other, Neither their respective SWPWR_DN nor SWRST will affect the other two PHYs.
Additionally, there was a misunderstanding about the orientation previously.
The USB orientation setting only affects the current PHY and does not impact the DP PHY. The DP PHY is configured in the DP_PHY_CFG_1.

TSCR_PHY_MODE can specify which PHY outputs to the Type-C port, and the global reset will simultaneously reset the two associated PHYs. 
Therefore, the correct switching process is as follows.
When switching the inserted device:
	1.Identify the PHY type.
	2.Enable the regulator.
	3.Trigger a reset.
	4.Enable the clock.
	5.Configure PHY type related orientation
	6.switch the TCSR PHY mode.
	7.Configure the registers of PHY.
During release:
	1.Reset.
	2.Disable the clock.
	3.Disable the regulator.

Our current design overall complies with this process, but it lacks the configuration for DP_PHY_CFG_1.

Shall we continue the discussion to clarify remain comments of the USBC driver?

>> However, I'm also confirming whether anything other will affect USB and DP each other.
> 


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration
  2024-12-05 11:40           ` Dmitry Baryshkov
@ 2024-12-19 10:36             ` Xiangxu Yin
  2024-12-19 21:45               ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2024-12-19 10:36 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 12/5/2024 7:40 PM, Dmitry Baryshkov wrote:
> On Thu, 5 Dec 2024 at 13:28, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>
>>
>>
>> On 12/2/2024 6:46 PM, Dmitry Baryshkov wrote:
>>> On Mon, Dec 02, 2024 at 04:40:05PM +0800, Xiangxu Yin wrote:
>>>>
>>>>
>>>> On 11/29/2024 9:50 PM, Dmitry Baryshkov wrote:
>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>>
>>>>>> Add the ability to configure lane mapping for the DP controller. This is
>>>>>> required when the platform's lane mapping does not follow the default
>>>>>> order (0, 1, 2, 3). The mapping rules are now configurable via the
>>>>>> `data-lane` property in the devicetree. This property defines the
>>>>>> logical-to-physical lane mapping sequence, ensuring correct lane
>>>>>> assignment for non-default configurations.
>>>>>>
>>>>>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
>>>>>> ---
>>>>>>  drivers/gpu/drm/msm/dp/dp_catalog.c | 11 +++++------
>>>>>>  drivers/gpu/drm/msm/dp/dp_catalog.h |  2 +-
>>>>>>  drivers/gpu/drm/msm/dp/dp_ctrl.c    |  2 +-
>>>>>>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 ++++++++++---
>>>>>>  drivers/gpu/drm/msm/dp/dp_panel.h   |  3 +++
>>>>>>  5 files changed, 20 insertions(+), 11 deletions(-)
>>>>>>
>>>
>>>>>> @@ -461,6 +460,7 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>>>>>>         struct msm_dp_panel_private *panel;
>>>>>>         struct device_node *of_node;
>>>>>>         int cnt;
>>>>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3};
>>>>>>
>>>>>>         panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
>>>>>>         of_node = panel->dev->of_node;
>>>>>> @@ -474,10 +474,17 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>>>>>>                 cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
>>>>>>         }
>>>>>>
>>>>>> -       if (cnt > 0)
>>>>>> +       if (cnt > 0) {
>>>>>> +               struct device_node *endpoint;
>>>>>> +
>>>>>>                 msm_dp_panel->max_dp_lanes = cnt;
>>>>>> -       else
>>>>>> +               endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1);
>>>>>> +               of_property_read_u32_array(endpoint, "data-lanes", lane_map, cnt);
>>>>>> +       } else {
>>>>>>                 msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
>>>>>> +       }
>>>>>
>>>>> Why? This sounds more like dp_catalog or (after the refactoring at
>>>>> [1]) dp_ctrl. But not the dp_panel.
>>>>>
>>>>> [1] https://patchwork.freedesktop.org/project/freedreno/series/?ordering=-last_updated
>>>>>
>>>> We are used the same prop 'data-lanes = <3 2 0 1>' in mdss_dp_out to keep similar behaviour with dsi_host_parse_lane_data.
>>>> From the modules used, catalog seems more appropriate, but since the max_dp_lanes is parsed at dp_panel, it has been placed here.
>>>> Should lane_map parsing in msm_dp_catalog_get, and keep max_dp_lanes parsing at the dp_panel?
>>>
>>> msm_dp_catalog_get() is going to be removed. Since the functions that
>>> are going to use it are in dp_ctrl module, I thought that dp_ctrl.c is
>>> the best place. A better option might be to move max_dp_lanes and
>>> max_dp_link_rate to dp_link.c as those are link params. Then
>>> lane_mapping also logically becomes a part of dp_link module.
>>>
>>> But now I have a more important question (triggered by Krishna's email
>>> about SAR2130P's USB): if the lanes are swapped, does USB 3 work on that
>>> platform? Or is it being demoted to USB 2 with nobody noticing that?
>>>
>>> If lanes 0/1 and 2/3 are swapped, shouldn't it be handled in the QMP
>>> PHY, where we handle lanes and orientation switching?
>>>
>> I have checked the DP hardware programming guide and also discussed it with Krishna.
>>
>> According to the HPG section '3.4.2 PN and Lane Swap: PHY supports PN swap for mainlink and AUX, but it doesn't support lane swap feature.'
>>
>> The lane swap mainly refers to the logical to physical mapping between the DP controller and the DP PHY. The PHY handles polarity inversion, and the lane map does not affect USB behavior.
>>
>> On the QCS615 platform, we have also tested when DP works with lane swap, other USB 3.0 ports can works normally at super speed.
> 
> "Other USB 3.0 ports"? What does that mean? Please correct me if I'm
> wrong, you should have a USB+DP combo port that is being managed with
> combo PHY. Does USB 3 work on that port?
> 
> In other words, where the order of lanes is actually inverted? Between
> DP and combo PHY? Within combo PHY? Between the PHY and the pinout?
> Granted that SM6150 was supported in msm-4.14 could you possibly point
> out a corresponding commit or a set of commits from that kernel?
> 
For "Other USB 3.0 ports", as replied in USBC driver, USB3 primary phy works for other four USB type-A port.

The REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING mapping determines how logical lanes (0, 1, 2, 3) map to physical lanes sent to the PHY.
This ensures alignment with hardware requirements.
The PHY’s polarity inversion only adjusts signal polarity and doesn’t affect lane mapping.
Both DP ctrl and PHY lane related config will not affect USB phy.

Without extra Type-C mapping, the DP controller’s mapping indirectly decides how signals are transmitted through Type-C.
Mapping ensures proper data transmission and compatibility across interfaces.

We only found sm6150 need this lane mapping config, 
For msm 4.14, please refer these links,
https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi (qcom,logical2physical-lane-map)
https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/drivers/gpu/drm/msm/dp/dp_parser.c (dp_parser_misc)
https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/drivers/gpu/drm/msm/dp/dp_catalog_v200.c (dp_catalog_ctrl_lane_mapping_v200)

If need process orientation info like dp_catalog_ctrl_lane_mapping_v200, 
then 
if implement in DP phy, then we need config dp_link register in PHY,
if implement in DP link, then we need pass orientation info to DP driver, perhaps we could add a new attribute to the phy_configure_opts_dp structure to pass this.
Do you have any suggestions?

>>
>> Additionally, if it were placed on the PHY side, the PHY would need access to dp_link’s domain which can access REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING.
> 
> I was thinking about inverting the SW_PORTSEL_VAL bit.
> 
>> Therefore, we believe that the  max_dp_link_rate,max_dp_lanes and lane_map move to dp_link side is better.
>>
>>>>>> +
>>>>>> +       memcpy(msm_dp_panel->lane_map, lane_map, msm_dp_panel->max_dp_lanes * sizeof(u32));
>>>>>>
>>>>>>         msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node);
>>>>>>         if (!msm_dp_panel->max_dp_link_rate)
>>>>>> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
>>>>>> index 0e944db3adf2f187f313664fe80cf540ec7a19f2..7603b92c32902bd3d4485539bd6308537ff75a2c 100644
>>>>>> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
>>>>>> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
>>>>>> @@ -11,6 +11,8 @@
>>>>>>  #include "dp_aux.h"
>>>>>>  #include "dp_link.h"
>>>>>>
>>>>>> +#define DP_MAX_NUM_DP_LANES    4
>>>>>> +
>>>>>>  struct edid;
>>>>>>
>>>>>>  struct msm_dp_display_mode {
>>>>>> @@ -46,6 +48,7 @@ struct msm_dp_panel {
>>>>>>         bool video_test;
>>>>>>         bool vsc_sdp_supported;
>>>>>>
>>>>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES];
>>>>>>         u32 max_dp_lanes;
>>>>>>         u32 max_dp_link_rate;
>>>>>>
>>>>>>
>>>>>> --
>>>>>> 2.25.1
>>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>> --
>>>> linux-phy mailing list
>>>> linux-phy@lists.infradead.org
>>>> https://lists.infradead.org/mailman/listinfo/linux-phy
>>>
>>
> 
> 


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-12-18 12:55                   ` Xiangxu Yin
@ 2024-12-19 21:38                     ` Dmitry Baryshkov
  2024-12-20  0:01                     ` Dmitry Baryshkov
  1 sibling, 0 replies; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-12-19 21:38 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Wed, Dec 18, 2024 at 08:55:54PM +0800, Xiangxu Yin wrote:
> 
> 
> On 12/12/2024 3:15 AM, Dmitry Baryshkov wrote:
> > On Wed, Dec 11, 2024 at 08:50:02PM +0800, Xiangxu Yin wrote:
> >>
> >>
> >> On 12/11/2024 5:46 PM, Dmitry Baryshkov wrote:
> >>> On Wed, Dec 11, 2024 at 08:46:16AM +0800, Xiangxu Yin wrote:
> >>>>
> >>>>
> >>>> On 12/10/2024 11:09 PM, Dmitry Baryshkov wrote:
> >>>>> On Thu, Dec 05, 2024 at 08:31:24PM +0200, Dmitry Baryshkov wrote:
> >>>>>> On Thu, Dec 05, 2024 at 09:26:47PM +0800, Xiangxu Yin wrote:
> >>>>>>>
> >>>>>>>
> >>>>>>> On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
> >>>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>>>>>>
> >>>>>>>>> Extended DP support for QCS615 USB or DP phy. Differentiated between
> >>>>>>>>> USBC and DP PHY using the match table’s type, dynamically generating
> >>>>>>>>> different types of cfg and layout attributes during initialization based
> >>>>>>>>> on this type. Static variables are stored in cfg, while parsed values
> >>>>>>>>> are organized into the layout structure.
> >>>>>>>>
> >>>>>>>> We didn't have an understanding / conclusion whether
> >>>>>>>> qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
> >>>>>>>> or two PHYs being placed next to each other. Could you please start
> >>>>>>>> your commit message by explaining it? Or even better, make that a part
> >>>>>>>> of the cover letter for a new series touching just the USBC PHY
> >>>>>>>> driver. DP changes don't have anything in common with the PHY changes,
> >>>>>>>> so you can split the series into two.
> >>>>>>>>
> >>>>>>> Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.
> >>>>>>
> >>>>>> What is "DP extension"?
> >>>>>>
> >>>> I'm sorry confusion casued by my description. It's means extend DP implemnt for USBC phy driver.
> >>>>>>>
> >>>>>>> We identified that DP and USB share some common controls for phy_mode and orientation.
> >>>>>>> Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
> >>>>>>> while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
> >>>>>>> It would be more efficient for a single driver to manage these controls. 
> >>>>>>
> >>>>>> The question is about the hardware, not about the driver.
> >>>>>>
> >>>>>>> Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
> >>>>>>> Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
> >>>>>>> we still decided to base it on the USBC extension.
> >>>>>>
> >>>>>> Could you please clarify, do usb3-or-dp PHYs support DP-over-USB-C? I
> >>>>>> thought that usbc-or-dp platforms support that, but they don't
> >>>>>> support DP+USB pin configuration. Note, the question is broader than
> >>>>>> just QCS615, it covers the PHY type itself.
> >>>>>>
> >>>>>> Also, is TCSR configuration read/write or read-only? Are we supposed to
> >>>>>> set the register from OS or are we supposed to read it and thus detemine
> >>>>>> the PHY mode?
> >>>>>
> >>>>> Any updates on these two topics?
> >>>>>
> >>>> Still confirming detail info with HW & design team.
> >>>> I’ll update the information that has been confirmed so far.
> >>>> This phy support DP-over-USB-C,but it's not support alt-mode which 2 lane work for DP, other 2 lane work for USB.
> >>>> TCSR phy mode is read/write reg and we can read for determine phy mode.
> >>>
> >>> Ok, thanks for the explanation. From my point of view:
> >>>
> >>> - Implement the DP PHY to be a part of the same driver. Each device
> >>>   supported by the usbc driver should get both PHYs.
> >>>
> >>> - Make sure not to break the ABI: #phy-cells = <0> should still work and
> >>>   return USB PHY, keeping backwards compatibility. Newer devices or
> >>>   upgraded DT for old devices should return USB PHY for <... 0> and DP
> >>>   PHY for <... 1>.
> >>>
> >> Yes, currently we have implemented like your description,
> >> Each deivce shoud get both PHYs, DP PHY for <... 1> and USB PHY for <... 0>.
> > 
> > Please note the backwards compatibility clause.
> > 
> For the USB node, we kept the same implementation as the original function interface, and the devicetree node definition also remains unchanged.
> In subsequent patches, I will follow Krzysztof’s suggestion to use a separate DT-binding to describe the DP PHY configuration, 
> without making changes to the USB devicetree and DT-binding implementation.

NO! See below. But basically NAK for implementing a separate bindings
and separate DP PHY driver. Also you can't just leave old platforms. All
of them have the same hardware, so all these platforms can be updated
simultaneously.

> >>> - I'm not shure how to handle the USB and DP coexistence, especially in
> >>>   your case of the USB-or-DP PHY.
> >>>
> >> For coexistence process:
> >>
> >> When we start implement DP part, usb driver team said only need config TCSR phy mode and orientation during switch in USB-C port.
> >> Based on your previous comments avout SW_PWRDN, I'm confirming with the USB team whether SW_REST/SWPWRDN/START_CTRL registers might affect DP.
> > 
> > Thanks!
> > 
> >> Anyway, even though the original SoC design supports DP or USB over Type-C,
> >> but on QCS615 ADP AIR platform, there are only four USB-A port which works with 'qcs615-qmp-usb3-phy' driver, and no USB-C port.
> >> DP port is mappped from usb pin to the video out sub-board.
> >> so we are unable to verify the switching case between DP and USB devices under USB-C.
> > 
> > That's also fine. We will get to that point once MSM8998 / SDM660
> > get USB-C support (the only current blocker is the support for the
> > TYPEC block of the PMI8998).
> > 
> I can't access MSM8998 / SDM660 documents now, but I have confirmed detail info about USB & DP phy design for sm6150.

The same PHY is present on SM6115 / SM4250 / QRB4210 and QCM2290 /
QRB2210, but those platforms don't seem to have a proper DisplayPort,
only the DP PHY as a part of this block. Please try gaining access to
the documents and make a design decision rather than making an ad-hoc
solutions.

> The 'usb-ssphy-qmp-usb3-or-dp PHY' on the current platform is essentially composed of three sub-PHYs, 
> which can even be considered as three separate PHYs: USB3 primary PHY, USB3 secondary PHY, and USB3 DP PHY.

Is there any software or hardware connection between primary and
secondary USB3 PHYs? It doesn't seem so.

> On the QCS615, the USB primary PHY is currently used to handle USB 3.0 communication for the previously mentioned four USB Type-A ports, 

currently? Can it be used in any other way?

> while the USB3 secondary PHY and USB3 DP PHY are used for the output of the Type-C port,
> but since the Type-C port is forcibly pin-to-pin configured to the video out board, the Type-C port will always configure as DP PHY.

This is the case for the particular board, not for the platform itself.

> 
> The internal registers of these three PHYs are independent of each other, Neither their respective SWPWR_DN nor SWRST will affect the other two PHYs.
> Additionally, there was a misunderstanding about the orientation previously.
> The USB orientation setting only affects the current PHY and does not impact the DP PHY. The DP PHY is configured in the DP_PHY_CFG_1.

Are you saying that those two registers are really independent? Well...
That might make sense as the two PHYs are mostly independent.

> TSCR_PHY_MODE can specify which PHY outputs to the Type-C port, and the global reset will simultaneously reset the two associated PHYs. 

Having the global reset means that there should be one driver handling
both PHYs.

> Therefore, the correct switching process is as follows.
> When switching the inserted device:
> 	1.Identify the PHY type.
> 	2.Enable the regulator.
> 	3.Trigger a reset.
> 	4.Enable the clock.
> 	5.Configure PHY type related orientation
> 	6.switch the TCSR PHY mode.
> 	7.Configure the registers of PHY.
> During release:
> 	1.Reset.
> 	2.Disable the clock.
> 	3.Disable the regulator.

What should we do during orientation switch? During the change between
native USB over USB-C and DP-over-USB-C? Please provide full
information, not the limited set.

> Our current design overall complies with this process, but it lacks the configuration for DP_PHY_CFG_1.
> 
> Shall we continue the discussion to clarify remain comments of the USBC driver?

As I wrote earlier, change USBC driver to provide either two PHYs
simultaneously or just one PHY and a way to switch modes on the fly
(personally I think that two PHYs better match the USBC PHY hardware and
the normal Combo PHY design).

Do we need to program this DP PHY differently for the DP-native and
DP-over-USB-C cases?

> >> However, I'm also confirming whether anything other will affect USB and DP each other.

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration
  2024-12-19 10:36             ` Xiangxu Yin
@ 2024-12-19 21:45               ` Dmitry Baryshkov
  2025-03-05 10:16                 ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-12-19 21:45 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Thu, Dec 19, 2024 at 06:36:38PM +0800, Xiangxu Yin wrote:
> 
> 
> On 12/5/2024 7:40 PM, Dmitry Baryshkov wrote:
> > On Thu, 5 Dec 2024 at 13:28, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>
> >>
> >>
> >> On 12/2/2024 6:46 PM, Dmitry Baryshkov wrote:
> >>> On Mon, Dec 02, 2024 at 04:40:05PM +0800, Xiangxu Yin wrote:
> >>>>
> >>>>
> >>>> On 11/29/2024 9:50 PM, Dmitry Baryshkov wrote:
> >>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>>>
> >>>>>> Add the ability to configure lane mapping for the DP controller. This is
> >>>>>> required when the platform's lane mapping does not follow the default
> >>>>>> order (0, 1, 2, 3). The mapping rules are now configurable via the
> >>>>>> `data-lane` property in the devicetree. This property defines the
> >>>>>> logical-to-physical lane mapping sequence, ensuring correct lane
> >>>>>> assignment for non-default configurations.
> >>>>>>
> >>>>>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> >>>>>> ---
> >>>>>>  drivers/gpu/drm/msm/dp/dp_catalog.c | 11 +++++------
> >>>>>>  drivers/gpu/drm/msm/dp/dp_catalog.h |  2 +-
> >>>>>>  drivers/gpu/drm/msm/dp/dp_ctrl.c    |  2 +-
> >>>>>>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 ++++++++++---
> >>>>>>  drivers/gpu/drm/msm/dp/dp_panel.h   |  3 +++
> >>>>>>  5 files changed, 20 insertions(+), 11 deletions(-)
> >>>>>>
> >>>
> >>>>>> @@ -461,6 +460,7 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
> >>>>>>         struct msm_dp_panel_private *panel;
> >>>>>>         struct device_node *of_node;
> >>>>>>         int cnt;
> >>>>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3};
> >>>>>>
> >>>>>>         panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
> >>>>>>         of_node = panel->dev->of_node;
> >>>>>> @@ -474,10 +474,17 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
> >>>>>>                 cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
> >>>>>>         }
> >>>>>>
> >>>>>> -       if (cnt > 0)
> >>>>>> +       if (cnt > 0) {
> >>>>>> +               struct device_node *endpoint;
> >>>>>> +
> >>>>>>                 msm_dp_panel->max_dp_lanes = cnt;
> >>>>>> -       else
> >>>>>> +               endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1);
> >>>>>> +               of_property_read_u32_array(endpoint, "data-lanes", lane_map, cnt);
> >>>>>> +       } else {
> >>>>>>                 msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
> >>>>>> +       }
> >>>>>
> >>>>> Why? This sounds more like dp_catalog or (after the refactoring at
> >>>>> [1]) dp_ctrl. But not the dp_panel.
> >>>>>
> >>>>> [1] https://patchwork.freedesktop.org/project/freedreno/series/?ordering=-last_updated
> >>>>>
> >>>> We are used the same prop 'data-lanes = <3 2 0 1>' in mdss_dp_out to keep similar behaviour with dsi_host_parse_lane_data.
> >>>> From the modules used, catalog seems more appropriate, but since the max_dp_lanes is parsed at dp_panel, it has been placed here.
> >>>> Should lane_map parsing in msm_dp_catalog_get, and keep max_dp_lanes parsing at the dp_panel?
> >>>
> >>> msm_dp_catalog_get() is going to be removed. Since the functions that
> >>> are going to use it are in dp_ctrl module, I thought that dp_ctrl.c is
> >>> the best place. A better option might be to move max_dp_lanes and
> >>> max_dp_link_rate to dp_link.c as those are link params. Then
> >>> lane_mapping also logically becomes a part of dp_link module.
> >>>
> >>> But now I have a more important question (triggered by Krishna's email
> >>> about SAR2130P's USB): if the lanes are swapped, does USB 3 work on that
> >>> platform? Or is it being demoted to USB 2 with nobody noticing that?
> >>>
> >>> If lanes 0/1 and 2/3 are swapped, shouldn't it be handled in the QMP
> >>> PHY, where we handle lanes and orientation switching?
> >>>
> >> I have checked the DP hardware programming guide and also discussed it with Krishna.
> >>
> >> According to the HPG section '3.4.2 PN and Lane Swap: PHY supports PN swap for mainlink and AUX, but it doesn't support lane swap feature.'
> >>
> >> The lane swap mainly refers to the logical to physical mapping between the DP controller and the DP PHY. The PHY handles polarity inversion, and the lane map does not affect USB behavior.
> >>
> >> On the QCS615 platform, we have also tested when DP works with lane swap, other USB 3.0 ports can works normally at super speed.
> > 
> > "Other USB 3.0 ports"? What does that mean? Please correct me if I'm
> > wrong, you should have a USB+DP combo port that is being managed with
> > combo PHY. Does USB 3 work on that port?
> > 
> > In other words, where the order of lanes is actually inverted? Between
> > DP and combo PHY? Within combo PHY? Between the PHY and the pinout?
> > Granted that SM6150 was supported in msm-4.14 could you possibly point
> > out a corresponding commit or a set of commits from that kernel?
> > 
> For "Other USB 3.0 ports", as replied in USBC driver, USB3 primary phy works for other four USB type-A port.

So if that's the USB3 primary, then why do you mention here at all? We
are taling about the secondary USB3 + DP.

> The REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING mapping determines how logical lanes (0, 1, 2, 3) map to physical lanes sent to the PHY.
> This ensures alignment with hardware requirements.
> The PHY’s polarity inversion only adjusts signal polarity and doesn’t affect lane mapping.
> Both DP ctrl and PHY lane related config will not affect USB phy.

Probably we misundersand each other. The DP PHY should have orientation
switch register, which controls whether 2-lane DP uses lanes 0/1 or 2/3.
Can you use that register?

Also, could you _please_ answer the question that I have asked? Is the
order of lanes inverted between the DP controller and DP PHY? Or between
DP PHY and the DP connector? If one uses USB3 signals coming from this
port (yes, on the other board, not on the Ride), would they also need to
switch the order of USB3 lanes? If one uses a DP-over-USB-C, are DP
lanes are swapped?

> Without extra Type-C mapping, the DP controller’s mapping indirectly decides how signals are transmitted through Type-C.
> Mapping ensures proper data transmission and compatibility across interfaces.
> 
> We only found sm6150 need this lane mapping config, 
> For msm 4.14, please refer these links,
> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi (qcom,logical2physical-lane-map)
> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/drivers/gpu/drm/msm/dp/dp_parser.c (dp_parser_misc)
> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/drivers/gpu/drm/msm/dp/dp_catalog_v200.c (dp_catalog_ctrl_lane_mapping_v200)
> 
> If need process orientation info like dp_catalog_ctrl_lane_mapping_v200, 
> then 
> if implement in DP phy, then we need config dp_link register in PHY,
> if implement in DP link, then we need pass orientation info to DP driver, perhaps we could add a new attribute to the phy_configure_opts_dp structure to pass this.
> Do you have any suggestions?

Does SW_PORTSEL_VAL affect the DP lanes on this platform?

> 
> >>
> >> Additionally, if it were placed on the PHY side, the PHY would need access to dp_link’s domain which can access REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING.
> > 
> > I was thinking about inverting the SW_PORTSEL_VAL bit.
> > 
> >> Therefore, we believe that the  max_dp_link_rate,max_dp_lanes and lane_map move to dp_link side is better.
> >>
> >>>>>> +
> >>>>>> +       memcpy(msm_dp_panel->lane_map, lane_map, msm_dp_panel->max_dp_lanes * sizeof(u32));
> >>>>>>
> >>>>>>         msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node);
> >>>>>>         if (!msm_dp_panel->max_dp_link_rate)
> >>>>>> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
> >>>>>> index 0e944db3adf2f187f313664fe80cf540ec7a19f2..7603b92c32902bd3d4485539bd6308537ff75a2c 100644
> >>>>>> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
> >>>>>> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
> >>>>>> @@ -11,6 +11,8 @@
> >>>>>>  #include "dp_aux.h"
> >>>>>>  #include "dp_link.h"
> >>>>>>
> >>>>>> +#define DP_MAX_NUM_DP_LANES    4
> >>>>>> +
> >>>>>>  struct edid;
> >>>>>>
> >>>>>>  struct msm_dp_display_mode {
> >>>>>> @@ -46,6 +48,7 @@ struct msm_dp_panel {
> >>>>>>         bool video_test;
> >>>>>>         bool vsc_sdp_supported;
> >>>>>>
> >>>>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES];
> >>>>>>         u32 max_dp_lanes;
> >>>>>>         u32 max_dp_link_rate;
> >>>>>>
> >>>>>>
> >>>>>> --
> >>>>>> 2.25.1
> >>>>>>
> >>>>>
> >>>>>
> >>>>
> >>>>
> >>>> --
> >>>> linux-phy mailing list
> >>>> linux-phy@lists.infradead.org
> >>>> https://lists.infradead.org/mailman/listinfo/linux-phy
> >>>
> >>
> > 
> > 
> 

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-12-18 12:55                   ` Xiangxu Yin
  2024-12-19 21:38                     ` Dmitry Baryshkov
@ 2024-12-20  0:01                     ` Dmitry Baryshkov
  2025-03-05 10:20                       ` Xiangxu Yin
  1 sibling, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2024-12-20  0:01 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Wed, Dec 18, 2024 at 08:55:54PM +0800, Xiangxu Yin wrote:
> 
> 
> On 12/12/2024 3:15 AM, Dmitry Baryshkov wrote:
> > On Wed, Dec 11, 2024 at 08:50:02PM +0800, Xiangxu Yin wrote:
> >>
> >>
> >> On 12/11/2024 5:46 PM, Dmitry Baryshkov wrote:
> >>> On Wed, Dec 11, 2024 at 08:46:16AM +0800, Xiangxu Yin wrote:
> >>>>
> >>>>
> >>>> On 12/10/2024 11:09 PM, Dmitry Baryshkov wrote:
> >>>>> On Thu, Dec 05, 2024 at 08:31:24PM +0200, Dmitry Baryshkov wrote:
> >>>>>> On Thu, Dec 05, 2024 at 09:26:47PM +0800, Xiangxu Yin wrote:
> >>>>>>>
> >>>>>>>
> >>>>>>> On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
> >>>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>>>>>>
> >>>>>>>>> Extended DP support for QCS615 USB or DP phy. Differentiated between
> >>>>>>>>> USBC and DP PHY using the match table’s type, dynamically generating
> >>>>>>>>> different types of cfg and layout attributes during initialization based
> >>>>>>>>> on this type. Static variables are stored in cfg, while parsed values
> >>>>>>>>> are organized into the layout structure.
> >>>>>>>>
> >>>>>>>> We didn't have an understanding / conclusion whether
> >>>>>>>> qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
> >>>>>>>> or two PHYs being placed next to each other. Could you please start
> >>>>>>>> your commit message by explaining it? Or even better, make that a part
> >>>>>>>> of the cover letter for a new series touching just the USBC PHY
> >>>>>>>> driver. DP changes don't have anything in common with the PHY changes,
> >>>>>>>> so you can split the series into two.
> >>>>>>>>
> >>>>>>> Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.
> >>>>>>
> >>>>>> What is "DP extension"?
> >>>>>>
> >>>> I'm sorry confusion casued by my description. It's means extend DP implemnt for USBC phy driver.
> >>>>>>>
> >>>>>>> We identified that DP and USB share some common controls for phy_mode and orientation.
> >>>>>>> Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
> >>>>>>> while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
> >>>>>>> It would be more efficient for a single driver to manage these controls. 
> >>>>>>
> >>>>>> The question is about the hardware, not about the driver.
> >>>>>>
> >>>>>>> Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
> >>>>>>> Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
> >>>>>>> we still decided to base it on the USBC extension.
> >>>>>>
> >>>>>> Could you please clarify, do usb3-or-dp PHYs support DP-over-USB-C? I
> >>>>>> thought that usbc-or-dp platforms support that, but they don't
> >>>>>> support DP+USB pin configuration. Note, the question is broader than
> >>>>>> just QCS615, it covers the PHY type itself.
> >>>>>>
> >>>>>> Also, is TCSR configuration read/write or read-only? Are we supposed to
> >>>>>> set the register from OS or are we supposed to read it and thus detemine
> >>>>>> the PHY mode?
> >>>>>
> >>>>> Any updates on these two topics?
> >>>>>
> >>>> Still confirming detail info with HW & design team.
> >>>> I’ll update the information that has been confirmed so far.
> >>>> This phy support DP-over-USB-C,but it's not support alt-mode which 2 lane work for DP, other 2 lane work for USB.
> >>>> TCSR phy mode is read/write reg and we can read for determine phy mode.
> >>>
> >>> Ok, thanks for the explanation. From my point of view:
> >>>
> >>> - Implement the DP PHY to be a part of the same driver. Each device
> >>>   supported by the usbc driver should get both PHYs.
> >>>
> >>> - Make sure not to break the ABI: #phy-cells = <0> should still work and
> >>>   return USB PHY, keeping backwards compatibility. Newer devices or
> >>>   upgraded DT for old devices should return USB PHY for <... 0> and DP
> >>>   PHY for <... 1>.
> >>>
> >> Yes, currently we have implemented like your description,
> >> Each deivce shoud get both PHYs, DP PHY for <... 1> and USB PHY for <... 0>.
> > 
> > Please note the backwards compatibility clause.
> > 
> For the USB node, we kept the same implementation as the original function interface, and the devicetree node definition also remains unchanged.
> In subsequent patches, I will follow Krzysztof’s suggestion to use a separate DT-binding to describe the DP PHY configuration, 
> without making changes to the USB devicetree and DT-binding implementation.
> >>> - I'm not shure how to handle the USB and DP coexistence, especially in
> >>>   your case of the USB-or-DP PHY.
> >>>
> >> For coexistence process:
> >>
> >> When we start implement DP part, usb driver team said only need config TCSR phy mode and orientation during switch in USB-C port.
> >> Based on your previous comments avout SW_PWRDN, I'm confirming with the USB team whether SW_REST/SWPWRDN/START_CTRL registers might affect DP.
> > 
> > Thanks!
> > 
> >> Anyway, even though the original SoC design supports DP or USB over Type-C,
> >> but on QCS615 ADP AIR platform, there are only four USB-A port which works with 'qcs615-qmp-usb3-phy' driver, and no USB-C port.
> >> DP port is mappped from usb pin to the video out sub-board.
> >> so we are unable to verify the switching case between DP and USB devices under USB-C.
> > 
> > That's also fine. We will get to that point once MSM8998 / SDM660
> > get USB-C support (the only current blocker is the support for the
> > TYPEC block of the PMI8998).
> > 
> I can't access MSM8998 / SDM660 documents now, but I have confirmed detail info about USB & DP phy design for sm6150.
> 
> The 'usb-ssphy-qmp-usb3-or-dp PHY' on the current platform is essentially composed of three sub-PHYs, 
> which can even be considered as three separate PHYs: USB3 primary PHY, USB3 secondary PHY, and USB3 DP PHY.

I've looked at sm6150-usb.dtsi and now I'm completely puzzled by your
answer. The msm-4.14 kernel lists a single USB QMP PHY at 0x88e6000,
used for the primary USB3 host. It it defined as
qcom,usb-ssphy-qmp-usb3-or-dp. Secondary USB host is listed as USB 2.0
only. So what do you mean by the USB3 secondary PHY? Which PHY and which
pins are connected to your video-out board?

> 
> On the QCS615, the USB primary PHY is currently used to handle USB 3.0 communication for the previously mentioned four USB Type-A ports, 
> while the USB3 secondary PHY and USB3 DP PHY are used for the output of the Type-C port,
> but since the Type-C port is forcibly pin-to-pin configured to the video out board, the Type-C port will always configure as DP PHY.
> 
> The internal registers of these three PHYs are independent of each other, Neither their respective SWPWR_DN nor SWRST will affect the other two PHYs.
> Additionally, there was a misunderstanding about the orientation previously.
> The USB orientation setting only affects the current PHY and does not impact the DP PHY. The DP PHY is configured in the DP_PHY_CFG_1.
> 
> TSCR_PHY_MODE can specify which PHY outputs to the Type-C port, and the global reset will simultaneously reset the two associated PHYs. 
> Therefore, the correct switching process is as follows.
> When switching the inserted device:
> 	1.Identify the PHY type.
> 	2.Enable the regulator.
> 	3.Trigger a reset.
> 	4.Enable the clock.
> 	5.Configure PHY type related orientation
> 	6.switch the TCSR PHY mode.
> 	7.Configure the registers of PHY.
> During release:
> 	1.Reset.
> 	2.Disable the clock.
> 	3.Disable the regulator.
> 
> Our current design overall complies with this process, but it lacks the configuration for DP_PHY_CFG_1.
> 
> Shall we continue the discussion to clarify remain comments of the USBC driver?
> 
> >> However, I'm also confirming whether anything other will affect USB and DP each other.
> > 
> 

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration
  2024-12-19 21:45               ` Dmitry Baryshkov
@ 2025-03-05 10:16                 ` Xiangxu Yin
  2025-03-05 21:14                   ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2025-03-05 10:16 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 12/20/2024 5:45 AM, Dmitry Baryshkov wrote:
> On Thu, Dec 19, 2024 at 06:36:38PM +0800, Xiangxu Yin wrote:
>>
>>
>> On 12/5/2024 7:40 PM, Dmitry Baryshkov wrote:
>>> On Thu, 5 Dec 2024 at 13:28, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>
>>>>
>>>>
>>>> On 12/2/2024 6:46 PM, Dmitry Baryshkov wrote:
>>>>> On Mon, Dec 02, 2024 at 04:40:05PM +0800, Xiangxu Yin wrote:
>>>>>>
>>>>>>
>>>>>> On 11/29/2024 9:50 PM, Dmitry Baryshkov wrote:
>>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>>>>
>>>>>>>> Add the ability to configure lane mapping for the DP controller. This is
>>>>>>>> required when the platform's lane mapping does not follow the default
>>>>>>>> order (0, 1, 2, 3). The mapping rules are now configurable via the
>>>>>>>> `data-lane` property in the devicetree. This property defines the
>>>>>>>> logical-to-physical lane mapping sequence, ensuring correct lane
>>>>>>>> assignment for non-default configurations.
>>>>>>>>
>>>>>>>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
>>>>>>>> ---
>>>>>>>>  drivers/gpu/drm/msm/dp/dp_catalog.c | 11 +++++------
>>>>>>>>  drivers/gpu/drm/msm/dp/dp_catalog.h |  2 +-
>>>>>>>>  drivers/gpu/drm/msm/dp/dp_ctrl.c    |  2 +-
>>>>>>>>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 ++++++++++---
>>>>>>>>  drivers/gpu/drm/msm/dp/dp_panel.h   |  3 +++
>>>>>>>>  5 files changed, 20 insertions(+), 11 deletions(-)
>>>>>>>>
>>>>>
>>>>>>>> @@ -461,6 +460,7 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>>>>>>>>         struct msm_dp_panel_private *panel;
>>>>>>>>         struct device_node *of_node;
>>>>>>>>         int cnt;
>>>>>>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3};
>>>>>>>>
>>>>>>>>         panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
>>>>>>>>         of_node = panel->dev->of_node;
>>>>>>>> @@ -474,10 +474,17 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>>>>>>>>                 cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
>>>>>>>>         }
>>>>>>>>
>>>>>>>> -       if (cnt > 0)
>>>>>>>> +       if (cnt > 0) {
>>>>>>>> +               struct device_node *endpoint;
>>>>>>>> +
>>>>>>>>                 msm_dp_panel->max_dp_lanes = cnt;
>>>>>>>> -       else
>>>>>>>> +               endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1);
>>>>>>>> +               of_property_read_u32_array(endpoint, "data-lanes", lane_map, cnt);
>>>>>>>> +       } else {
>>>>>>>>                 msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
>>>>>>>> +       }
>>>>>>>
>>>>>>> Why? This sounds more like dp_catalog or (after the refactoring at
>>>>>>> [1]) dp_ctrl. But not the dp_panel.
>>>>>>>
>>>>>>> [1] https://patchwork.freedesktop.org/project/freedreno/series/?ordering=-last_updated
>>>>>>>
>>>>>> We are used the same prop 'data-lanes = <3 2 0 1>' in mdss_dp_out to keep similar behaviour with dsi_host_parse_lane_data.
>>>>>> From the modules used, catalog seems more appropriate, but since the max_dp_lanes is parsed at dp_panel, it has been placed here.
>>>>>> Should lane_map parsing in msm_dp_catalog_get, and keep max_dp_lanes parsing at the dp_panel?
>>>>>
>>>>> msm_dp_catalog_get() is going to be removed. Since the functions that
>>>>> are going to use it are in dp_ctrl module, I thought that dp_ctrl.c is
>>>>> the best place. A better option might be to move max_dp_lanes and
>>>>> max_dp_link_rate to dp_link.c as those are link params. Then
>>>>> lane_mapping also logically becomes a part of dp_link module.
>>>>>
>>>>> But now I have a more important question (triggered by Krishna's email
>>>>> about SAR2130P's USB): if the lanes are swapped, does USB 3 work on that
>>>>> platform? Or is it being demoted to USB 2 with nobody noticing that?
>>>>>
>>>>> If lanes 0/1 and 2/3 are swapped, shouldn't it be handled in the QMP
>>>>> PHY, where we handle lanes and orientation switching?
>>>>>
>>>> I have checked the DP hardware programming guide and also discussed it with Krishna.
>>>>
>>>> According to the HPG section '3.4.2 PN and Lane Swap: PHY supports PN swap for mainlink and AUX, but it doesn't support lane swap feature.'
>>>>
>>>> The lane swap mainly refers to the logical to physical mapping between the DP controller and the DP PHY. The PHY handles polarity inversion, and the lane map does not affect USB behavior.
>>>>
>>>> On the QCS615 platform, we have also tested when DP works with lane swap, other USB 3.0 ports can works normally at super speed.
>>>
>>> "Other USB 3.0 ports"? What does that mean? Please correct me if I'm
>>> wrong, you should have a USB+DP combo port that is being managed with
>>> combo PHY. Does USB 3 work on that port?
>>>
>>> In other words, where the order of lanes is actually inverted? Between
>>> DP and combo PHY? Within combo PHY? Between the PHY and the pinout?
>>> Granted that SM6150 was supported in msm-4.14 could you possibly point
>>> out a corresponding commit or a set of commits from that kernel?
>>>
>> For "Other USB 3.0 ports", as replied in USBC driver, USB3 primary phy works for other four USB type-A port.
> 
> So if that's the USB3 primary, then why do you mention here at all? We
> are taling about the secondary USB3 + DP.
> 
OK, sorry for confusing you.
>> The REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING mapping determines how logical lanes (0, 1, 2, 3) map to physical lanes sent to the PHY.
>> This ensures alignment with hardware requirements.
>> The PHY’s polarity inversion only adjusts signal polarity and doesn’t affect lane mapping.
>> Both DP ctrl and PHY lane related config will not affect USB phy.
> 
> Probably we misundersand each other. The DP PHY should have orientation
> switch register, which controls whether 2-lane DP uses lanes 0/1 or 2/3.
> Can you use that register?
> 
Yes, DP PHY have orientation register as below.
DP_PHY_DP_PHY_CFG_1(0x88e9014) bit(7) SW_PORTSELECT
> Also, could you _please_ answer the question that I have asked? Is the
> order of lanes inverted between the DP controller and DP PHY? Or between
> DP PHY and the DP connector? If one uses USB3 signals coming from this
> port (yes, on the other board, not on the Ride), would they also need to
> switch the order of USB3 lanes? If one uses a DP-over-USB-C, are DP
> lanes are swapped?
> 
It's inverted between the DP controller and DP PHY.
If other use USB3 on the other board, will not need switch order of USB3 lanes,
If one use DP-over-USB-C, then need DP lanes swap.
>> Without extra Type-C mapping, the DP controller’s mapping indirectly decides how signals are transmitted through Type-C.
>> Mapping ensures proper data transmission and compatibility across interfaces.
>>
>> We only found sm6150 need this lane mapping config, 
>> For msm 4.14, please refer these links,
>> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi (qcom,logical2physical-lane-map)
>> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/drivers/gpu/drm/msm/dp/dp_parser.c (dp_parser_misc)
>> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/drivers/gpu/drm/msm/dp/dp_catalog_v200.c (dp_catalog_ctrl_lane_mapping_v200)
>>
>> If need process orientation info like dp_catalog_ctrl_lane_mapping_v200, 
>> then 
>> if implement in DP phy, then we need config dp_link register in PHY,
>> if implement in DP link, then we need pass orientation info to DP driver, perhaps we could add a new attribute to the phy_configure_opts_dp structure to pass this.
>> Do you have any suggestions?
> 
> Does SW_PORTSEL_VAL affect the DP lanes on this platform?
> 
SW_PORTSEL_VAL for USB3PHY_PCS_MISC_TYPEC_CTRL will not affect DP lanes in this DP or USB3 chip series.
USB3 will use USB3PHY_PCS_MISC_TYPEC_CTRL(SW_PORTSEL_VAL BIT_0) and DP will use DP_PHY_DP_PHY_CFG_1(SW_PORTSELECT BIT_7)
>>
>>>>
>>>> Additionally, if it were placed on the PHY side, the PHY would need access to dp_link’s domain which can access REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING.
>>>
>>> I was thinking about inverting the SW_PORTSEL_VAL bit.
>>>
>>>> Therefore, we believe that the  max_dp_link_rate,max_dp_lanes and lane_map move to dp_link side is better.
>>>>
>>>>>>>> +
>>>>>>>> +       memcpy(msm_dp_panel->lane_map, lane_map, msm_dp_panel->max_dp_lanes * sizeof(u32));
>>>>>>>>
>>>>>>>>         msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node);
>>>>>>>>         if (!msm_dp_panel->max_dp_link_rate)
>>>>>>>> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
>>>>>>>> index 0e944db3adf2f187f313664fe80cf540ec7a19f2..7603b92c32902bd3d4485539bd6308537ff75a2c 100644
>>>>>>>> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
>>>>>>>> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
>>>>>>>> @@ -11,6 +11,8 @@
>>>>>>>>  #include "dp_aux.h"
>>>>>>>>  #include "dp_link.h"
>>>>>>>>
>>>>>>>> +#define DP_MAX_NUM_DP_LANES    4
>>>>>>>> +
>>>>>>>>  struct edid;
>>>>>>>>
>>>>>>>>  struct msm_dp_display_mode {
>>>>>>>> @@ -46,6 +48,7 @@ struct msm_dp_panel {
>>>>>>>>         bool video_test;
>>>>>>>>         bool vsc_sdp_supported;
>>>>>>>>
>>>>>>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES];
>>>>>>>>         u32 max_dp_lanes;
>>>>>>>>         u32 max_dp_link_rate;
>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> 2.25.1
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>> linux-phy mailing list
>>>>>> linux-phy@lists.infradead.org
>>>>>> https://lists.infradead.org/mailman/listinfo/linux-phy
>>>>>
>>>>
>>>
>>>
>>
> 


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2024-12-20  0:01                     ` Dmitry Baryshkov
@ 2025-03-05 10:20                       ` Xiangxu Yin
  2025-03-05 21:25                         ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2025-03-05 10:20 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 12/20/2024 8:01 AM, Dmitry Baryshkov wrote:
> On Wed, Dec 18, 2024 at 08:55:54PM +0800, Xiangxu Yin wrote:
>>
>>
>> On 12/12/2024 3:15 AM, Dmitry Baryshkov wrote:
>>> On Wed, Dec 11, 2024 at 08:50:02PM +0800, Xiangxu Yin wrote:
>>>>
>>>>
>>>> On 12/11/2024 5:46 PM, Dmitry Baryshkov wrote:
>>>>> On Wed, Dec 11, 2024 at 08:46:16AM +0800, Xiangxu Yin wrote:
>>>>>>
>>>>>>
>>>>>> On 12/10/2024 11:09 PM, Dmitry Baryshkov wrote:
>>>>>>> On Thu, Dec 05, 2024 at 08:31:24PM +0200, Dmitry Baryshkov wrote:
>>>>>>>> On Thu, Dec 05, 2024 at 09:26:47PM +0800, Xiangxu Yin wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
>>>>>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>>>>>>>
>>>>>>>>>>> Extended DP support for QCS615 USB or DP phy. Differentiated between
>>>>>>>>>>> USBC and DP PHY using the match table’s type, dynamically generating
>>>>>>>>>>> different types of cfg and layout attributes during initialization based
>>>>>>>>>>> on this type. Static variables are stored in cfg, while parsed values
>>>>>>>>>>> are organized into the layout structure.
>>>>>>>>>>
>>>>>>>>>> We didn't have an understanding / conclusion whether
>>>>>>>>>> qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
>>>>>>>>>> or two PHYs being placed next to each other. Could you please start
>>>>>>>>>> your commit message by explaining it? Or even better, make that a part
>>>>>>>>>> of the cover letter for a new series touching just the USBC PHY
>>>>>>>>>> driver. DP changes don't have anything in common with the PHY changes,
>>>>>>>>>> so you can split the series into two.
>>>>>>>>>>
>>>>>>>>> Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.
>>>>>>>>
>>>>>>>> What is "DP extension"?
>>>>>>>>
>>>>>> I'm sorry confusion casued by my description. It's means extend DP implemnt for USBC phy driver.
>>>>>>>>>
>>>>>>>>> We identified that DP and USB share some common controls for phy_mode and orientation.
>>>>>>>>> Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
>>>>>>>>> while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
>>>>>>>>> It would be more efficient for a single driver to manage these controls. 
>>>>>>>>
>>>>>>>> The question is about the hardware, not about the driver.
>>>>>>>>
>>>>>>>>> Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
>>>>>>>>> Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
>>>>>>>>> we still decided to base it on the USBC extension.
>>>>>>>>
>>>>>>>> Could you please clarify, do usb3-or-dp PHYs support DP-over-USB-C? I
>>>>>>>> thought that usbc-or-dp platforms support that, but they don't
>>>>>>>> support DP+USB pin configuration. Note, the question is broader than
>>>>>>>> just QCS615, it covers the PHY type itself.
>>>>>>>>
>>>>>>>> Also, is TCSR configuration read/write or read-only? Are we supposed to
>>>>>>>> set the register from OS or are we supposed to read it and thus detemine
>>>>>>>> the PHY mode?
>>>>>>>
>>>>>>> Any updates on these two topics?
>>>>>>>
>>>>>> Still confirming detail info with HW & design team.
>>>>>> I’ll update the information that has been confirmed so far.
>>>>>> This phy support DP-over-USB-C,but it's not support alt-mode which 2 lane work for DP, other 2 lane work for USB.
>>>>>> TCSR phy mode is read/write reg and we can read for determine phy mode.
>>>>>
>>>>> Ok, thanks for the explanation. From my point of view:
>>>>>
>>>>> - Implement the DP PHY to be a part of the same driver. Each device
>>>>>   supported by the usbc driver should get both PHYs.
>>>>>
>>>>> - Make sure not to break the ABI: #phy-cells = <0> should still work and
>>>>>   return USB PHY, keeping backwards compatibility. Newer devices or
>>>>>   upgraded DT for old devices should return USB PHY for <... 0> and DP
>>>>>   PHY for <... 1>.
>>>>>
>>>> Yes, currently we have implemented like your description,
>>>> Each deivce shoud get both PHYs, DP PHY for <... 1> and USB PHY for <... 0>.
>>>
>>> Please note the backwards compatibility clause.
>>>
>> For the USB node, we kept the same implementation as the original function interface, and the devicetree node definition also remains unchanged.
>> In subsequent patches, I will follow Krzysztof’s suggestion to use a separate DT-binding to describe the DP PHY configuration, 
>> without making changes to the USB devicetree and DT-binding implementation.
>>>>> - I'm not shure how to handle the USB and DP coexistence, especially in
>>>>>   your case of the USB-or-DP PHY.
>>>>>
>>>> For coexistence process:
>>>>
>>>> When we start implement DP part, usb driver team said only need config TCSR phy mode and orientation during switch in USB-C port.
>>>> Based on your previous comments avout SW_PWRDN, I'm confirming with the USB team whether SW_REST/SWPWRDN/START_CTRL registers might affect DP.
>>>
>>> Thanks!
>>>
>>>> Anyway, even though the original SoC design supports DP or USB over Type-C,
>>>> but on QCS615 ADP AIR platform, there are only four USB-A port which works with 'qcs615-qmp-usb3-phy' driver, and no USB-C port.
>>>> DP port is mappped from usb pin to the video out sub-board.
>>>> so we are unable to verify the switching case between DP and USB devices under USB-C.
>>>
>>> That's also fine. We will get to that point once MSM8998 / SDM660
>>> get USB-C support (the only current blocker is the support for the
>>> TYPEC block of the PMI8998).
>>>
>> I can't access MSM8998 / SDM660 documents now, but I have confirmed detail info about USB & DP phy design for sm6150.
>>
>> The 'usb-ssphy-qmp-usb3-or-dp PHY' on the current platform is essentially composed of three sub-PHYs, 
>> which can even be considered as three separate PHYs: USB3 primary PHY, USB3 secondary PHY, and USB3 DP PHY.
> 
> I've looked at sm6150-usb.dtsi and now I'm completely puzzled by your
> answer. The msm-4.14 kernel lists a single USB QMP PHY at 0x88e6000,
> used for the primary USB3 host. It it defined as
> qcom,usb-ssphy-qmp-usb3-or-dp. Secondary USB host is listed as USB 2.0
> only. So what do you mean by the USB3 secondary PHY? Which PHY and which
> pins are connected to your video-out board?
> 
Five PHYs are integrated into Talos SoC: two USB2 PHYs, two USB3 PHYs, and one DP PHY.
PERIPH_SS_QUSB2PHY_PRIM_QUSB2PHY_PRIM_CM_QUSB2_LQ_1EX (0x088E2000)
PERIPH_SS_QUSB2PHY_SEC_QUSB2PHY_SEC_CM_QUSB2_LQ_1EX (0x088E3000)
PERIPH_SS_USB0_USB3PHY_USB0_USB3PHY_CM_USB3_SW (0x088E6000)
PERIPH_SS_USB1_USB3PHY_USB1_USB3PHY_CM_USB3_SW (0x088E8000)
PERIPH_SS_DP_PHY_DP_PHY_CM_DP_4LN_SW (0x088E9000)

The USB3 secondary PHY(0x088E8000) is the one mutually exclusive with the DP PHY, which controlled by the TCSR switch.
USB3 secondary PHY is not configed in qcs615 dtsi.

In Ride, DP PHY, DP lane 0~3 and DP aux pins are connected to video-out board.
>>
>> On the QCS615, the USB primary PHY is currently used to handle USB 3.0 communication for the previously mentioned four USB Type-A ports, 
>> while the USB3 secondary PHY and USB3 DP PHY are used for the output of the Type-C port,
>> but since the Type-C port is forcibly pin-to-pin configured to the video out board, the Type-C port will always configure as DP PHY.
>>
>> The internal registers of these three PHYs are independent of each other, Neither their respective SWPWR_DN nor SWRST will affect the other two PHYs.
>> Additionally, there was a misunderstanding about the orientation previously.
>> The USB orientation setting only affects the current PHY and does not impact the DP PHY. The DP PHY is configured in the DP_PHY_CFG_1.
>>
>> TSCR_PHY_MODE can specify which PHY outputs to the Type-C port, and the global reset will simultaneously reset the two associated PHYs. 
>> Therefore, the correct switching process is as follows.
>> When switching the inserted device:
>> 	1.Identify the PHY type.
>> 	2.Enable the regulator.
>> 	3.Trigger a reset.
>> 	4.Enable the clock.
>> 	5.Configure PHY type related orientation
>> 	6.switch the TCSR PHY mode.
>> 	7.Configure the registers of PHY.
>> During release:
>> 	1.Reset.
>> 	2.Disable the clock.
>> 	3.Disable the regulator.
>>
>> Our current design overall complies with this process, but it lacks the configuration for DP_PHY_CFG_1.
>>
>> Shall we continue the discussion to clarify remain comments of the USBC driver?
>>
>>>> However, I'm also confirming whether anything other will affect USB and DP each other.
>>>
>>
> 


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration
  2025-03-05 10:16                 ` Xiangxu Yin
@ 2025-03-05 21:14                   ` Dmitry Baryshkov
  2025-05-19  8:20                     ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2025-03-05 21:14 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Wed, Mar 05, 2025 at 06:16:45PM +0800, Xiangxu Yin wrote:
> 
> 
> On 12/20/2024 5:45 AM, Dmitry Baryshkov wrote:
> > On Thu, Dec 19, 2024 at 06:36:38PM +0800, Xiangxu Yin wrote:
> >>
> >>
> >> On 12/5/2024 7:40 PM, Dmitry Baryshkov wrote:
> >>> On Thu, 5 Dec 2024 at 13:28, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>
> >>>>
> >>>>
> >>>> On 12/2/2024 6:46 PM, Dmitry Baryshkov wrote:
> >>>>> On Mon, Dec 02, 2024 at 04:40:05PM +0800, Xiangxu Yin wrote:
> >>>>>>
> >>>>>>
> >>>>>> On 11/29/2024 9:50 PM, Dmitry Baryshkov wrote:
> >>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>>>>>
> >>>>>>>> Add the ability to configure lane mapping for the DP controller. This is
> >>>>>>>> required when the platform's lane mapping does not follow the default
> >>>>>>>> order (0, 1, 2, 3). The mapping rules are now configurable via the
> >>>>>>>> `data-lane` property in the devicetree. This property defines the
> >>>>>>>> logical-to-physical lane mapping sequence, ensuring correct lane
> >>>>>>>> assignment for non-default configurations.
> >>>>>>>>
> >>>>>>>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> >>>>>>>> ---
> >>>>>>>>  drivers/gpu/drm/msm/dp/dp_catalog.c | 11 +++++------
> >>>>>>>>  drivers/gpu/drm/msm/dp/dp_catalog.h |  2 +-
> >>>>>>>>  drivers/gpu/drm/msm/dp/dp_ctrl.c    |  2 +-
> >>>>>>>>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 ++++++++++---
> >>>>>>>>  drivers/gpu/drm/msm/dp/dp_panel.h   |  3 +++
> >>>>>>>>  5 files changed, 20 insertions(+), 11 deletions(-)
> >>>>>>>>
> >>>>>
> >>>>>>>> @@ -461,6 +460,7 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
> >>>>>>>>         struct msm_dp_panel_private *panel;
> >>>>>>>>         struct device_node *of_node;
> >>>>>>>>         int cnt;
> >>>>>>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3};
> >>>>>>>>
> >>>>>>>>         panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
> >>>>>>>>         of_node = panel->dev->of_node;
> >>>>>>>> @@ -474,10 +474,17 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
> >>>>>>>>                 cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
> >>>>>>>>         }
> >>>>>>>>
> >>>>>>>> -       if (cnt > 0)
> >>>>>>>> +       if (cnt > 0) {
> >>>>>>>> +               struct device_node *endpoint;
> >>>>>>>> +
> >>>>>>>>                 msm_dp_panel->max_dp_lanes = cnt;
> >>>>>>>> -       else
> >>>>>>>> +               endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1);
> >>>>>>>> +               of_property_read_u32_array(endpoint, "data-lanes", lane_map, cnt);
> >>>>>>>> +       } else {
> >>>>>>>>                 msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
> >>>>>>>> +       }
> >>>>>>>
> >>>>>>> Why? This sounds more like dp_catalog or (after the refactoring at
> >>>>>>> [1]) dp_ctrl. But not the dp_panel.
> >>>>>>>
> >>>>>>> [1] https://patchwork.freedesktop.org/project/freedreno/series/?ordering=-last_updated
> >>>>>>>
> >>>>>> We are used the same prop 'data-lanes = <3 2 0 1>' in mdss_dp_out to keep similar behaviour with dsi_host_parse_lane_data.
> >>>>>> From the modules used, catalog seems more appropriate, but since the max_dp_lanes is parsed at dp_panel, it has been placed here.
> >>>>>> Should lane_map parsing in msm_dp_catalog_get, and keep max_dp_lanes parsing at the dp_panel?
> >>>>>
> >>>>> msm_dp_catalog_get() is going to be removed. Since the functions that
> >>>>> are going to use it are in dp_ctrl module, I thought that dp_ctrl.c is
> >>>>> the best place. A better option might be to move max_dp_lanes and
> >>>>> max_dp_link_rate to dp_link.c as those are link params. Then
> >>>>> lane_mapping also logically becomes a part of dp_link module.
> >>>>>
> >>>>> But now I have a more important question (triggered by Krishna's email
> >>>>> about SAR2130P's USB): if the lanes are swapped, does USB 3 work on that
> >>>>> platform? Or is it being demoted to USB 2 with nobody noticing that?
> >>>>>
> >>>>> If lanes 0/1 and 2/3 are swapped, shouldn't it be handled in the QMP
> >>>>> PHY, where we handle lanes and orientation switching?
> >>>>>
> >>>> I have checked the DP hardware programming guide and also discussed it with Krishna.
> >>>>
> >>>> According to the HPG section '3.4.2 PN and Lane Swap: PHY supports PN swap for mainlink and AUX, but it doesn't support lane swap feature.'
> >>>>
> >>>> The lane swap mainly refers to the logical to physical mapping between the DP controller and the DP PHY. The PHY handles polarity inversion, and the lane map does not affect USB behavior.
> >>>>
> >>>> On the QCS615 platform, we have also tested when DP works with lane swap, other USB 3.0 ports can works normally at super speed.
> >>>
> >>> "Other USB 3.0 ports"? What does that mean? Please correct me if I'm
> >>> wrong, you should have a USB+DP combo port that is being managed with
> >>> combo PHY. Does USB 3 work on that port?
> >>>
> >>> In other words, where the order of lanes is actually inverted? Between
> >>> DP and combo PHY? Within combo PHY? Between the PHY and the pinout?
> >>> Granted that SM6150 was supported in msm-4.14 could you possibly point
> >>> out a corresponding commit or a set of commits from that kernel?
> >>>
> >> For "Other USB 3.0 ports", as replied in USBC driver, USB3 primary phy works for other four USB type-A port.
> > 
> > So if that's the USB3 primary, then why do you mention here at all? We
> > are taling about the secondary USB3 + DP.
> > 
> OK, sorry for confusing you.
> >> The REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING mapping determines how logical lanes (0, 1, 2, 3) map to physical lanes sent to the PHY.
> >> This ensures alignment with hardware requirements.
> >> The PHY’s polarity inversion only adjusts signal polarity and doesn’t affect lane mapping.
> >> Both DP ctrl and PHY lane related config will not affect USB phy.
> > 
> > Probably we misundersand each other. The DP PHY should have orientation
> > switch register, which controls whether 2-lane DP uses lanes 0/1 or 2/3.
> > Can you use that register?
> > 
> Yes, DP PHY have orientation register as below.
> DP_PHY_DP_PHY_CFG_1(0x88e9014) bit(7) SW_PORTSELECT
> > Also, could you _please_ answer the question that I have asked? Is the
> > order of lanes inverted between the DP controller and DP PHY? Or between
> > DP PHY and the DP connector? If one uses USB3 signals coming from this
> > port (yes, on the other board, not on the Ride), would they also need to
> > switch the order of USB3 lanes? If one uses a DP-over-USB-C, are DP
> > lanes are swapped?
> > 
> It's inverted between the DP controller and DP PHY.
> If other use USB3 on the other board, will not need switch order of USB3 lanes,
> If one use DP-over-USB-C, then need DP lanes swap.

Thanks!

> >> Without extra Type-C mapping, the DP controller’s mapping indirectly decides how signals are transmitted through Type-C.
> >> Mapping ensures proper data transmission and compatibility across interfaces.
> >>
> >> We only found sm6150 need this lane mapping config, 
> >> For msm 4.14, please refer these links,
> >> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi (qcom,logical2physical-lane-map)
> >> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/drivers/gpu/drm/msm/dp/dp_parser.c (dp_parser_misc)
> >> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/drivers/gpu/drm/msm/dp/dp_catalog_v200.c (dp_catalog_ctrl_lane_mapping_v200)
> >>
> >> If need process orientation info like dp_catalog_ctrl_lane_mapping_v200, 
> >> then 
> >> if implement in DP phy, then we need config dp_link register in PHY,
> >> if implement in DP link, then we need pass orientation info to DP driver, perhaps we could add a new attribute to the phy_configure_opts_dp structure to pass this.
> >> Do you have any suggestions?
> > 
> > Does SW_PORTSEL_VAL affect the DP lanes on this platform?
> > 
> SW_PORTSEL_VAL for USB3PHY_PCS_MISC_TYPEC_CTRL will not affect DP lanes in this DP or USB3 chip series.
> USB3 will use USB3PHY_PCS_MISC_TYPEC_CTRL(SW_PORTSEL_VAL BIT_0) and DP will use DP_PHY_DP_PHY_CFG_1(SW_PORTSELECT BIT_7)

Is it possible to set this bit from the PHY driver rather than remapping
the lanes in the DP driver?

> >>
> >>>>
> >>>> Additionally, if it were placed on the PHY side, the PHY would need access to dp_link’s domain which can access REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING.
> >>>
> >>> I was thinking about inverting the SW_PORTSEL_VAL bit.
> >>>
> >>>> Therefore, we believe that the  max_dp_link_rate,max_dp_lanes and lane_map move to dp_link side is better.
> >>>>
> >>>>>>>> +
> >>>>>>>> +       memcpy(msm_dp_panel->lane_map, lane_map, msm_dp_panel->max_dp_lanes * sizeof(u32));
> >>>>>>>>
> >>>>>>>>         msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node);
> >>>>>>>>         if (!msm_dp_panel->max_dp_link_rate)
> >>>>>>>> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
> >>>>>>>> index 0e944db3adf2f187f313664fe80cf540ec7a19f2..7603b92c32902bd3d4485539bd6308537ff75a2c 100644
> >>>>>>>> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
> >>>>>>>> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
> >>>>>>>> @@ -11,6 +11,8 @@
> >>>>>>>>  #include "dp_aux.h"
> >>>>>>>>  #include "dp_link.h"
> >>>>>>>>
> >>>>>>>> +#define DP_MAX_NUM_DP_LANES    4
> >>>>>>>> +
> >>>>>>>>  struct edid;
> >>>>>>>>
> >>>>>>>>  struct msm_dp_display_mode {
> >>>>>>>> @@ -46,6 +48,7 @@ struct msm_dp_panel {
> >>>>>>>>         bool video_test;
> >>>>>>>>         bool vsc_sdp_supported;
> >>>>>>>>
> >>>>>>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES];
> >>>>>>>>         u32 max_dp_lanes;
> >>>>>>>>         u32 max_dp_link_rate;
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> --
> >>>>>>>> 2.25.1
> >>>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>
> >>>>>>
> >>>>>> --
> >>>>>> linux-phy mailing list
> >>>>>> linux-phy@lists.infradead.org
> >>>>>> https://lists.infradead.org/mailman/listinfo/linux-phy
> >>>>>
> >>>>
> >>>
> >>>
> >>
> > 
> 

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2025-03-05 10:20                       ` Xiangxu Yin
@ 2025-03-05 21:25                         ` Dmitry Baryshkov
  2025-03-21 10:17                           ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2025-03-05 21:25 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On Wed, Mar 05, 2025 at 06:20:45PM +0800, Xiangxu Yin wrote:
> 
> 
> On 12/20/2024 8:01 AM, Dmitry Baryshkov wrote:
> > On Wed, Dec 18, 2024 at 08:55:54PM +0800, Xiangxu Yin wrote:
> >>
> >>
> >> On 12/12/2024 3:15 AM, Dmitry Baryshkov wrote:
> >>> On Wed, Dec 11, 2024 at 08:50:02PM +0800, Xiangxu Yin wrote:
> >>>>
> >>>>
> >>>> On 12/11/2024 5:46 PM, Dmitry Baryshkov wrote:
> >>>>> On Wed, Dec 11, 2024 at 08:46:16AM +0800, Xiangxu Yin wrote:
> >>>>>>
> >>>>>>
> >>>>>> On 12/10/2024 11:09 PM, Dmitry Baryshkov wrote:
> >>>>>>> On Thu, Dec 05, 2024 at 08:31:24PM +0200, Dmitry Baryshkov wrote:
> >>>>>>>> On Thu, Dec 05, 2024 at 09:26:47PM +0800, Xiangxu Yin wrote:
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>> On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
> >>>>>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>>>>>>>>
> >>>>>>>>>>> Extended DP support for QCS615 USB or DP phy. Differentiated between
> >>>>>>>>>>> USBC and DP PHY using the match table’s type, dynamically generating
> >>>>>>>>>>> different types of cfg and layout attributes during initialization based
> >>>>>>>>>>> on this type. Static variables are stored in cfg, while parsed values
> >>>>>>>>>>> are organized into the layout structure.
> >>>>>>>>>>
> >>>>>>>>>> We didn't have an understanding / conclusion whether
> >>>>>>>>>> qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
> >>>>>>>>>> or two PHYs being placed next to each other. Could you please start
> >>>>>>>>>> your commit message by explaining it? Or even better, make that a part
> >>>>>>>>>> of the cover letter for a new series touching just the USBC PHY
> >>>>>>>>>> driver. DP changes don't have anything in common with the PHY changes,
> >>>>>>>>>> so you can split the series into two.
> >>>>>>>>>>
> >>>>>>>>> Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.
> >>>>>>>>
> >>>>>>>> What is "DP extension"?
> >>>>>>>>
> >>>>>> I'm sorry confusion casued by my description. It's means extend DP implemnt for USBC phy driver.
> >>>>>>>>>
> >>>>>>>>> We identified that DP and USB share some common controls for phy_mode and orientation.
> >>>>>>>>> Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
> >>>>>>>>> while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
> >>>>>>>>> It would be more efficient for a single driver to manage these controls. 
> >>>>>>>>
> >>>>>>>> The question is about the hardware, not about the driver.
> >>>>>>>>
> >>>>>>>>> Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
> >>>>>>>>> Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
> >>>>>>>>> we still decided to base it on the USBC extension.
> >>>>>>>>
> >>>>>>>> Could you please clarify, do usb3-or-dp PHYs support DP-over-USB-C? I
> >>>>>>>> thought that usbc-or-dp platforms support that, but they don't
> >>>>>>>> support DP+USB pin configuration. Note, the question is broader than
> >>>>>>>> just QCS615, it covers the PHY type itself.
> >>>>>>>>
> >>>>>>>> Also, is TCSR configuration read/write or read-only? Are we supposed to
> >>>>>>>> set the register from OS or are we supposed to read it and thus detemine
> >>>>>>>> the PHY mode?
> >>>>>>>
> >>>>>>> Any updates on these two topics?
> >>>>>>>
> >>>>>> Still confirming detail info with HW & design team.
> >>>>>> I’ll update the information that has been confirmed so far.
> >>>>>> This phy support DP-over-USB-C,but it's not support alt-mode which 2 lane work for DP, other 2 lane work for USB.
> >>>>>> TCSR phy mode is read/write reg and we can read for determine phy mode.
> >>>>>
> >>>>> Ok, thanks for the explanation. From my point of view:
> >>>>>
> >>>>> - Implement the DP PHY to be a part of the same driver. Each device
> >>>>>   supported by the usbc driver should get both PHYs.
> >>>>>
> >>>>> - Make sure not to break the ABI: #phy-cells = <0> should still work and
> >>>>>   return USB PHY, keeping backwards compatibility. Newer devices or
> >>>>>   upgraded DT for old devices should return USB PHY for <... 0> and DP
> >>>>>   PHY for <... 1>.
> >>>>>
> >>>> Yes, currently we have implemented like your description,
> >>>> Each deivce shoud get both PHYs, DP PHY for <... 1> and USB PHY for <... 0>.
> >>>
> >>> Please note the backwards compatibility clause.
> >>>
> >> For the USB node, we kept the same implementation as the original function interface, and the devicetree node definition also remains unchanged.
> >> In subsequent patches, I will follow Krzysztof’s suggestion to use a separate DT-binding to describe the DP PHY configuration, 
> >> without making changes to the USB devicetree and DT-binding implementation.
> >>>>> - I'm not shure how to handle the USB and DP coexistence, especially in
> >>>>>   your case of the USB-or-DP PHY.
> >>>>>
> >>>> For coexistence process:
> >>>>
> >>>> When we start implement DP part, usb driver team said only need config TCSR phy mode and orientation during switch in USB-C port.
> >>>> Based on your previous comments avout SW_PWRDN, I'm confirming with the USB team whether SW_REST/SWPWRDN/START_CTRL registers might affect DP.
> >>>
> >>> Thanks!
> >>>
> >>>> Anyway, even though the original SoC design supports DP or USB over Type-C,
> >>>> but on QCS615 ADP AIR platform, there are only four USB-A port which works with 'qcs615-qmp-usb3-phy' driver, and no USB-C port.
> >>>> DP port is mappped from usb pin to the video out sub-board.
> >>>> so we are unable to verify the switching case between DP and USB devices under USB-C.
> >>>
> >>> That's also fine. We will get to that point once MSM8998 / SDM660
> >>> get USB-C support (the only current blocker is the support for the
> >>> TYPEC block of the PMI8998).
> >>>
> >> I can't access MSM8998 / SDM660 documents now, but I have confirmed detail info about USB & DP phy design for sm6150.
> >>
> >> The 'usb-ssphy-qmp-usb3-or-dp PHY' on the current platform is essentially composed of three sub-PHYs, 
> >> which can even be considered as three separate PHYs: USB3 primary PHY, USB3 secondary PHY, and USB3 DP PHY.
> > 
> > I've looked at sm6150-usb.dtsi and now I'm completely puzzled by your
> > answer. The msm-4.14 kernel lists a single USB QMP PHY at 0x88e6000,
> > used for the primary USB3 host. It it defined as
> > qcom,usb-ssphy-qmp-usb3-or-dp. Secondary USB host is listed as USB 2.0
> > only. So what do you mean by the USB3 secondary PHY? Which PHY and which
> > pins are connected to your video-out board?
> > 
> Five PHYs are integrated into Talos SoC: two USB2 PHYs, two USB3 PHYs, and one DP PHY.
> PERIPH_SS_QUSB2PHY_PRIM_QUSB2PHY_PRIM_CM_QUSB2_LQ_1EX (0x088E2000)
> PERIPH_SS_QUSB2PHY_SEC_QUSB2PHY_SEC_CM_QUSB2_LQ_1EX (0x088E3000)
> PERIPH_SS_USB0_USB3PHY_USB0_USB3PHY_CM_USB3_SW (0x088E6000)
> PERIPH_SS_USB1_USB3PHY_USB1_USB3PHY_CM_USB3_SW (0x088E8000)
> PERIPH_SS_DP_PHY_DP_PHY_CM_DP_4LN_SW (0x088E9000)
> 
> The USB3 secondary PHY(0x088E8000) is the one mutually exclusive with the DP PHY, which controlled by the TCSR switch.
> USB3 secondary PHY is not configed in qcs615 dtsi.

Okay, thanks for the explanation. I'm still puzzled by msm-4.14 defining
primary USB3 PHY as 'qcom,usb-ssphy-qmp-usb3-or-dp', but it might be
some kind of a hack or just a difference between QCS615 and SM6150.

If QCS615 follows other platforms of the same generation, I'd assume
that the correct way to handle it would be:

- Keep the primary USB3 PHY as is (it needs to be reposted though, the
  driver part didn't make it in).

- Extend the qmp-usbc driver to support USB+DP 'exclusive combo' PHYs by
  registering two PHYs for a single device. Make sure to continue
  supporting #phy-cells = 0 and region size = 0x1000. Use definitions
  from include/dt-bindings/phy/phy-qcom-qmp.h .

- Make sure that the PHY driver doesn't allow both PHYs to be powered
  on. Add TCSR programming to the power_on / power_off callbacks,
  implementing the switch between DP and USB3.

At this point all PHYs in qmp-usbc can be switched to the new USB+DP
configuration, still providing backwards compatibility with the existing
board DTs.

> In Ride, DP PHY, DP lane 0~3 and DP aux pins are connected to video-out board.
> >>
> >> On the QCS615, the USB primary PHY is currently used to handle USB 3.0 communication for the previously mentioned four USB Type-A ports, 
> >> while the USB3 secondary PHY and USB3 DP PHY are used for the output of the Type-C port,
> >> but since the Type-C port is forcibly pin-to-pin configured to the video out board, the Type-C port will always configure as DP PHY.
> >>
> >> The internal registers of these three PHYs are independent of each other, Neither their respective SWPWR_DN nor SWRST will affect the other two PHYs.
> >> Additionally, there was a misunderstanding about the orientation previously.
> >> The USB orientation setting only affects the current PHY and does not impact the DP PHY. The DP PHY is configured in the DP_PHY_CFG_1.
> >>
> >> TSCR_PHY_MODE can specify which PHY outputs to the Type-C port, and the global reset will simultaneously reset the two associated PHYs. 
> >> Therefore, the correct switching process is as follows.
> >> When switching the inserted device:
> >> 	1.Identify the PHY type.
> >> 	2.Enable the regulator.
> >> 	3.Trigger a reset.
> >> 	4.Enable the clock.
> >> 	5.Configure PHY type related orientation
> >> 	6.switch the TCSR PHY mode.
> >> 	7.Configure the registers of PHY.
> >> During release:
> >> 	1.Reset.
> >> 	2.Disable the clock.
> >> 	3.Disable the regulator.
> >>
> >> Our current design overall complies with this process, but it lacks the configuration for DP_PHY_CFG_1.
> >>
> >> Shall we continue the discussion to clarify remain comments of the USBC driver?
> >>
> >>>> However, I'm also confirming whether anything other will affect USB and DP each other.
> >>>
> >>
> > 
> 

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2025-03-05 21:25                         ` Dmitry Baryshkov
@ 2025-03-21 10:17                           ` Xiangxu Yin
  2025-03-21 12:19                             ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2025-03-21 10:17 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio



On 3/6/2025 5:25 AM, Dmitry Baryshkov wrote:
> On Wed, Mar 05, 2025 at 06:20:45PM +0800, Xiangxu Yin wrote:
>>
>>
>> On 12/20/2024 8:01 AM, Dmitry Baryshkov wrote:
>>> On Wed, Dec 18, 2024 at 08:55:54PM +0800, Xiangxu Yin wrote:
>>>>
>>>>
>>>> On 12/12/2024 3:15 AM, Dmitry Baryshkov wrote:
>>>>> On Wed, Dec 11, 2024 at 08:50:02PM +0800, Xiangxu Yin wrote:
>>>>>>
>>>>>>
>>>>>> On 12/11/2024 5:46 PM, Dmitry Baryshkov wrote:
>>>>>>> On Wed, Dec 11, 2024 at 08:46:16AM +0800, Xiangxu Yin wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On 12/10/2024 11:09 PM, Dmitry Baryshkov wrote:
>>>>>>>>> On Thu, Dec 05, 2024 at 08:31:24PM +0200, Dmitry Baryshkov wrote:
>>>>>>>>>> On Thu, Dec 05, 2024 at 09:26:47PM +0800, Xiangxu Yin wrote:
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
>>>>>>>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> Extended DP support for QCS615 USB or DP phy. Differentiated between
>>>>>>>>>>>>> USBC and DP PHY using the match table’s type, dynamically generating
>>>>>>>>>>>>> different types of cfg and layout attributes during initialization based
>>>>>>>>>>>>> on this type. Static variables are stored in cfg, while parsed values
>>>>>>>>>>>>> are organized into the layout structure.
>>>>>>>>>>>>
>>>>>>>>>>>> We didn't have an understanding / conclusion whether
>>>>>>>>>>>> qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
>>>>>>>>>>>> or two PHYs being placed next to each other. Could you please start
>>>>>>>>>>>> your commit message by explaining it? Or even better, make that a part
>>>>>>>>>>>> of the cover letter for a new series touching just the USBC PHY
>>>>>>>>>>>> driver. DP changes don't have anything in common with the PHY changes,
>>>>>>>>>>>> so you can split the series into two.
>>>>>>>>>>>>
>>>>>>>>>>> Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.
>>>>>>>>>>
>>>>>>>>>> What is "DP extension"?
>>>>>>>>>>
>>>>>>>> I'm sorry confusion casued by my description. It's means extend DP implemnt for USBC phy driver.
>>>>>>>>>>>
>>>>>>>>>>> We identified that DP and USB share some common controls for phy_mode and orientation.
>>>>>>>>>>> Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
>>>>>>>>>>> while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
>>>>>>>>>>> It would be more efficient for a single driver to manage these controls. 
>>>>>>>>>>
>>>>>>>>>> The question is about the hardware, not about the driver.
>>>>>>>>>>
>>>>>>>>>>> Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
>>>>>>>>>>> Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
>>>>>>>>>>> we still decided to base it on the USBC extension.
>>>>>>>>>>
>>>>>>>>>> Could you please clarify, do usb3-or-dp PHYs support DP-over-USB-C? I
>>>>>>>>>> thought that usbc-or-dp platforms support that, but they don't
>>>>>>>>>> support DP+USB pin configuration. Note, the question is broader than
>>>>>>>>>> just QCS615, it covers the PHY type itself.
>>>>>>>>>>
>>>>>>>>>> Also, is TCSR configuration read/write or read-only? Are we supposed to
>>>>>>>>>> set the register from OS or are we supposed to read it and thus detemine
>>>>>>>>>> the PHY mode?
>>>>>>>>>
>>>>>>>>> Any updates on these two topics?
>>>>>>>>>
>>>>>>>> Still confirming detail info with HW & design team.
>>>>>>>> I’ll update the information that has been confirmed so far.
>>>>>>>> This phy support DP-over-USB-C,but it's not support alt-mode which 2 lane work for DP, other 2 lane work for USB.
>>>>>>>> TCSR phy mode is read/write reg and we can read for determine phy mode.
>>>>>>>
>>>>>>> Ok, thanks for the explanation. From my point of view:
>>>>>>>
>>>>>>> - Implement the DP PHY to be a part of the same driver. Each device
>>>>>>>   supported by the usbc driver should get both PHYs.
>>>>>>>
>>>>>>> - Make sure not to break the ABI: #phy-cells = <0> should still work and
>>>>>>>   return USB PHY, keeping backwards compatibility. Newer devices or
>>>>>>>   upgraded DT for old devices should return USB PHY for <... 0> and DP
>>>>>>>   PHY for <... 1>.
>>>>>>>
>>>>>> Yes, currently we have implemented like your description,
>>>>>> Each deivce shoud get both PHYs, DP PHY for <... 1> and USB PHY for <... 0>.
>>>>>
>>>>> Please note the backwards compatibility clause.
>>>>>
>>>> For the USB node, we kept the same implementation as the original function interface, and the devicetree node definition also remains unchanged.
>>>> In subsequent patches, I will follow Krzysztof’s suggestion to use a separate DT-binding to describe the DP PHY configuration, 
>>>> without making changes to the USB devicetree and DT-binding implementation.
>>>>>>> - I'm not shure how to handle the USB and DP coexistence, especially in
>>>>>>>   your case of the USB-or-DP PHY.
>>>>>>>
>>>>>> For coexistence process:
>>>>>>
>>>>>> When we start implement DP part, usb driver team said only need config TCSR phy mode and orientation during switch in USB-C port.
>>>>>> Based on your previous comments avout SW_PWRDN, I'm confirming with the USB team whether SW_REST/SWPWRDN/START_CTRL registers might affect DP.
>>>>>
>>>>> Thanks!
>>>>>
>>>>>> Anyway, even though the original SoC design supports DP or USB over Type-C,
>>>>>> but on QCS615 ADP AIR platform, there are only four USB-A port which works with 'qcs615-qmp-usb3-phy' driver, and no USB-C port.
>>>>>> DP port is mappped from usb pin to the video out sub-board.
>>>>>> so we are unable to verify the switching case between DP and USB devices under USB-C.
>>>>>
>>>>> That's also fine. We will get to that point once MSM8998 / SDM660
>>>>> get USB-C support (the only current blocker is the support for the
>>>>> TYPEC block of the PMI8998).
>>>>>
>>>> I can't access MSM8998 / SDM660 documents now, but I have confirmed detail info about USB & DP phy design for sm6150.
>>>>
>>>> The 'usb-ssphy-qmp-usb3-or-dp PHY' on the current platform is essentially composed of three sub-PHYs, 
>>>> which can even be considered as three separate PHYs: USB3 primary PHY, USB3 secondary PHY, and USB3 DP PHY.
>>>
>>> I've looked at sm6150-usb.dtsi and now I'm completely puzzled by your
>>> answer. The msm-4.14 kernel lists a single USB QMP PHY at 0x88e6000,
>>> used for the primary USB3 host. It it defined as
>>> qcom,usb-ssphy-qmp-usb3-or-dp. Secondary USB host is listed as USB 2.0
>>> only. So what do you mean by the USB3 secondary PHY? Which PHY and which
>>> pins are connected to your video-out board?
>>>
>> Five PHYs are integrated into Talos SoC: two USB2 PHYs, two USB3 PHYs, and one DP PHY.
>> PERIPH_SS_QUSB2PHY_PRIM_QUSB2PHY_PRIM_CM_QUSB2_LQ_1EX (0x088E2000)
>> PERIPH_SS_QUSB2PHY_SEC_QUSB2PHY_SEC_CM_QUSB2_LQ_1EX (0x088E3000)
>> PERIPH_SS_USB0_USB3PHY_USB0_USB3PHY_CM_USB3_SW (0x088E6000)
>> PERIPH_SS_USB1_USB3PHY_USB1_USB3PHY_CM_USB3_SW (0x088E8000)
>> PERIPH_SS_DP_PHY_DP_PHY_CM_DP_4LN_SW (0x088E9000)
>>
>> The USB3 secondary PHY(0x088E8000) is the one mutually exclusive with the DP PHY, which controlled by the TCSR switch.
>> USB3 secondary PHY is not configed in qcs615 dtsi.
> 
> Okay, thanks for the explanation. I'm still puzzled by msm-4.14 defining
> primary USB3 PHY as 'qcom,usb-ssphy-qmp-usb3-or-dp', but it might be
> some kind of a hack or just a difference between QCS615 and SM6150.
> 
> If QCS615 follows other platforms of the same generation, I'd assume
> that the correct way to handle it would be:
> 
> - Keep the primary USB3 PHY as is (it needs to be reposted though, the
>   driver part didn't make it in).
> 
> - Extend the qmp-usbc driver to support USB+DP 'exclusive combo' PHYs by
>   registering two PHYs for a single device. Make sure to continue
>   supporting #phy-cells = 0 and region size = 0x1000. Use definitions
>   from include/dt-bindings/phy/phy-qcom-qmp.h .
> 
To avoid any misunderstandings, let me double-confirm these points.

1.In this patch [PATCH 3/8], 
we didn't modify the USB driver logic; we only adjusted the structure and organizational relationships. 
Does the first point suggest splitting this patch and isolating the USB structure changes into a separate patch?
Or did I misunderstand?

2. Does "two PHYs for a single device" means should define both usb PHY and DP PHY in dtsi, the USBC PHY driver's probe will run separately for both USB and DP?
Then USB PHY node can keep forward compatibility with prop '#clock-cells = <0>' & '#phy-cells = <0>',
and DP PHY will define with prop '#clock-cells = <1>' & '#phy-cells = <1>'.

> - Make sure that the PHY driver doesn't allow both PHYs to be powered
>   on. Add TCSR programming to the power_on / power_off callbacks,
>   implementing the switch between DP and USB3.
> 
Ok, I will add TCSR switch logic to DP power_on / power_off callbacks, 
During DP power off, default will reset to USB3 PHY.

> At this point all PHYs in qmp-usbc can be switched to the new USB+DP
> configuration, still providing backwards compatibility with the existing
> board DTs.
> 
>> In Ride, DP PHY, DP lane 0~3 and DP aux pins are connected to video-out board.
>>>>
>>>> On the QCS615, the USB primary PHY is currently used to handle USB 3.0 communication for the previously mentioned four USB Type-A ports, 
>>>> while the USB3 secondary PHY and USB3 DP PHY are used for the output of the Type-C port,
>>>> but since the Type-C port is forcibly pin-to-pin configured to the video out board, the Type-C port will always configure as DP PHY.
>>>>
>>>> The internal registers of these three PHYs are independent of each other, Neither their respective SWPWR_DN nor SWRST will affect the other two PHYs.
>>>> Additionally, there was a misunderstanding about the orientation previously.
>>>> The USB orientation setting only affects the current PHY and does not impact the DP PHY. The DP PHY is configured in the DP_PHY_CFG_1.
>>>>
>>>> TSCR_PHY_MODE can specify which PHY outputs to the Type-C port, and the global reset will simultaneously reset the two associated PHYs. 
>>>> Therefore, the correct switching process is as follows.
>>>> When switching the inserted device:
>>>> 	1.Identify the PHY type.
>>>> 	2.Enable the regulator.
>>>> 	3.Trigger a reset.
>>>> 	4.Enable the clock.
>>>> 	5.Configure PHY type related orientation
>>>> 	6.switch the TCSR PHY mode.
>>>> 	7.Configure the registers of PHY.
>>>> During release:
>>>> 	1.Reset.
>>>> 	2.Disable the clock.
>>>> 	3.Disable the regulator.
>>>>
>>>> Our current design overall complies with this process, but it lacks the configuration for DP_PHY_CFG_1.
>>>>
>>>> Shall we continue the discussion to clarify remain comments of the USBC driver?
>>>>
>>>>>> However, I'm also confirming whether anything other will affect USB and DP each other.
>>>>>
>>>>
>>>
>>
> 


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615
  2025-03-21 10:17                           ` Xiangxu Yin
@ 2025-03-21 12:19                             ` Dmitry Baryshkov
  0 siblings, 0 replies; 60+ messages in thread
From: Dmitry Baryshkov @ 2025-03-21 12:19 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Dmitry Baryshkov, Rob Clark, Abhinav Kumar, Sean Paul,
	Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, linux-phy, linux-gpio

On Fri, Mar 21, 2025 at 06:17:39PM +0800, Xiangxu Yin wrote:
> 
> 
> On 3/6/2025 5:25 AM, Dmitry Baryshkov wrote:
> > On Wed, Mar 05, 2025 at 06:20:45PM +0800, Xiangxu Yin wrote:
> >>
> >>
> >> On 12/20/2024 8:01 AM, Dmitry Baryshkov wrote:
> >>> On Wed, Dec 18, 2024 at 08:55:54PM +0800, Xiangxu Yin wrote:
> >>>>
> >>>>
> >>>> On 12/12/2024 3:15 AM, Dmitry Baryshkov wrote:
> >>>>> On Wed, Dec 11, 2024 at 08:50:02PM +0800, Xiangxu Yin wrote:
> >>>>>>
> >>>>>>
> >>>>>> On 12/11/2024 5:46 PM, Dmitry Baryshkov wrote:
> >>>>>>> On Wed, Dec 11, 2024 at 08:46:16AM +0800, Xiangxu Yin wrote:
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> On 12/10/2024 11:09 PM, Dmitry Baryshkov wrote:
> >>>>>>>>> On Thu, Dec 05, 2024 at 08:31:24PM +0200, Dmitry Baryshkov wrote:
> >>>>>>>>>> On Thu, Dec 05, 2024 at 09:26:47PM +0800, Xiangxu Yin wrote:
> >>>>>>>>>>>
> >>>>>>>>>>>
> >>>>>>>>>>> On 11/29/2024 10:33 PM, Dmitry Baryshkov wrote:
> >>>>>>>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> Extended DP support for QCS615 USB or DP phy. Differentiated between
> >>>>>>>>>>>>> USBC and DP PHY using the match table’s type, dynamically generating
> >>>>>>>>>>>>> different types of cfg and layout attributes during initialization based
> >>>>>>>>>>>>> on this type. Static variables are stored in cfg, while parsed values
> >>>>>>>>>>>>> are organized into the layout structure.
> >>>>>>>>>>>>
> >>>>>>>>>>>> We didn't have an understanding / conclusion whether
> >>>>>>>>>>>> qcom,usb-ssphy-qmp-usb3-or-dp PHYs are actually a single device / PHY
> >>>>>>>>>>>> or two PHYs being placed next to each other. Could you please start
> >>>>>>>>>>>> your commit message by explaining it? Or even better, make that a part
> >>>>>>>>>>>> of the cover letter for a new series touching just the USBC PHY
> >>>>>>>>>>>> driver. DP changes don't have anything in common with the PHY changes,
> >>>>>>>>>>>> so you can split the series into two.
> >>>>>>>>>>>>
> >>>>>>>>>>> Before implement DP extension, we have discussed with abhinav and krishna about whether use combo, usbc or separate phy.
> >>>>>>>>>>
> >>>>>>>>>> What is "DP extension"?
> >>>>>>>>>>
> >>>>>>>> I'm sorry confusion casued by my description. It's means extend DP implemnt for USBC phy driver.
> >>>>>>>>>>>
> >>>>>>>>>>> We identified that DP and USB share some common controls for phy_mode and orientation.
> >>>>>>>>>>> Specifically, 'TCSR_USB3_0_DP_PHYMODE' controls who must use the lanes - USB or DP,
> >>>>>>>>>>> while PERIPH_SS_USB0_USB3PHY_PCS_MISC_TYPEC_CTRL controls the orientation.
> >>>>>>>>>>> It would be more efficient for a single driver to manage these controls. 
> >>>>>>>>>>
> >>>>>>>>>> The question is about the hardware, not about the driver.
> >>>>>>>>>>
> >>>>>>>>>>> Additionally, this PHY does not support Alt Mode, and the two control registers are located in separate address spaces. 
> >>>>>>>>>>> Therefore, even though the orientation for DP on this platform is always normal and connected to the video output board, 
> >>>>>>>>>>> we still decided to base it on the USBC extension.
> >>>>>>>>>>
> >>>>>>>>>> Could you please clarify, do usb3-or-dp PHYs support DP-over-USB-C? I
> >>>>>>>>>> thought that usbc-or-dp platforms support that, but they don't
> >>>>>>>>>> support DP+USB pin configuration. Note, the question is broader than
> >>>>>>>>>> just QCS615, it covers the PHY type itself.
> >>>>>>>>>>
> >>>>>>>>>> Also, is TCSR configuration read/write or read-only? Are we supposed to
> >>>>>>>>>> set the register from OS or are we supposed to read it and thus detemine
> >>>>>>>>>> the PHY mode?
> >>>>>>>>>
> >>>>>>>>> Any updates on these two topics?
> >>>>>>>>>
> >>>>>>>> Still confirming detail info with HW & design team.
> >>>>>>>> I’ll update the information that has been confirmed so far.
> >>>>>>>> This phy support DP-over-USB-C,but it's not support alt-mode which 2 lane work for DP, other 2 lane work for USB.
> >>>>>>>> TCSR phy mode is read/write reg and we can read for determine phy mode.
> >>>>>>>
> >>>>>>> Ok, thanks for the explanation. From my point of view:
> >>>>>>>
> >>>>>>> - Implement the DP PHY to be a part of the same driver. Each device
> >>>>>>>   supported by the usbc driver should get both PHYs.
> >>>>>>>
> >>>>>>> - Make sure not to break the ABI: #phy-cells = <0> should still work and
> >>>>>>>   return USB PHY, keeping backwards compatibility. Newer devices or
> >>>>>>>   upgraded DT for old devices should return USB PHY for <... 0> and DP
> >>>>>>>   PHY for <... 1>.
> >>>>>>>
> >>>>>> Yes, currently we have implemented like your description,
> >>>>>> Each deivce shoud get both PHYs, DP PHY for <... 1> and USB PHY for <... 0>.
> >>>>>
> >>>>> Please note the backwards compatibility clause.
> >>>>>
> >>>> For the USB node, we kept the same implementation as the original function interface, and the devicetree node definition also remains unchanged.
> >>>> In subsequent patches, I will follow Krzysztof’s suggestion to use a separate DT-binding to describe the DP PHY configuration, 
> >>>> without making changes to the USB devicetree and DT-binding implementation.
> >>>>>>> - I'm not shure how to handle the USB and DP coexistence, especially in
> >>>>>>>   your case of the USB-or-DP PHY.
> >>>>>>>
> >>>>>> For coexistence process:
> >>>>>>
> >>>>>> When we start implement DP part, usb driver team said only need config TCSR phy mode and orientation during switch in USB-C port.
> >>>>>> Based on your previous comments avout SW_PWRDN, I'm confirming with the USB team whether SW_REST/SWPWRDN/START_CTRL registers might affect DP.
> >>>>>
> >>>>> Thanks!
> >>>>>
> >>>>>> Anyway, even though the original SoC design supports DP or USB over Type-C,
> >>>>>> but on QCS615 ADP AIR platform, there are only four USB-A port which works with 'qcs615-qmp-usb3-phy' driver, and no USB-C port.
> >>>>>> DP port is mappped from usb pin to the video out sub-board.
> >>>>>> so we are unable to verify the switching case between DP and USB devices under USB-C.
> >>>>>
> >>>>> That's also fine. We will get to that point once MSM8998 / SDM660
> >>>>> get USB-C support (the only current blocker is the support for the
> >>>>> TYPEC block of the PMI8998).
> >>>>>
> >>>> I can't access MSM8998 / SDM660 documents now, but I have confirmed detail info about USB & DP phy design for sm6150.
> >>>>
> >>>> The 'usb-ssphy-qmp-usb3-or-dp PHY' on the current platform is essentially composed of three sub-PHYs, 
> >>>> which can even be considered as three separate PHYs: USB3 primary PHY, USB3 secondary PHY, and USB3 DP PHY.
> >>>
> >>> I've looked at sm6150-usb.dtsi and now I'm completely puzzled by your
> >>> answer. The msm-4.14 kernel lists a single USB QMP PHY at 0x88e6000,
> >>> used for the primary USB3 host. It it defined as
> >>> qcom,usb-ssphy-qmp-usb3-or-dp. Secondary USB host is listed as USB 2.0
> >>> only. So what do you mean by the USB3 secondary PHY? Which PHY and which
> >>> pins are connected to your video-out board?
> >>>
> >> Five PHYs are integrated into Talos SoC: two USB2 PHYs, two USB3 PHYs, and one DP PHY.
> >> PERIPH_SS_QUSB2PHY_PRIM_QUSB2PHY_PRIM_CM_QUSB2_LQ_1EX (0x088E2000)
> >> PERIPH_SS_QUSB2PHY_SEC_QUSB2PHY_SEC_CM_QUSB2_LQ_1EX (0x088E3000)
> >> PERIPH_SS_USB0_USB3PHY_USB0_USB3PHY_CM_USB3_SW (0x088E6000)
> >> PERIPH_SS_USB1_USB3PHY_USB1_USB3PHY_CM_USB3_SW (0x088E8000)
> >> PERIPH_SS_DP_PHY_DP_PHY_CM_DP_4LN_SW (0x088E9000)
> >>
> >> The USB3 secondary PHY(0x088E8000) is the one mutually exclusive with the DP PHY, which controlled by the TCSR switch.
> >> USB3 secondary PHY is not configed in qcs615 dtsi.
> > 
> > Okay, thanks for the explanation. I'm still puzzled by msm-4.14 defining
> > primary USB3 PHY as 'qcom,usb-ssphy-qmp-usb3-or-dp', but it might be
> > some kind of a hack or just a difference between QCS615 and SM6150.
> > 
> > If QCS615 follows other platforms of the same generation, I'd assume
> > that the correct way to handle it would be:
> > 
> > - Keep the primary USB3 PHY as is (it needs to be reposted though, the
> >   driver part didn't make it in).
> > 
> > - Extend the qmp-usbc driver to support USB+DP 'exclusive combo' PHYs by
> >   registering two PHYs for a single device. Make sure to continue
> >   supporting #phy-cells = 0 and region size = 0x1000. Use definitions
> >   from include/dt-bindings/phy/phy-qcom-qmp.h .
> > 
> To avoid any misunderstandings, let me double-confirm these points.
> 
> 1.In this patch [PATCH 3/8], 
> we didn't modify the USB driver logic; we only adjusted the structure and organizational relationships. 
> Does the first point suggest splitting this patch and isolating the USB structure changes into a separate patch?
> Or did I misunderstand?

I don't understand your question. See below.

> 
> 2. Does "two PHYs for a single device" means should define both usb PHY and DP PHY in dtsi, the USBC PHY driver's probe will run separately for both USB and DP?
> Then USB PHY node can keep forward compatibility with prop '#clock-cells = <0>' & '#phy-cells = <0>',
> and DP PHY will define with prop '#clock-cells = <1>' & '#phy-cells = <1>'.

No. It means replacing extending existing entries with bigger reg and
#phy-cells = <1>. The driver must keep working with old node definitions
as is to ensure backwards compatibility. New nodes should make it
register two PHYs (USB3 and DP). On the driver side modify generic code
paths, all platforms supported by the driver should be able to support
USB3+DP combination.

> 
> > - Make sure that the PHY driver doesn't allow both PHYs to be powered
> >   on. Add TCSR programming to the power_on / power_off callbacks,
> >   implementing the switch between DP and USB3.
> > 
> Ok, I will add TCSR switch logic to DP power_on / power_off callbacks, 
> During DP power off, default will reset to USB3 PHY.

Not quite. Both USB3 and DP drivers should be calling power_on / _off.
If USB3 is on, powering on DP PHY should fail. Vice versa, if DP is on,
powering on USB should fail.

> 
> > At this point all PHYs in qmp-usbc can be switched to the new USB+DP
> > configuration, still providing backwards compatibility with the existing
> > board DTs.
> > 
> >> In Ride, DP PHY, DP lane 0~3 and DP aux pins are connected to video-out board.
> >>>>
> >>>> On the QCS615, the USB primary PHY is currently used to handle USB 3.0 communication for the previously mentioned four USB Type-A ports, 
> >>>> while the USB3 secondary PHY and USB3 DP PHY are used for the output of the Type-C port,
> >>>> but since the Type-C port is forcibly pin-to-pin configured to the video out board, the Type-C port will always configure as DP PHY.
> >>>>
> >>>> The internal registers of these three PHYs are independent of each other, Neither their respective SWPWR_DN nor SWRST will affect the other two PHYs.
> >>>> Additionally, there was a misunderstanding about the orientation previously.
> >>>> The USB orientation setting only affects the current PHY and does not impact the DP PHY. The DP PHY is configured in the DP_PHY_CFG_1.
> >>>>
> >>>> TSCR_PHY_MODE can specify which PHY outputs to the Type-C port, and the global reset will simultaneously reset the two associated PHYs. 
> >>>> Therefore, the correct switching process is as follows.
> >>>> When switching the inserted device:
> >>>> 	1.Identify the PHY type.
> >>>> 	2.Enable the regulator.
> >>>> 	3.Trigger a reset.
> >>>> 	4.Enable the clock.
> >>>> 	5.Configure PHY type related orientation
> >>>> 	6.switch the TCSR PHY mode.
> >>>> 	7.Configure the registers of PHY.
> >>>> During release:
> >>>> 	1.Reset.
> >>>> 	2.Disable the clock.
> >>>> 	3.Disable the regulator.
> >>>>
> >>>> Our current design overall complies with this process, but it lacks the configuration for DP_PHY_CFG_1.
> >>>>
> >>>> Shall we continue the discussion to clarify remain comments of the USBC driver?
> >>>>
> >>>>>> However, I'm also confirming whether anything other will affect USB and DP each other.
> >>>>>
> >>>>
> >>>
> >>
> > 
> 

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration
  2025-03-05 21:14                   ` Dmitry Baryshkov
@ 2025-05-19  8:20                     ` Xiangxu Yin
  2025-05-19  9:58                       ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2025-05-19  8:20 UTC (permalink / raw)
  To: Dmitry Baryshkov, dmitry.baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio, quic_xiangxuy



On 3/6/2025 5:14 AM, Dmitry Baryshkov wrote:
> On Wed, Mar 05, 2025 at 06:16:45PM +0800, Xiangxu Yin wrote:
>>
>>
>> On 12/20/2024 5:45 AM, Dmitry Baryshkov wrote:
>>> On Thu, Dec 19, 2024 at 06:36:38PM +0800, Xiangxu Yin wrote:
>>>>
>>>>
>>>> On 12/5/2024 7:40 PM, Dmitry Baryshkov wrote:
>>>>> On Thu, 5 Dec 2024 at 13:28, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 12/2/2024 6:46 PM, Dmitry Baryshkov wrote:
>>>>>>> On Mon, Dec 02, 2024 at 04:40:05PM +0800, Xiangxu Yin wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On 11/29/2024 9:50 PM, Dmitry Baryshkov wrote:
>>>>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>>>>>>
>>>>>>>>>> Add the ability to configure lane mapping for the DP controller. This is
>>>>>>>>>> required when the platform's lane mapping does not follow the default
>>>>>>>>>> order (0, 1, 2, 3). The mapping rules are now configurable via the
>>>>>>>>>> `data-lane` property in the devicetree. This property defines the
>>>>>>>>>> logical-to-physical lane mapping sequence, ensuring correct lane
>>>>>>>>>> assignment for non-default configurations.
>>>>>>>>>>
>>>>>>>>>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
>>>>>>>>>> ---
>>>>>>>>>>  drivers/gpu/drm/msm/dp/dp_catalog.c | 11 +++++------
>>>>>>>>>>  drivers/gpu/drm/msm/dp/dp_catalog.h |  2 +-
>>>>>>>>>>  drivers/gpu/drm/msm/dp/dp_ctrl.c    |  2 +-
>>>>>>>>>>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 ++++++++++---
>>>>>>>>>>  drivers/gpu/drm/msm/dp/dp_panel.h   |  3 +++
>>>>>>>>>>  5 files changed, 20 insertions(+), 11 deletions(-)
>>>>>>>>>>
>>>>>>>
>>>>>>>>>> @@ -461,6 +460,7 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>>>>>>>>>>         struct msm_dp_panel_private *panel;
>>>>>>>>>>         struct device_node *of_node;
>>>>>>>>>>         int cnt;
>>>>>>>>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3};
>>>>>>>>>>
>>>>>>>>>>         panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
>>>>>>>>>>         of_node = panel->dev->of_node;
>>>>>>>>>> @@ -474,10 +474,17 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
>>>>>>>>>>                 cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
>>>>>>>>>>         }
>>>>>>>>>>
>>>>>>>>>> -       if (cnt > 0)
>>>>>>>>>> +       if (cnt > 0) {
>>>>>>>>>> +               struct device_node *endpoint;
>>>>>>>>>> +
>>>>>>>>>>                 msm_dp_panel->max_dp_lanes = cnt;
>>>>>>>>>> -       else
>>>>>>>>>> +               endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1);
>>>>>>>>>> +               of_property_read_u32_array(endpoint, "data-lanes", lane_map, cnt);
>>>>>>>>>> +       } else {
>>>>>>>>>>                 msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
>>>>>>>>>> +       }
>>>>>>>>>
>>>>>>>>> Why? This sounds more like dp_catalog or (after the refactoring at
>>>>>>>>> [1]) dp_ctrl. But not the dp_panel.
>>>>>>>>>
>>>>>>>>> [1] https://patchwork.freedesktop.org/project/freedreno/series/?ordering=-last_updated
>>>>>>>>>
>>>>>>>> We are used the same prop 'data-lanes = <3 2 0 1>' in mdss_dp_out to keep similar behaviour with dsi_host_parse_lane_data.
>>>>>>>> From the modules used, catalog seems more appropriate, but since the max_dp_lanes is parsed at dp_panel, it has been placed here.
>>>>>>>> Should lane_map parsing in msm_dp_catalog_get, and keep max_dp_lanes parsing at the dp_panel?
>>>>>>>
>>>>>>> msm_dp_catalog_get() is going to be removed. Since the functions that
>>>>>>> are going to use it are in dp_ctrl module, I thought that dp_ctrl.c is
>>>>>>> the best place. A better option might be to move max_dp_lanes and
>>>>>>> max_dp_link_rate to dp_link.c as those are link params. Then
>>>>>>> lane_mapping also logically becomes a part of dp_link module.
>>>>>>>
>>>>>>> But now I have a more important question (triggered by Krishna's email
>>>>>>> about SAR2130P's USB): if the lanes are swapped, does USB 3 work on that
>>>>>>> platform? Or is it being demoted to USB 2 with nobody noticing that?
>>>>>>>
>>>>>>> If lanes 0/1 and 2/3 are swapped, shouldn't it be handled in the QMP
>>>>>>> PHY, where we handle lanes and orientation switching?
>>>>>>>
>>>>>> I have checked the DP hardware programming guide and also discussed it with Krishna.
>>>>>>
>>>>>> According to the HPG section '3.4.2 PN and Lane Swap: PHY supports PN swap for mainlink and AUX, but it doesn't support lane swap feature.'
>>>>>>
>>>>>> The lane swap mainly refers to the logical to physical mapping between the DP controller and the DP PHY. The PHY handles polarity inversion, and the lane map does not affect USB behavior.
>>>>>>
>>>>>> On the QCS615 platform, we have also tested when DP works with lane swap, other USB 3.0 ports can works normally at super speed.
>>>>>
>>>>> "Other USB 3.0 ports"? What does that mean? Please correct me if I'm
>>>>> wrong, you should have a USB+DP combo port that is being managed with
>>>>> combo PHY. Does USB 3 work on that port?
>>>>>
>>>>> In other words, where the order of lanes is actually inverted? Between
>>>>> DP and combo PHY? Within combo PHY? Between the PHY and the pinout?
>>>>> Granted that SM6150 was supported in msm-4.14 could you possibly point
>>>>> out a corresponding commit or a set of commits from that kernel?
>>>>>
>>>> For "Other USB 3.0 ports", as replied in USBC driver, USB3 primary phy works for other four USB type-A port.
>>>
>>> So if that's the USB3 primary, then why do you mention here at all? We
>>> are taling about the secondary USB3 + DP.
>>>
>> OK, sorry for confusing you.
>>>> The REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING mapping determines how logical lanes (0, 1, 2, 3) map to physical lanes sent to the PHY.
>>>> This ensures alignment with hardware requirements.
>>>> The PHY’s polarity inversion only adjusts signal polarity and doesn’t affect lane mapping.
>>>> Both DP ctrl and PHY lane related config will not affect USB phy.
>>>
>>> Probably we misundersand each other. The DP PHY should have orientation
>>> switch register, which controls whether 2-lane DP uses lanes 0/1 or 2/3.
>>> Can you use that register?
>>>
>> Yes, DP PHY have orientation register as below.
>> DP_PHY_DP_PHY_CFG_1(0x88e9014) bit(7) SW_PORTSELECT
>>> Also, could you _please_ answer the question that I have asked? Is the
>>> order of lanes inverted between the DP controller and DP PHY? Or between
>>> DP PHY and the DP connector? If one uses USB3 signals coming from this
>>> port (yes, on the other board, not on the Ride), would they also need to
>>> switch the order of USB3 lanes? If one uses a DP-over-USB-C, are DP
>>> lanes are swapped?
>>>
>> It's inverted between the DP controller and DP PHY.
>> If other use USB3 on the other board, will not need switch order of USB3 lanes,
>> If one use DP-over-USB-C, then need DP lanes swap.
> 
> Thanks!
> 
>>>> Without extra Type-C mapping, the DP controller’s mapping indirectly decides how signals are transmitted through Type-C.
>>>> Mapping ensures proper data transmission and compatibility across interfaces.
>>>>
>>>> We only found sm6150 need this lane mapping config, 
>>>> For msm 4.14, please refer these links,
>>>> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi (qcom,logical2physical-lane-map)
>>>> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/drivers/gpu/drm/msm/dp/dp_parser.c (dp_parser_misc)
>>>> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/drivers/gpu/drm/msm/dp/dp_catalog_v200.c (dp_catalog_ctrl_lane_mapping_v200)
>>>>
>>>> If need process orientation info like dp_catalog_ctrl_lane_mapping_v200, 
>>>> then 
>>>> if implement in DP phy, then we need config dp_link register in PHY,
>>>> if implement in DP link, then we need pass orientation info to DP driver, perhaps we could add a new attribute to the phy_configure_opts_dp structure to pass this.
>>>> Do you have any suggestions?
>>>
>>> Does SW_PORTSEL_VAL affect the DP lanes on this platform?
>>>
>> SW_PORTSEL_VAL for USB3PHY_PCS_MISC_TYPEC_CTRL will not affect DP lanes in this DP or USB3 chip series.
>> USB3 will use USB3PHY_PCS_MISC_TYPEC_CTRL(SW_PORTSEL_VAL BIT_0) and DP will use DP_PHY_DP_PHY_CFG_1(SW_PORTSELECT BIT_7)
> 
> Is it possible to set this bit from the PHY driver rather than remapping
> the lanes in the DP driver?
> 
I have verified and confirmed with chip verification team.

We configured the logical2physical mapping primarily to correct the PHY output mapping.
Currently, the logical2physical mapping defines the input-to-output mapping for the DP controller, 
while the SW_PORTSELECT in PHY determines the swapping between PHY input ports 0↔3 and 1↔2.
When the DP controller input to PHY output mapping is correctly configured, PHY's SW_PORTSELECT can be used to implement flip operations. 
However, due to the improper mapping implementation on Talos platforms, using SW_PORTSELECT would require additional modifications to the logical2physical mapping.

For example, other platform except Talos implementations the data-lanes mapping follows <0 1 2 3> sequence. 
A proper flip operation should produce <3 2 1 0>, which can be equivalently achieved either through DP driver configuration or PHY portselect.
But in the Talos where the initial mapping is arranged as <3 2 0 1>, the expected post-flip sequence should be <0 1 3 2>. 
then when applying PHY SW_PORTSELECT setting 1, the PHY output becomes <1 0 2 3> which mismatches the expected pattern.

To maintain cross-platform compatibility between Talos and other platforms, recommend the flip handling at the DP driver level such like dp_catalog_ctrl_lane_mapping_v200 in sm6150.
>>>>
>>>>>>
>>>>>> Additionally, if it were placed on the PHY side, the PHY would need access to dp_link’s domain which can access REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING.
>>>>>
>>>>> I was thinking about inverting the SW_PORTSEL_VAL bit.
>>>>>
>>>>>> Therefore, we believe that the  max_dp_link_rate,max_dp_lanes and lane_map move to dp_link side is better.
>>>>>>
>>>>>>>>>> +
>>>>>>>>>> +       memcpy(msm_dp_panel->lane_map, lane_map, msm_dp_panel->max_dp_lanes * sizeof(u32));
>>>>>>>>>>
>>>>>>>>>>         msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node);
>>>>>>>>>>         if (!msm_dp_panel->max_dp_link_rate)
>>>>>>>>>> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
>>>>>>>>>> index 0e944db3adf2f187f313664fe80cf540ec7a19f2..7603b92c32902bd3d4485539bd6308537ff75a2c 100644
>>>>>>>>>> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
>>>>>>>>>> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
>>>>>>>>>> @@ -11,6 +11,8 @@
>>>>>>>>>>  #include "dp_aux.h"
>>>>>>>>>>  #include "dp_link.h"
>>>>>>>>>>
>>>>>>>>>> +#define DP_MAX_NUM_DP_LANES    4
>>>>>>>>>> +
>>>>>>>>>>  struct edid;
>>>>>>>>>>
>>>>>>>>>>  struct msm_dp_display_mode {
>>>>>>>>>> @@ -46,6 +48,7 @@ struct msm_dp_panel {
>>>>>>>>>>         bool video_test;
>>>>>>>>>>         bool vsc_sdp_supported;
>>>>>>>>>>
>>>>>>>>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES];
>>>>>>>>>>         u32 max_dp_lanes;
>>>>>>>>>>         u32 max_dp_link_rate;
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> 2.25.1
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> linux-phy mailing list
>>>>>>>> linux-phy@lists.infradead.org
>>>>>>>> https://lists.infradead.org/mailman/listinfo/linux-phy
>>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>
>>
> 


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration
  2025-05-19  8:20                     ` Xiangxu Yin
@ 2025-05-19  9:58                       ` Dmitry Baryshkov
  0 siblings, 0 replies; 60+ messages in thread
From: Dmitry Baryshkov @ 2025-05-19  9:58 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Dmitry Baryshkov, Rob Clark, Abhinav Kumar, Sean Paul,
	Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, linux-phy, linux-gpio, quic_xiangxuy

On Mon, 19 May 2025 at 11:20, Xiangxu Yin <xiangxu.yin@oss.qualcomm.com> wrote:
>
>
>
> On 3/6/2025 5:14 AM, Dmitry Baryshkov wrote:
> > On Wed, Mar 05, 2025 at 06:16:45PM +0800, Xiangxu Yin wrote:
> >>
> >>
> >> On 12/20/2024 5:45 AM, Dmitry Baryshkov wrote:
> >>> On Thu, Dec 19, 2024 at 06:36:38PM +0800, Xiangxu Yin wrote:
> >>>>
> >>>>
> >>>> On 12/5/2024 7:40 PM, Dmitry Baryshkov wrote:
> >>>>> On Thu, 5 Dec 2024 at 13:28, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>> On 12/2/2024 6:46 PM, Dmitry Baryshkov wrote:
> >>>>>>> On Mon, Dec 02, 2024 at 04:40:05PM +0800, Xiangxu Yin wrote:
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> On 11/29/2024 9:50 PM, Dmitry Baryshkov wrote:
> >>>>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>>>>>>>
> >>>>>>>>>> Add the ability to configure lane mapping for the DP controller. This is
> >>>>>>>>>> required when the platform's lane mapping does not follow the default
> >>>>>>>>>> order (0, 1, 2, 3). The mapping rules are now configurable via the
> >>>>>>>>>> `data-lane` property in the devicetree. This property defines the
> >>>>>>>>>> logical-to-physical lane mapping sequence, ensuring correct lane
> >>>>>>>>>> assignment for non-default configurations.
> >>>>>>>>>>
> >>>>>>>>>> Signed-off-by: Xiangxu Yin <quic_xiangxuy@quicinc.com>
> >>>>>>>>>> ---
> >>>>>>>>>>  drivers/gpu/drm/msm/dp/dp_catalog.c | 11 +++++------
> >>>>>>>>>>  drivers/gpu/drm/msm/dp/dp_catalog.h |  2 +-
> >>>>>>>>>>  drivers/gpu/drm/msm/dp/dp_ctrl.c    |  2 +-
> >>>>>>>>>>  drivers/gpu/drm/msm/dp/dp_panel.c   | 13 ++++++++++---
> >>>>>>>>>>  drivers/gpu/drm/msm/dp/dp_panel.h   |  3 +++
> >>>>>>>>>>  5 files changed, 20 insertions(+), 11 deletions(-)
> >>>>>>>>>>
> >>>>>>>
> >>>>>>>>>> @@ -461,6 +460,7 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
> >>>>>>>>>>         struct msm_dp_panel_private *panel;
> >>>>>>>>>>         struct device_node *of_node;
> >>>>>>>>>>         int cnt;
> >>>>>>>>>> +       u32 lane_map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3};
> >>>>>>>>>>
> >>>>>>>>>>         panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
> >>>>>>>>>>         of_node = panel->dev->of_node;
> >>>>>>>>>> @@ -474,10 +474,17 @@ static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel)
> >>>>>>>>>>                 cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
> >>>>>>>>>>         }
> >>>>>>>>>>
> >>>>>>>>>> -       if (cnt > 0)
> >>>>>>>>>> +       if (cnt > 0) {
> >>>>>>>>>> +               struct device_node *endpoint;
> >>>>>>>>>> +
> >>>>>>>>>>                 msm_dp_panel->max_dp_lanes = cnt;
> >>>>>>>>>> -       else
> >>>>>>>>>> +               endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1);
> >>>>>>>>>> +               of_property_read_u32_array(endpoint, "data-lanes", lane_map, cnt);
> >>>>>>>>>> +       } else {
> >>>>>>>>>>                 msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
> >>>>>>>>>> +       }
> >>>>>>>>>
> >>>>>>>>> Why? This sounds more like dp_catalog or (after the refactoring at
> >>>>>>>>> [1]) dp_ctrl. But not the dp_panel.
> >>>>>>>>>
> >>>>>>>>> [1] https://patchwork.freedesktop.org/project/freedreno/series/?ordering=-last_updated
> >>>>>>>>>
> >>>>>>>> We are used the same prop 'data-lanes = <3 2 0 1>' in mdss_dp_out to keep similar behaviour with dsi_host_parse_lane_data.
> >>>>>>>> From the modules used, catalog seems more appropriate, but since the max_dp_lanes is parsed at dp_panel, it has been placed here.
> >>>>>>>> Should lane_map parsing in msm_dp_catalog_get, and keep max_dp_lanes parsing at the dp_panel?
> >>>>>>>
> >>>>>>> msm_dp_catalog_get() is going to be removed. Since the functions that
> >>>>>>> are going to use it are in dp_ctrl module, I thought that dp_ctrl.c is
> >>>>>>> the best place. A better option might be to move max_dp_lanes and
> >>>>>>> max_dp_link_rate to dp_link.c as those are link params. Then
> >>>>>>> lane_mapping also logically becomes a part of dp_link module.
> >>>>>>>
> >>>>>>> But now I have a more important question (triggered by Krishna's email
> >>>>>>> about SAR2130P's USB): if the lanes are swapped, does USB 3 work on that
> >>>>>>> platform? Or is it being demoted to USB 2 with nobody noticing that?
> >>>>>>>
> >>>>>>> If lanes 0/1 and 2/3 are swapped, shouldn't it be handled in the QMP
> >>>>>>> PHY, where we handle lanes and orientation switching?
> >>>>>>>
> >>>>>> I have checked the DP hardware programming guide and also discussed it with Krishna.
> >>>>>>
> >>>>>> According to the HPG section '3.4.2 PN and Lane Swap: PHY supports PN swap for mainlink and AUX, but it doesn't support lane swap feature.'
> >>>>>>
> >>>>>> The lane swap mainly refers to the logical to physical mapping between the DP controller and the DP PHY. The PHY handles polarity inversion, and the lane map does not affect USB behavior.
> >>>>>>
> >>>>>> On the QCS615 platform, we have also tested when DP works with lane swap, other USB 3.0 ports can works normally at super speed.
> >>>>>
> >>>>> "Other USB 3.0 ports"? What does that mean? Please correct me if I'm
> >>>>> wrong, you should have a USB+DP combo port that is being managed with
> >>>>> combo PHY. Does USB 3 work on that port?
> >>>>>
> >>>>> In other words, where the order of lanes is actually inverted? Between
> >>>>> DP and combo PHY? Within combo PHY? Between the PHY and the pinout?
> >>>>> Granted that SM6150 was supported in msm-4.14 could you possibly point
> >>>>> out a corresponding commit or a set of commits from that kernel?
> >>>>>
> >>>> For "Other USB 3.0 ports", as replied in USBC driver, USB3 primary phy works for other four USB type-A port.
> >>>
> >>> So if that's the USB3 primary, then why do you mention here at all? We
> >>> are taling about the secondary USB3 + DP.
> >>>
> >> OK, sorry for confusing you.
> >>>> The REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING mapping determines how logical lanes (0, 1, 2, 3) map to physical lanes sent to the PHY.
> >>>> This ensures alignment with hardware requirements.
> >>>> The PHY’s polarity inversion only adjusts signal polarity and doesn’t affect lane mapping.
> >>>> Both DP ctrl and PHY lane related config will not affect USB phy.
> >>>
> >>> Probably we misundersand each other. The DP PHY should have orientation
> >>> switch register, which controls whether 2-lane DP uses lanes 0/1 or 2/3.
> >>> Can you use that register?
> >>>
> >> Yes, DP PHY have orientation register as below.
> >> DP_PHY_DP_PHY_CFG_1(0x88e9014) bit(7) SW_PORTSELECT
> >>> Also, could you _please_ answer the question that I have asked? Is the
> >>> order of lanes inverted between the DP controller and DP PHY? Or between
> >>> DP PHY and the DP connector? If one uses USB3 signals coming from this
> >>> port (yes, on the other board, not on the Ride), would they also need to
> >>> switch the order of USB3 lanes? If one uses a DP-over-USB-C, are DP
> >>> lanes are swapped?
> >>>
> >> It's inverted between the DP controller and DP PHY.
> >> If other use USB3 on the other board, will not need switch order of USB3 lanes,
> >> If one use DP-over-USB-C, then need DP lanes swap.
> >
> > Thanks!
> >
> >>>> Without extra Type-C mapping, the DP controller’s mapping indirectly decides how signals are transmitted through Type-C.
> >>>> Mapping ensures proper data transmission and compatibility across interfaces.
> >>>>
> >>>> We only found sm6150 need this lane mapping config,
> >>>> For msm 4.14, please refer these links,
> >>>> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi (qcom,logical2physical-lane-map)
> >>>> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/drivers/gpu/drm/msm/dp/dp_parser.c (dp_parser_misc)
> >>>> https://android.googlesource.com/kernel/msm/+/af03eef7d4c3cbd1fe26c67d4f1915b05d0c1488/drivers/gpu/drm/msm/dp/dp_catalog_v200.c (dp_catalog_ctrl_lane_mapping_v200)
> >>>>
> >>>> If need process orientation info like dp_catalog_ctrl_lane_mapping_v200,
> >>>> then
> >>>> if implement in DP phy, then we need config dp_link register in PHY,
> >>>> if implement in DP link, then we need pass orientation info to DP driver, perhaps we could add a new attribute to the phy_configure_opts_dp structure to pass this.
> >>>> Do you have any suggestions?
> >>>
> >>> Does SW_PORTSEL_VAL affect the DP lanes on this platform?
> >>>
> >> SW_PORTSEL_VAL for USB3PHY_PCS_MISC_TYPEC_CTRL will not affect DP lanes in this DP or USB3 chip series.
> >> USB3 will use USB3PHY_PCS_MISC_TYPEC_CTRL(SW_PORTSEL_VAL BIT_0) and DP will use DP_PHY_DP_PHY_CFG_1(SW_PORTSELECT BIT_7)
> >
> > Is it possible to set this bit from the PHY driver rather than remapping
> > the lanes in the DP driver?
> >
> I have verified and confirmed with chip verification team.
>
> We configured the logical2physical mapping primarily to correct the PHY output mapping.
> Currently, the logical2physical mapping defines the input-to-output mapping for the DP controller,
> while the SW_PORTSELECT in PHY determines the swapping between PHY input ports 0↔3 and 1↔2.
> When the DP controller input to PHY output mapping is correctly configured, PHY's SW_PORTSELECT can be used to implement flip operations.
> However, due to the improper mapping implementation on Talos platforms, using SW_PORTSELECT would require additional modifications to the logical2physical mapping.
>
> For example, other platform except Talos implementations the data-lanes mapping follows <0 1 2 3> sequence.
> A proper flip operation should produce <3 2 1 0>, which can be equivalently achieved either through DP driver configuration or PHY portselect.
> But in the Talos where the initial mapping is arranged as <3 2 0 1>, the expected post-flip sequence should be <0 1 3 2>.
> then when applying PHY SW_PORTSELECT setting 1, the PHY output becomes <1 0 2 3> which mismatches the expected pattern.

Ack. Thanks for the detailed explanation. Please add similar text to
the commit message, with the only change: s/Talos/SM6150/

>
> To maintain cross-platform compatibility between Talos and other platforms, recommend the flip handling at the DP driver level such like dp_catalog_ctrl_lane_mapping_v200 in sm6150.
> >>>>
> >>>>>>
> >>>>>> Additionally, if it were placed on the PHY side, the PHY would need access to dp_link’s domain which can access REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING.
> >>>>>
> >>>>> I was thinking about inverting the SW_PORTSEL_VAL bit.
> >>>>>
> >>>>>> Therefore, we believe that the  max_dp_link_rate,max_dp_lanes and lane_map move to dp_link side is better.

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 7/8] drm/msm/dp: Retry Link Training 2 with lower pattern
  2024-12-03 14:07       ` Dmitry Baryshkov
@ 2025-05-27 20:49         ` Konrad Dybcio
  2025-07-09  9:16           ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Konrad Dybcio @ 2025-05-27 20:49 UTC (permalink / raw)
  To: Dmitry Baryshkov, Xiangxu Yin
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio

On 12/3/24 3:07 PM, Dmitry Baryshkov wrote:
> On Tue, Dec 03, 2024 at 04:13:22PM +0800, Xiangxu Yin wrote:
>>
>>
>> On 11/29/2024 9:53 PM, Dmitry Baryshkov wrote:
>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>
>>>> Add a mechanism to retry Link Training 2 by lowering the pattern level
>>>> when the link training #2 first attempt fails. This approach enhances
>>>> compatibility, particularly addressing issues caused by certain hub
>>>> configurations.
>>>
>>> Please reference corresponding part of the standard, describing this lowering.
>>>
>> Per DisplayPort 1.4a specification Section 3.5.1.2 and Table 3-10, while the standard doesn't explicitly define a TPS downgrade mechanism, it does specify:
> 
> Anything in DP 2.1?
> 
>> - All devices shall support TPS1 and TPS2
>> - HDR2-capable devices shall support TPS3
>> - HDR3-capable devices shall support TPS4
>> While these capabilities are explicitly defined DPCD for sink devices, source device capabilities are less strictly defined, with the minimum requirement being support for TPS1 and TPS2.
>> In QCS615 DP phy is only supporting to HBR2, we observed a critical interoperability scenario with a DP->HDMI bridge. When link training at TPS4 consistently failed, downgrading to the next lower training pattern successfully established the link and display output successfully.
> 
> Any other driver doing such TPS lowering? Or maybe we should be
> selecting TPS3 for HBR2-only devices?

Bump, this patch looks interesting and I'd like to see it revisited if
it's correct

Konrad

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 7/8] drm/msm/dp: Retry Link Training 2 with lower pattern
  2025-05-27 20:49         ` Konrad Dybcio
@ 2025-07-09  9:16           ` Xiangxu Yin
  2025-07-19  9:43             ` Dmitry Baryshkov
  0 siblings, 1 reply; 60+ messages in thread
From: Xiangxu Yin @ 2025-07-09  9:16 UTC (permalink / raw)
  To: Konrad Dybcio, Dmitry Baryshkov, dmitry.baryshkov
  Cc: Rob Clark, Abhinav Kumar, Sean Paul, Marijn Suijten,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Kuogee Hsieh, Vinod Koul, Kishon Vijay Abraham I, Linus Walleij,
	Bartosz Golaszewski, quic_lliu6, quic_fangez, linux-arm-msm,
	dri-devel, freedreno, devicetree, linux-kernel, linux-phy,
	linux-gpio, quic_xiangxuy



On 5/28/2025 4:49 AM, Konrad Dybcio wrote:
> On 12/3/24 3:07 PM, Dmitry Baryshkov wrote:
>> On Tue, Dec 03, 2024 at 04:13:22PM +0800, Xiangxu Yin wrote:
>>>
>>>
>>> On 11/29/2024 9:53 PM, Dmitry Baryshkov wrote:
>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>
>>>>> Add a mechanism to retry Link Training 2 by lowering the pattern level
>>>>> when the link training #2 first attempt fails. This approach enhances
>>>>> compatibility, particularly addressing issues caused by certain hub
>>>>> configurations.
>>>>
>>>> Please reference corresponding part of the standard, describing this lowering.
>>>>
>>> Per DisplayPort 1.4a specification Section 3.5.1.2 and Table 3-10, while the standard doesn't explicitly define a TPS downgrade mechanism, it does specify:
>>
>> Anything in DP 2.1?
>>
In the DP 2.1 spec, mainly on section '3.6.7.2 8b/10b DP Link Layer LTTPR Link Training Mandates', defined 'LTTPR shall support TPS4'.
The other parts seems similar to the 1.4 spec.
>>> - All devices shall support TPS1 and TPS2
>>> - HDR2-capable devices shall support TPS3
>>> - HDR3-capable devices shall support TPS4
>>> While these capabilities are explicitly defined DPCD for sink devices, source device capabilities are less strictly defined, with the minimum requirement being support for TPS1 and TPS2.
>>> In QCS615 DP phy is only supporting to HBR2, we observed a critical interoperability scenario with a DP->HDMI bridge. When link training at TPS4 consistently failed, downgrading to the next lower training pattern successfully established the link and display output successfully.
>>
>> Any other driver doing such TPS lowering? Or maybe we should be
>> selecting TPS3 for HBR2-only devices?
> 
This logic is porting from qualcomm downstream, 
For other device, only found in some older Tx chips like i915(intel_dp_training_pattern) used the maximum hardware-supported patterns, but not lowering.

According to the description in DPCD table 2-232 003h, From the DP spec perspective, it appears that all supported cases should preferably adopt TPS4, as it is more robust.
'DPRXs should support TPS4 and set this bit, regardless of whether the DPRX supports HBR3 because TPS4 is more conducive to robust link establishment than TPS2 and TPS3.
0 = TPS4 is not supported.
1 = TPS4 is supported (shall be supported for downstream devices with DPCD r1.4, except for eDPRXs).'

Although maximum capability of QCS615 is HBR2, but the actual pattern supports TPS4. 
From pure design perspective, it would be cleaner to drop this lowering in next patch. 
> Bump, this patch looks interesting and I'd like to see it revisited if
> it's correct
> 
> Konrad



^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 7/8] drm/msm/dp: Retry Link Training 2 with lower pattern
  2025-07-09  9:16           ` Xiangxu Yin
@ 2025-07-19  9:43             ` Dmitry Baryshkov
  2025-07-21  4:18               ` Xiangxu Yin
  0 siblings, 1 reply; 60+ messages in thread
From: Dmitry Baryshkov @ 2025-07-19  9:43 UTC (permalink / raw)
  To: Xiangxu Yin
  Cc: Konrad Dybcio, Dmitry Baryshkov, Rob Clark, Abhinav Kumar,
	Sean Paul, Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, linux-phy, linux-gpio, quic_xiangxuy

On Wed, Jul 09, 2025 at 05:16:02PM +0800, Xiangxu Yin wrote:
> 
> 
> On 5/28/2025 4:49 AM, Konrad Dybcio wrote:
> > On 12/3/24 3:07 PM, Dmitry Baryshkov wrote:
> >> On Tue, Dec 03, 2024 at 04:13:22PM +0800, Xiangxu Yin wrote:
> >>>
> >>>
> >>> On 11/29/2024 9:53 PM, Dmitry Baryshkov wrote:
> >>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
> >>>>>
> >>>>> Add a mechanism to retry Link Training 2 by lowering the pattern level
> >>>>> when the link training #2 first attempt fails. This approach enhances
> >>>>> compatibility, particularly addressing issues caused by certain hub
> >>>>> configurations.
> >>>>
> >>>> Please reference corresponding part of the standard, describing this lowering.
> >>>>
> >>> Per DisplayPort 1.4a specification Section 3.5.1.2 and Table 3-10, while the standard doesn't explicitly define a TPS downgrade mechanism, it does specify:
> >>
> >> Anything in DP 2.1?
> >>
> In the DP 2.1 spec, mainly on section '3.6.7.2 8b/10b DP Link Layer LTTPR Link Training Mandates', defined 'LTTPR shall support TPS4'.
> The other parts seems similar to the 1.4 spec.
> >>> - All devices shall support TPS1 and TPS2
> >>> - HDR2-capable devices shall support TPS3
> >>> - HDR3-capable devices shall support TPS4
> >>> While these capabilities are explicitly defined DPCD for sink devices, source device capabilities are less strictly defined, with the minimum requirement being support for TPS1 and TPS2.
> >>> In QCS615 DP phy is only supporting to HBR2, we observed a critical interoperability scenario with a DP->HDMI bridge. When link training at TPS4 consistently failed, downgrading to the next lower training pattern successfully established the link and display output successfully.
> >>
> >> Any other driver doing such TPS lowering? Or maybe we should be
> >> selecting TPS3 for HBR2-only devices?
> > 
> This logic is porting from qualcomm downstream, 

Hopefully a downstream has some sensible commit message which describes
the issue and the configuration to reproduce it?

> For other device, only found in some older Tx chips like i915(intel_dp_training_pattern) used the maximum hardware-supported patterns, but not lowering.
> 
> According to the description in DPCD table 2-232 003h, From the DP spec perspective, it appears that all supported cases should preferably adopt TPS4, as it is more robust.

If other drivers don't perform this kind of lowering, I'd prefer if we
don't perform it too.

> 'DPRXs should support TPS4 and set this bit, regardless of whether the DPRX supports HBR3 because TPS4 is more conducive to robust link establishment than TPS2 and TPS3.
> 0 = TPS4 is not supported.
> 1 = TPS4 is supported (shall be supported for downstream devices with DPCD r1.4, except for eDPRXs).'
> 
> Although maximum capability of QCS615 is HBR2, but the actual pattern supports TPS4. 
> From pure design perspective, it would be cleaner to drop this lowering in next patch. 
> > Bump, this patch looks interesting and I'd like to see it revisited if
> > it's correct
> > 
> > Konrad
> 
> 

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH 7/8] drm/msm/dp: Retry Link Training 2 with lower pattern
  2025-07-19  9:43             ` Dmitry Baryshkov
@ 2025-07-21  4:18               ` Xiangxu Yin
  0 siblings, 0 replies; 60+ messages in thread
From: Xiangxu Yin @ 2025-07-21  4:18 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Konrad Dybcio, Dmitry Baryshkov, Rob Clark, Abhinav Kumar,
	Sean Paul, Marijn Suijten, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Kuogee Hsieh, Vinod Koul,
	Kishon Vijay Abraham I, Linus Walleij, Bartosz Golaszewski,
	quic_lliu6, quic_fangez, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, linux-phy, linux-gpio, quic_xiangxuy


On 7/19/2025 5:43 PM, Dmitry Baryshkov wrote:
> On Wed, Jul 09, 2025 at 05:16:02PM +0800, Xiangxu Yin wrote:
>>
>> On 5/28/2025 4:49 AM, Konrad Dybcio wrote:
>>> On 12/3/24 3:07 PM, Dmitry Baryshkov wrote:
>>>> On Tue, Dec 03, 2024 at 04:13:22PM +0800, Xiangxu Yin wrote:
>>>>>
>>>>> On 11/29/2024 9:53 PM, Dmitry Baryshkov wrote:
>>>>>> On Fri, 29 Nov 2024 at 09:59, Xiangxu Yin <quic_xiangxuy@quicinc.com> wrote:
>>>>>>> Add a mechanism to retry Link Training 2 by lowering the pattern level
>>>>>>> when the link training #2 first attempt fails. This approach enhances
>>>>>>> compatibility, particularly addressing issues caused by certain hub
>>>>>>> configurations.
>>>>>> Please reference corresponding part of the standard, describing this lowering.
>>>>>>
>>>>> Per DisplayPort 1.4a specification Section 3.5.1.2 and Table 3-10, while the standard doesn't explicitly define a TPS downgrade mechanism, it does specify:
>>>> Anything in DP 2.1?
>>>>
>> In the DP 2.1 spec, mainly on section '3.6.7.2 8b/10b DP Link Layer LTTPR Link Training Mandates', defined 'LTTPR shall support TPS4'.
>> The other parts seems similar to the 1.4 spec.
>>>>> - All devices shall support TPS1 and TPS2
>>>>> - HDR2-capable devices shall support TPS3
>>>>> - HDR3-capable devices shall support TPS4
>>>>> While these capabilities are explicitly defined DPCD for sink devices, source device capabilities are less strictly defined, with the minimum requirement being support for TPS1 and TPS2.
>>>>> In QCS615 DP phy is only supporting to HBR2, we observed a critical interoperability scenario with a DP->HDMI bridge. When link training at TPS4 consistently failed, downgrading to the next lower training pattern successfully established the link and display output successfully.
>>>> Any other driver doing such TPS lowering? Or maybe we should be
>>>> selecting TPS3 for HBR2-only devices?
>> This logic is porting from qualcomm downstream, 
> Hopefully a downstream has some sensible commit message which describes
> the issue and the configuration to reproduce it?

The downstream commit log shows in 2019/08, SM8250 (kernel 4.19) type-c DP meet LT2 failures on Samsung HDR curved monitor, the pattern lowering fix was adopted.
On QCS615, an mDP-to-HDMI adapter cable exhibited similar LT failure pattern, and it's works with this solution.
However, It's rare compatibility case with special device and lowering seems violates protocol standards, maybe not suitable for general deployment.

>> For other device, only found in some older Tx chips like i915(intel_dp_training_pattern) used the maximum hardware-supported patterns, but not lowering.
>>
>> According to the description in DPCD table 2-232 003h, From the DP spec perspective, it appears that all supported cases should preferably adopt TPS4, as it is more robust.
> If other drivers don't perform this kind of lowering, I'd prefer if we
> don't perform it too.
Agree,  I'll remove this patch in an upcoming version soon.
>
>> 'DPRXs should support TPS4 and set this bit, regardless of whether the DPRX supports HBR3 because TPS4 is more conducive to robust link establishment than TPS2 and TPS3.
>> 0 = TPS4 is not supported.
>> 1 = TPS4 is supported (shall be supported for downstream devices with DPCD r1.4, except for eDPRXs).'
>>
>> Although maximum capability of QCS615 is HBR2, but the actual pattern supports TPS4. 
>> From pure design perspective, it would be cleaner to drop this lowering in next patch. 
>>> Bump, this patch looks interesting and I'd like to see it revisited if
>>> it's correct
>>>
>>> Konrad
>>

^ permalink raw reply	[flat|nested] 60+ messages in thread

end of thread, other threads:[~2025-07-21  4:18 UTC | newest]

Thread overview: 60+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-29  7:57 [PATCH 0/8] Add DisplayPort support for QCS615 platform Xiangxu Yin
2024-11-29  7:57 ` [PATCH 1/8] dt-bindings: display/msm: Document DP on QCS615 Xiangxu Yin
2024-11-29  8:11   ` Krzysztof Kozlowski
2024-11-29  7:57 ` [PATCH 2/8] dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: Add DP support for QCS615 Xiangxu Yin
2024-11-29  8:14   ` Krzysztof Kozlowski
2024-11-29  7:57 ` [PATCH 3/8] phy: qcom: qmp-usbc: Add DP phy mode support on QCS615 Xiangxu Yin
2024-11-29  8:18   ` Krzysztof Kozlowski
2024-12-02 10:31     ` Xiangxu Yin
2024-12-02 15:48       ` Dmitry Baryshkov
2024-11-29 12:12   ` kernel test robot
2024-11-29 14:33   ` Dmitry Baryshkov
2024-12-05 13:26     ` Xiangxu Yin
2024-12-05 18:31       ` Dmitry Baryshkov
2024-12-10 15:09         ` Dmitry Baryshkov
2024-12-11  0:46           ` Xiangxu Yin
2024-12-11  9:46             ` Dmitry Baryshkov
2024-12-11 12:50               ` Xiangxu Yin
2024-12-11 19:15                 ` Dmitry Baryshkov
2024-12-18 12:55                   ` Xiangxu Yin
2024-12-19 21:38                     ` Dmitry Baryshkov
2024-12-20  0:01                     ` Dmitry Baryshkov
2025-03-05 10:20                       ` Xiangxu Yin
2025-03-05 21:25                         ` Dmitry Baryshkov
2025-03-21 10:17                           ` Xiangxu Yin
2025-03-21 12:19                             ` Dmitry Baryshkov
2024-11-29  7:57 ` [PATCH 4/8] drm/msm/dp: Add DisplayPort support for QCS615 Xiangxu Yin
2024-11-29 13:54   ` Dmitry Baryshkov
2024-11-29  7:57 ` [PATCH 5/8] drm/msm/dp: Add support for lane mapping configuration Xiangxu Yin
2024-11-29 13:50   ` Dmitry Baryshkov
2024-12-02  8:40     ` Xiangxu Yin
2024-12-02 10:46       ` Dmitry Baryshkov
2024-12-05 11:28         ` Xiangxu Yin
2024-12-05 11:40           ` Dmitry Baryshkov
2024-12-19 10:36             ` Xiangxu Yin
2024-12-19 21:45               ` Dmitry Baryshkov
2025-03-05 10:16                 ` Xiangxu Yin
2025-03-05 21:14                   ` Dmitry Baryshkov
2025-05-19  8:20                     ` Xiangxu Yin
2025-05-19  9:58                       ` Dmitry Baryshkov
2024-11-29  7:57 ` [PATCH 6/8] drm/msm/dp: Add maximum width limitation for modes Xiangxu Yin
2024-11-29 13:52   ` Dmitry Baryshkov
2024-12-02  9:05     ` Xiangxu Yin
2024-12-02  9:32       ` Dmitry Baryshkov
2024-12-03  7:41         ` Xiangxu Yin
2024-12-03 13:58           ` Dmitry Baryshkov
2024-12-06 20:13             ` Abhinav Kumar
2024-12-09  1:57               ` Xiangxu Yin
2024-12-09 20:18                 ` Abhinav Kumar
2024-11-29  7:57 ` [PATCH 7/8] drm/msm/dp: Retry Link Training 2 with lower pattern Xiangxu Yin
2024-11-29 13:53   ` Dmitry Baryshkov
2024-12-03  8:13     ` Xiangxu Yin
2024-12-03 14:07       ` Dmitry Baryshkov
2025-05-27 20:49         ` Konrad Dybcio
2025-07-09  9:16           ` Xiangxu Yin
2025-07-19  9:43             ` Dmitry Baryshkov
2025-07-21  4:18               ` Xiangxu Yin
2024-11-29  7:57 ` [PATCH 8/8] drm/msm/dp: Support external GPIO HPD with 3rd pinctrl chip Xiangxu Yin
2024-11-29  8:21   ` Krzysztof Kozlowski
2024-11-29 13:45   ` Dmitry Baryshkov
2024-11-29 13:54   ` neil.armstrong

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).