* [PATCH v2 0/3] phy: cix: Add Sky1 DisplayPort PHY support
@ 2026-10-12 12:36 Luo Liu
2026-10-12 12:36 ` [PATCH v2 1/3] dt-bindings: phy: Add CIX Sky1 DP PHY Luo Liu
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Luo Liu @ 2026-10-12 12:36 UTC (permalink / raw)
To: vkoul, neil.armstrong, mani, robh, krzk+dt, conor+dt, gary.yang,
fugang.duan, linux-phy, devicetree, linux-arm-kernel
Cc: cix-kernel-upstream, p.zabel, linux-kernel, Luo.Liu, Wuyi.Shen,
EastLake.Yang
Add dt-bindings, driver and DTS support for the dedicated DisplayPort
PHY on the CIX Sky1 SoC.
The PHY exposes a PMA/CDB register interface and is controlled through
the generic PHY DP configure ops (link rate, lane count, SSC and
voltage swing).
Patch 1 adds the binding and MAINTAINERS entry.
Patch 2 adds the PHY driver.
Patch 3 describes the SoC node and enables it on Radxa Orion O6.
Changes in v2:
- Move MAINTAINERS into the binding patch; keep tabs; add R: entry
- Require resets in the binding; use exclusive reset in the driver
- Include linux/property.h; document Sky1 1/2-lane physical routing
- Rename DT label to dp_phy; enable it on sky1-orion-o6
- After CDB_ENABLE, wait for busy then idle to avoid a stale READY race
Luo Liu (3):
dt-bindings: phy: Add CIX Sky1 DP PHY
phy: cix: Add Sky1 DP PHY driver
arm64: dts: cix: Add Sky1 DP PHY node
.../bindings/phy/cix,sky1-dp-phy.yaml | 53 +
MAINTAINERS | 8 +
arch/arm64/boot/dts/cix/sky1-orion-o6.dts | 4 +
arch/arm64/boot/dts/cix/sky1.dtsi | 8 +
drivers/phy/Kconfig | 1 +
drivers/phy/Makefile | 1 +
drivers/phy/cix/Kconfig | 18 +
drivers/phy/cix/Makefile | 2 +
drivers/phy/cix/phy-cix-dp.c | 985 ++++++++++++++++++
9 files changed, 1080 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
create mode 100644 drivers/phy/cix/Kconfig
create mode 100644 drivers/phy/cix/Makefile
create mode 100644 drivers/phy/cix/phy-cix-dp.c
base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
--
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] 8+ messages in thread
* [PATCH v2 1/3] dt-bindings: phy: Add CIX Sky1 DP PHY
2026-10-12 12:36 [PATCH v2 0/3] phy: cix: Add Sky1 DisplayPort PHY support Luo Liu
@ 2026-10-12 12:36 ` Luo Liu
2026-10-12 18:54 ` Conor Dooley
2026-10-12 12:36 ` [PATCH v2 2/3] phy: cix: Add Sky1 DP PHY driver Luo Liu
2026-10-12 12:36 ` [PATCH v2 3/3] arm64: dts: cix: Add Sky1 DP PHY node Luo Liu
2 siblings, 1 reply; 8+ messages in thread
From: Luo Liu @ 2026-10-12 12:36 UTC (permalink / raw)
To: vkoul, neil.armstrong, mani, robh, krzk+dt, conor+dt, gary.yang,
fugang.duan, linux-phy, devicetree, linux-arm-kernel
Cc: cix-kernel-upstream, p.zabel, linux-kernel, Luo.Liu, Wuyi.Shen,
EastLake.Yang
Document the dedicated DisplayPort PHY on CIX Sky1, including the
optional cix,external-dp board property for external connector swing.
Add a MAINTAINERS entry for the binding and driver.
Signed-off-by: Luo Liu <Luo.Liu@cixtech.com>
---
.../bindings/phy/cix,sky1-dp-phy.yaml | 53 +++++++++++++++++++
MAINTAINERS | 8 +++
2 files changed, 61 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
diff --git a/Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml b/Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
new file mode 100644
index 000000000000..c6914cab74e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
@@ -0,0 +1,53 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/cix,sky1-dp-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: CIX Sky1 DisplayPort PHY
+
+maintainers:
+ - Luo Liu <Luo.Liu@cixtech.com>
+
+description:
+ The CIX Sky1 DP PHY provides the PMA/CDB register interface for the
+ dedicated DisplayPort instance on CIX Sky1.
+
+properties:
+ compatible:
+ const: cix,sky1-dp-phy
+
+ reg:
+ maxItems: 1
+
+ "#phy-cells":
+ const: 0
+
+ resets:
+ maxItems: 1
+ description: PHY hardware reset
+
+ cix,external-dp:
+ type: boolean
+ description:
+ Use voltage swing values suitable for an external DisplayPort
+ connector instead of the default low-voltage values.
+
+required:
+ - compatible
+ - reg
+ - "#phy-cells"
+ - resets
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/reset/cix,sky1-s5-system-control.h>
+
+ phy@1414c000 {
+ compatible = "cix,sky1-dp-phy";
+ reg = <0x1414c000 0x4000>;
+ resets = <&s5_syscon SKY1_DP_PHY_RST_N>;
+ #phy-cells = <0>;
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 3a19da74d00c..b46d0f4220a9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6360,6 +6360,14 @@ M: Satish Kharat <satishkh@cisco.com>
S: Supported
F: drivers/infiniband/hw/usnic/
+CIX SKY1 DISPLAYPORT PHY DRIVER
+M: Luo Liu <Luo.Liu@cixtech.com>
+R: CIX Linux Kernel Upstream Group <cix-kernel-upstream@cixtech.com>
+L: linux-phy@lists.infradead.org
+S: Maintained
+F: Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
+F: drivers/phy/cix/
+
CLANG CONTEXT ANALYSIS
M: Marco Elver <elver@google.com>
R: Bart Van Assche <bvanassche@acm.org>
--
2.25.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 2/3] phy: cix: Add Sky1 DP PHY driver
2026-10-12 12:36 [PATCH v2 0/3] phy: cix: Add Sky1 DisplayPort PHY support Luo Liu
2026-10-12 12:36 ` [PATCH v2 1/3] dt-bindings: phy: Add CIX Sky1 DP PHY Luo Liu
@ 2026-10-12 12:36 ` Luo Liu
2026-10-12 12:47 ` sashiko-bot
2026-10-12 12:36 ` [PATCH v2 3/3] arm64: dts: cix: Add Sky1 DP PHY node Luo Liu
2 siblings, 1 reply; 8+ messages in thread
From: Luo Liu @ 2026-10-12 12:36 UTC (permalink / raw)
To: vkoul, neil.armstrong, mani, robh, krzk+dt, conor+dt, gary.yang,
fugang.duan, linux-phy, devicetree, linux-arm-kernel
Cc: cix-kernel-upstream, p.zabel, linux-kernel, Luo.Liu, Wuyi.Shen,
EastLake.Yang
Add a PHY driver for the CIX Sky1 dedicated DisplayPort PMA. Support
link rate, lane count, SSC and voltage swing via the generic PHY DP
ops. Load PMA tables in phy_init and enable the analog path in
phy_power_on so configure can run before power-on.
Signed-off-by: Luo Liu <Luo.Liu@cixtech.com>
---
drivers/phy/Kconfig | 1 +
drivers/phy/Makefile | 1 +
drivers/phy/cix/Kconfig | 18 +
drivers/phy/cix/Makefile | 2 +
drivers/phy/cix/phy-cix-dp.c | 985 +++++++++++++++++++++++++++++++++++
5 files changed, 1007 insertions(+)
create mode 100644 drivers/phy/cix/Kconfig
create mode 100644 drivers/phy/cix/Makefile
create mode 100644 drivers/phy/cix/phy-cix-dp.c
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 19f3b7d12b7d..cb0d4be47628 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -175,6 +175,7 @@ source "drivers/phy/axiado/Kconfig"
source "drivers/phy/broadcom/Kconfig"
source "drivers/phy/cadence/Kconfig"
source "drivers/phy/canaan/Kconfig"
+source "drivers/phy/cix/Kconfig"
source "drivers/phy/eswin/Kconfig"
source "drivers/phy/freescale/Kconfig"
source "drivers/phy/hisilicon/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index d7aa516bcc49..6fd0f3910018 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_GENERIC_PHY) += allwinner/ \
broadcom/ \
cadence/ \
canaan/ \
+ cix/ \
eswin/ \
freescale/ \
hisilicon/ \
diff --git a/drivers/phy/cix/Kconfig b/drivers/phy/cix/Kconfig
new file mode 100644
index 000000000000..0e429e2790bf
--- /dev/null
+++ b/drivers/phy/cix/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Phy drivers for CIX PHYs
+#
+
+config PHY_CIX_DP
+ tristate "CIX Sky1 DP PHY driver"
+ depends on OF && HAS_IOMEM
+ depends on ARCH_CIX || COMPILE_TEST
+ select GENERIC_PHY
+ help
+ Say Y here to enable the dedicated DisplayPort PHY used by the CIX
+ Sky1 DisplayPort controller. The PHY provides the physical layer
+ used by the dedicated DisplayPort output and supports link rates
+ up to HBR3.
+
+ To compile this driver as a module, choose M here. The module will
+ be called phy-cix-dp.
diff --git a/drivers/phy/cix/Makefile b/drivers/phy/cix/Makefile
new file mode 100644
index 000000000000..cc56c7586ec5
--- /dev/null
+++ b/drivers/phy/cix/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_PHY_CIX_DP) += phy-cix-dp.o
diff --git a/drivers/phy/cix/phy-cix-dp.c b/drivers/phy/cix/phy-cix-dp.c
new file mode 100644
index 000000000000..00c9d1ad6a5b
--- /dev/null
+++ b/drivers/phy/cix/phy-cix-dp.c
@@ -0,0 +1,985 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * CIX DP PHY driver
+ *
+ * Copyright (C) 2023 Trilinear Technologies
+ * Copyright 2024 Cix Technology Group Co., Ltd.
+ */
+
+#include <linux/bits.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/reset.h>
+
+#define CIX_DP_PHY_ID_REV_REG 0xfc
+#define CIX_DP_PHY_ID 0x4d
+#define CIX_DP_PHY_PWR_STATE_IDLE 0x0000
+#define CIX_DP_PHY_PWR_STATE_A0_TXRX_ACTIVE 0x0001
+#define CIX_DP_PHY_PWR_STATE_A2_POWERDOWN2 0x0004
+#define CIX_DP_PHY_PWR_STATE_A3_POWERDOWN3 0x0008
+
+#define CIX_DP_CDB_ADDR 0x0000
+#define CIX_DP_CDB_WDATA 0x0004
+#define CIX_DP_CDB_SEL_WR 0x0008
+#define CIX_DP_CDB_READY 0x000c
+#define CIX_DP_CDB_RDATA 0x0010
+#define CIX_DP_CDB_RSTN 0x0014
+#define CIX_DP_CDB_ENABLE 0x0018
+#define CIX_DP_CDB_SEL_READ 0x2
+#define CIX_DP_CDB_SEL_WRITE 0x3
+
+#define CIX_DP_NUM_LANES 4
+#define CIX_DP_POLL_SLEEP_US 10
+#define CIX_DP_POLL_TIMEOUT_US 100000
+#define CIX_DP_PWR_TIMEOUT_US 10000
+#define CIX_DP_PHY_CONFIG_RSTN 0x0040
+#define CIX_DP_PHY_CMN_READY 0x0044
+#define CIX_DP_PHY_LANE_EN_BITS 0x0048
+#define CIX_DP_PHY_LANE_RSTN_BITS 0x004c
+#define CIX_DP_PHY_DATA_ENABLE 0x0050
+#define CIX_DP_AUXHPD_ENABLE_BITS 0x0054
+#define CIX_DP_TX_ELEC_IDLE_BITS 0x0058
+#define CIX_DP_PHY_LANE_PWR_STATE_REQ 0x0060
+#define CIX_DP_PHY_LANE_PWR_STATE_ACK 0x0064
+#define CIX_DP_PHY_LANE_PLLCLK_ENABLE 0x0068
+#define CIX_DP_PHY_LANE_PLLCLK_EN_ACK 0x006c
+
+#define CIX_DP_PHY_PLL_CFG 0xc00e
+#define CIX_DP_PHY_PMA_CMN_CTRL2 0xe001
+#define CIX_DP_PHY_PMA_PLL_RAW_CTRL 0xe003
+
+/* Common (CMN) registers */
+#define CIX_DP_CMN_SSM_BIAS_TMR 0x0022
+#define CIX_DP_CMN_PLLSM0_PLLPRE_TMR 0x002a
+#define CIX_DP_CMN_PLLSM0_PLLLOCK_TMR 0x002c
+#define CIX_DP_CMN_PLLSM1_PLLPRE_TMR 0x0032
+#define CIX_DP_CMN_PLLSM1_PLLLOCK_TMR 0x0034
+#define CIX_DP_CMN_BGCAL_INIT_TMR 0x0064
+#define CIX_DP_CMN_BGCAL_ITER_TMR 0x0065
+#define CIX_DP_CMN_IBCAL_INIT_TMR 0x0074
+#define CIX_DP_CMN_PLL0_VCOCAL_TCTRL 0x0082
+#define CIX_DP_CMN_PLL0_VCOCAL_INIT_TMR 0x0084
+#define CIX_DP_CMN_PLL0_VCOCAL_ITER_TMR 0x0085
+#define CIX_DP_CMN_PLL0_VCOCAL_REFTIM_START 0x0086
+#define CIX_DP_CMN_PLL0_VCOCAL_PLLCNT_START 0x0088
+#define CIX_DP_CMN_PLL0_LOCK_REFCNT_START 0x009c
+#define CIX_DP_CMN_PLL0_LOCK_PLLCNT_START 0x009e
+#define CIX_DP_CMN_PLL0_LOCK_PLLCNT_THR 0x009f
+#define CIX_DP_CMN_PLL0_INTDIV_M0 0x0090
+#define CIX_DP_CMN_PLL0_FRACDIVL_M0 0x0091
+#define CIX_DP_CMN_PLL0_FRACDIVH_M0 0x0092
+#define CIX_DP_CMN_PLL0_HIGH_THR_M0 0x0093
+#define CIX_DP_CMN_PLL0_DSM_DIAG_M0 0x0094
+#define CIX_DP_CMN_PLL0_SS_CTRL1_M0 0x0098
+#define CIX_DP_CMN_PLL0_SS_CTRL2_M0 0x0099
+#define CIX_DP_CMN_PLL0_SS_CTRL3_M0 0x009a
+#define CIX_DP_CMN_PLL0_SS_CTRL4_M0 0x009b
+#define CIX_DP_CMN_PLL1_VCOCAL_TCTRL 0x00c2
+#define CIX_DP_CMN_PLL1_VCOCAL_INIT_TMR 0x00c4
+#define CIX_DP_CMN_PLL1_VCOCAL_ITER_TMR 0x00c5
+#define CIX_DP_CMN_PLL1_VCOCAL_REFTIM_START 0x00c6
+#define CIX_DP_CMN_PLL1_VCOCAL_PLLCNT_START 0x00c8
+#define CIX_DP_CMN_PLL1_LOCK_REFCNT_START 0x00dc
+#define CIX_DP_CMN_PLL1_LOCK_PLLCNT_START 0x00de
+#define CIX_DP_CMN_PLL1_LOCK_PLLCNT_THR 0x00df
+#define CIX_DP_CMN_PLL1_INTDIV_M0 0x00d0
+#define CIX_DP_CMN_PLL1_FRACDIVL_M0 0x00d1
+#define CIX_DP_CMN_PLL1_FRACDIVH_M0 0x00d2
+#define CIX_DP_CMN_PLL1_HIGH_THR_M0 0x00d3
+#define CIX_DP_CMN_PLL1_DSM_DIAG_M0 0x00d4
+#define CIX_DP_CMN_PLL1_SS_CTRL1_M0 0x00d8
+#define CIX_DP_CMN_PLL1_SS_CTRL2_M0 0x00d9
+#define CIX_DP_CMN_PLL1_SS_CTRL3_M0 0x00da
+#define CIX_DP_CMN_PLL1_SS_CTRL4_M0 0x00db
+#define CIX_DP_CMN_TXPUCAL_INIT_TMR 0x0104
+#define CIX_DP_CMN_TXPDCAL_INIT_TMR 0x010c
+#define CIX_DP_CMN_RXCAL_INIT_TMR 0x0114
+#define CIX_DP_CMN_SD_CAL_PLLCNT_START 0x0128
+#define CIX_DP_CMN_PDIAG_PLL0_CTRL_M0 0x01a0
+#define CIX_DP_CMN_PDIAG_PLL0_CLK_SEL_M0 0x01a1
+#define CIX_DP_CMN_PDIAG_PLL0_CP_PADJ_M0 0x01a4
+#define CIX_DP_CMN_PDIAG_PLL0_CP_IADJ_M0 0x01a5
+#define CIX_DP_CMN_PDIAG_PLL0_FILT_PADJ_M0 0x01a6
+#define CIX_DP_CMN_PDIAG_PLL1_CTRL_M0 0x01c0
+#define CIX_DP_CMN_PDIAG_PLL1_CP_PADJ_M0 0x01c4
+#define CIX_DP_CMN_PDIAG_PLL1_CP_IADJ_M0 0x01c5
+#define CIX_DP_CMN_PDIAG_PLL1_FILT_PADJ_M0 0x01c6
+
+/* Lane / TX / RX / XCVR registers */
+#define CIX_DP_TX_TXCC_CTRL 0x4040
+#define CIX_DP_TX_TXCC_CPOST_MULT_00 0x404c
+#define CIX_DP_TX_TXCC_MGNFS_MULT_000 0x4050
+#define CIX_DP_XCVR_DIAG_PLLDRC_CTRL 0x40e5
+#define CIX_DP_XCVR_DIAG_HSCLK_DIV 0x40e7
+#define CIX_DP_XCVR_DIAG_BIDI_CTRL 0x40ea
+#define CIX_DP_DRV_DIAG_TX_DRV 0x40c6
+#define CIX_DP_TX_PSC_A0 0x4100
+#define CIX_DP_TX_PSC_A2 0x4102
+#define CIX_DP_TX_PSC_A3 0x4103
+#define CIX_DP_RX_ST_TMR 0x4123
+#define CIX_DP_TX_DIAG_ACYA 0x41e7
+#define CIX_DP_RX_PSC_A0 0x8000
+#define CIX_DP_RX_PSC_A2 0x8002
+#define CIX_DP_RX_PSC_A3 0x8003
+#define CIX_DP_RX_PSC_CAL 0x8006
+#define CIX_DP_RX_SDCAL0_INIT_TMR 0x8044
+#define CIX_DP_RX_SDCAL0_ITER_TMR 0x8045
+#define CIX_DP_RX_SDCAL1_INIT_TMR 0x804c
+#define CIX_DP_RX_SDCAL1_ITER_TMR 0x804d
+#define CIX_DP_RX_REE_GCSM1_CTRL 0x8108
+#define CIX_DP_RX_REE_GCSM2_CTRL 0x8110
+#define CIX_DP_RX_REE_PERGCSM_CTRL 0x8118
+
+/* PMA bit defines */
+#define CIX_DP_PMA_CMN_CTRL2_PLL0_READY_BIT BIT(0)
+#define CIX_DP_PMA_CMN_CTRL2_PLL0_DISABLED_BIT BIT(2)
+#define CIX_DP_PMA_PLL_RAW_CTRL_PLL0_FORCE_RSTN BIT(0)
+
+#define CIX_DP_LANE_OFFSET(x) \
+ ((x) * 0x0200)
+#define CIX_DP_XCVR_DIAG_HSCLK_DIV_LANE(x) \
+ (CIX_DP_XCVR_DIAG_HSCLK_DIV + CIX_DP_LANE_OFFSET(x))
+#define CIX_DP_TX_DIAG_ACYA_LANE(x) \
+ (CIX_DP_TX_DIAG_ACYA + CIX_DP_LANE_OFFSET(x))
+#define CIX_DP_TX_TXCC_CTRL_LANE(x) \
+ (CIX_DP_TX_TXCC_CTRL + CIX_DP_LANE_OFFSET(x))
+#define CIX_DP_DRV_DIAG_TX_DRV_LANE(x) \
+ (CIX_DP_DRV_DIAG_TX_DRV + CIX_DP_LANE_OFFSET(x))
+#define CIX_DP_TX_TXCC_MGNFS_MULT_000_LANE(x) \
+ (CIX_DP_TX_TXCC_MGNFS_MULT_000 + CIX_DP_LANE_OFFSET(x))
+#define CIX_DP_TX_TXCC_CPOST_MULT_00_LANE(x) \
+ (CIX_DP_TX_TXCC_CPOST_MULT_00 + CIX_DP_LANE_OFFSET(x))
+
+enum cix_dp_pwr {
+ CIX_DP_PWR_A0,
+ CIX_DP_PWR_A2,
+ CIX_DP_PWR_A3,
+};
+
+struct cix_dp {
+ struct phy *phy;
+ struct reset_control *reset;
+ void __iomem *base;
+ bool use_low_volt;
+ bool powered;
+ unsigned int num_lanes;
+};
+
+struct cix_dp_link_cfg {
+ u32 link_rate;
+ u32 hsclk_div;
+ u32 clk_sel;
+ u32 pll_intdiv;
+ u32 pll_fracdivl;
+ u32 pll_high_thr;
+};
+
+struct cix_dp_reg {
+ u32 reg;
+ u32 val;
+ bool per_lane;
+};
+
+struct cix_dp_voltage_conf {
+ u32 tx_txcc_ctrl;
+ u32 drv_diag_tx_drv;
+ u32 tx_txcc_mgnfs_mult_000;
+ u32 tx_txcc_cpost_mult_00;
+};
+
+static const struct cix_dp_voltage_conf cix_dp_volt_cfg[] = {
+ { 0x08a4, 0x0003, 0x002a, 0x0000 }, /* swing level == 0 */
+ { 0x08a4, 0x0003, 0x001f, 0x0014 },
+ { 0x08a4, 0x0003, 0x0013, 0x0020 },
+ { 0x08a4, 0x0003, 0x000a, 0x002a },
+ { 0x08a4, 0x0003, 0x001f, 0x0000 }, /* swing level == 1 */
+ { 0x08a4, 0x0003, 0x0013, 0x0012 },
+ { 0x08a4, 0x0003, 0x0000, 0x001f },
+ { 0x08a4, 0x0003, 0x0000, 0x001f },
+ { 0x08a4, 0x0003, 0x0013, 0x0000 }, /* swing level == 2 */
+ { 0x08a4, 0x0003, 0x0000, 0x0013 },
+ { 0x08a4, 0x0003, 0x0000, 0x0013 },
+ { 0x08a4, 0x0003, 0x0000, 0x0013 },
+ { 0x08a4, 0x0003, 0x0000, 0x0000 }, /* swing level == 3 */
+ { 0x08a4, 0x0003, 0x0000, 0x0000 },
+ { 0x08a4, 0x0003, 0x0000, 0x0000 },
+ { 0x08a4, 0x0003, 0x0000, 0x0000 },
+};
+
+static const struct cix_dp_voltage_conf cix_dp_volt_low_cfg[] = {
+ { 0x08a4, 0x0003, 0x002f, 0x0000 }, /* swing level == 0 */
+ { 0x08a4, 0x0003, 0x002a, 0x000d },
+ { 0x08a4, 0x0003, 0x0026, 0x0015 },
+ { 0x08a4, 0x0003, 0x0022, 0x001b },
+ { 0x08a4, 0x0003, 0x002b, 0x0000 }, /* swing level == 1 */
+ { 0x08a4, 0x0003, 0x0027, 0x000b },
+ { 0x08a4, 0x0003, 0x0023, 0x0012 },
+ { 0x08a4, 0x0003, 0x0000, 0x0000 },
+ { 0x08a4, 0x0003, 0x0027, 0x0000 }, /* swing level == 2 */
+ { 0x08a4, 0x0003, 0x0023, 0x0009 },
+ { 0x08a4, 0x0003, 0x0000, 0x0000 },
+ { 0x08a4, 0x0003, 0x0000, 0x0000 },
+ { 0x08a4, 0x0003, 0x0023, 0x0000 }, /* swing level == 3 */
+ { 0x08a4, 0x0003, 0x0000, 0x0000 },
+ { 0x08a4, 0x0003, 0x0000, 0x0000 },
+ { 0x08a4, 0x0003, 0x0000, 0x0000 },
+};
+
+/* Default PHY programming, including SSC enabled (SS_CTRL1 = 0x1). */
+static const struct cix_dp_reg cix_dp_reg_conf[] = {
+ { CIX_DP_CMN_SSM_BIAS_TMR, 0x0018 },
+ { CIX_DP_CMN_PLLSM0_PLLPRE_TMR, 0x0030 },
+ { CIX_DP_CMN_PLLSM0_PLLLOCK_TMR, 0x00f0 },
+ { CIX_DP_CMN_PLLSM1_PLLPRE_TMR, 0x0030 },
+ { CIX_DP_CMN_PLLSM1_PLLLOCK_TMR, 0x00f0 },
+ { CIX_DP_CMN_BGCAL_INIT_TMR, 0x0078 },
+ { CIX_DP_CMN_BGCAL_ITER_TMR, 0x0078 },
+ { CIX_DP_CMN_IBCAL_INIT_TMR, 0x0018 },
+ { CIX_DP_CMN_TXPUCAL_INIT_TMR, 0x001d },
+ { CIX_DP_CMN_TXPDCAL_INIT_TMR, 0x001d },
+ { CIX_DP_CMN_RXCAL_INIT_TMR, 0x02d0 },
+ { CIX_DP_CMN_SD_CAL_PLLCNT_START, 0x0137 },
+ { CIX_DP_RX_SDCAL0_INIT_TMR, 0x0018, true },
+ { CIX_DP_RX_SDCAL0_ITER_TMR, 0x0078, true },
+ { CIX_DP_RX_SDCAL1_INIT_TMR, 0x0018, true },
+ { CIX_DP_RX_SDCAL1_ITER_TMR, 0x0078, true },
+ { CIX_DP_RX_ST_TMR, 0x0960, true },
+ { CIX_DP_PHY_PLL_CFG, 0x0000 },
+ { CIX_DP_XCVR_DIAG_HSCLK_DIV, 0x0000, true },
+ { CIX_DP_XCVR_DIAG_PLLDRC_CTRL, 0x0011, true },
+ { CIX_DP_CMN_PLL0_DSM_DIAG_M0, 0x8004 },
+ { CIX_DP_CMN_PLL1_DSM_DIAG_M0, 0x0004 },
+ { CIX_DP_CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0b17 },
+ { CIX_DP_CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0b17 },
+ { CIX_DP_CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0e01 },
+ { CIX_DP_CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0e01 },
+ { CIX_DP_CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0d05 },
+ { CIX_DP_CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0d05 },
+ { CIX_DP_CMN_PLL0_INTDIV_M0, 0x01c2 },
+ { CIX_DP_CMN_PLL1_INTDIV_M0, 0x014d },
+ { CIX_DP_CMN_PLL1_FRACDIVL_M0, 0x5555 },
+ { CIX_DP_CMN_PLL0_FRACDIVH_M0, 0x0002 },
+ { CIX_DP_CMN_PLL1_FRACDIVH_M0, 0x0002 },
+ { CIX_DP_CMN_PLL0_HIGH_THR_M0, 0x012c },
+ { CIX_DP_CMN_PLL1_HIGH_THR_M0, 0x00e0 },
+ { CIX_DP_CMN_PDIAG_PLL0_CTRL_M0, 0x1002 },
+ { CIX_DP_CMN_PDIAG_PLL1_CTRL_M0, 0x1002 },
+ { CIX_DP_CMN_PLL0_SS_CTRL1_M0, 0x0001 },
+ { CIX_DP_CMN_PLL1_SS_CTRL1_M0, 0x0001 },
+ { CIX_DP_CMN_PLL0_SS_CTRL2_M0, 0x044f },
+ { CIX_DP_CMN_PLL1_SS_CTRL2_M0, 0x03c7 },
+ { CIX_DP_CMN_PLL0_SS_CTRL3_M0, 0x007f },
+ { CIX_DP_CMN_PLL1_SS_CTRL3_M0, 0x007f },
+ { CIX_DP_CMN_PLL0_SS_CTRL4_M0, 0x0003 },
+ { CIX_DP_CMN_PLL1_SS_CTRL4_M0, 0x0003 },
+ { CIX_DP_CMN_PLL0_VCOCAL_INIT_TMR, 0x00f0 },
+ { CIX_DP_CMN_PLL1_VCOCAL_INIT_TMR, 0x00f0 },
+ { CIX_DP_CMN_PLL0_VCOCAL_ITER_TMR, 0x0004 },
+ { CIX_DP_CMN_PLL1_VCOCAL_ITER_TMR, 0x0004 },
+ { CIX_DP_CMN_PLL0_VCOCAL_REFTIM_START, 0x02f8 },
+ { CIX_DP_CMN_PLL1_VCOCAL_REFTIM_START, 0x02f8 },
+ { CIX_DP_CMN_PLL0_VCOCAL_PLLCNT_START, 0x02f6 },
+ { CIX_DP_CMN_PLL1_VCOCAL_PLLCNT_START, 0x02f6 },
+ { CIX_DP_CMN_PLL0_VCOCAL_TCTRL, 0x0003 },
+ { CIX_DP_CMN_PLL1_VCOCAL_TCTRL, 0x0003 },
+ { CIX_DP_CMN_PLL0_LOCK_REFCNT_START, 0x00bf },
+ { CIX_DP_CMN_PLL1_LOCK_REFCNT_START, 0x00bf },
+ { CIX_DP_CMN_PLL0_LOCK_PLLCNT_START, 0x00bf },
+ { CIX_DP_CMN_PLL1_LOCK_PLLCNT_START, 0x00bf },
+ { CIX_DP_CMN_PLL0_LOCK_PLLCNT_THR, 0x0005 },
+ { CIX_DP_CMN_PLL1_LOCK_PLLCNT_THR, 0x0005 },
+ { CIX_DP_TX_PSC_A0, 0x00fb, true },
+ { CIX_DP_TX_PSC_A2, 0x04aa, true },
+ { CIX_DP_TX_PSC_A3, 0x04aa, true },
+ { CIX_DP_RX_PSC_A0, 0x0000, true },
+ { CIX_DP_RX_PSC_A2, 0x0000, true },
+ { CIX_DP_RX_PSC_A3, 0x0000, true },
+ { CIX_DP_RX_PSC_CAL, 0x0000, true },
+ { CIX_DP_XCVR_DIAG_BIDI_CTRL, 0x000f, true },
+ { CIX_DP_RX_REE_GCSM1_CTRL, 0x0000, true },
+ { CIX_DP_RX_REE_GCSM2_CTRL, 0x0000, true },
+ { CIX_DP_RX_REE_PERGCSM_CTRL, 0x0000, true },
+};
+
+/*
+ * Supported DisplayPort link rates in Mb/s. 2160 and 4320 listed by
+ * phy-dp.h are not implemented on this PHY.
+ */
+static const struct cix_dp_link_cfg cix_dp_link_cfg[] = {
+ { 1620, 0x0002, 0x0f01, 0x0195, 0x0000, 0x010e },
+ { 2430, 0x0001, 0x0701, 0x0195, 0x0000, 0x010e },
+ { 2700, 0x0001, 0x0701, 0x01c2, 0x0000, 0x012c },
+ { 3240, 0x0002, 0x0b00, 0x0195, 0x0000, 0x010e },
+ { 5400, 0x0000, 0x0301, 0x01c2, 0x0000, 0x012c },
+ { 8100, 0x0000, 0x0200, 0x0151, 0x8000, 0x00e2 },
+};
+
+/*
+ * Sky1 routes 1- and 2-lane DP through physical lanes 2/3, not 0/1.
+ * phy-dp.h describes logical lanes starting from lane 0; map them with
+ * +2 so enable/reset masks and voltage programming hit the wired pads.
+ */
+static u32 cix_dp_phy_lane_bits(unsigned int lanes)
+{
+ switch (lanes) {
+ case 1:
+ return BIT(2);
+ case 2:
+ return BIT(2) | BIT(3);
+ case 4:
+ return GENMASK(3, 0);
+ default:
+ return 0;
+ }
+}
+
+static void cix_dp_phy_write(struct cix_dp *dp, u32 offset, u32 value)
+{
+ writel(value, dp->base + offset);
+}
+
+static int cix_dp_phy_cdb_ready(struct cix_dp *dp)
+{
+ u32 value;
+
+ return readl_poll_timeout(dp->base + CIX_DP_CDB_READY, value,
+ value & BIT(0), CIX_DP_POLL_SLEEP_US,
+ CIX_DP_POLL_TIMEOUT_US);
+}
+
+/*
+ * After kicking CDB_ENABLE, READY may stay high for a few clocks before the
+ * IP drops it. Poll tightly for busy so a stale READY=1 is not taken as
+ * completion. The busy pulse can be shorter than a sleeping poll, so ignore
+ * a missed busy and still wait for idle.
+ */
+static int cix_dp_phy_cdb_complete(struct cix_dp *dp)
+{
+ u32 value;
+
+ readl_poll_timeout_atomic(dp->base + CIX_DP_CDB_READY, value,
+ !(value & BIT(0)), 0, 1);
+
+ return cix_dp_phy_cdb_ready(dp);
+}
+
+static int cix_dp_phy_cdb_write(struct cix_dp *dp, u32 offset, u32 data)
+{
+ int ret;
+
+ ret = cix_dp_phy_cdb_ready(dp);
+ if (ret)
+ return ret;
+
+ writel(offset, dp->base + CIX_DP_CDB_ADDR);
+ writel(data, dp->base + CIX_DP_CDB_WDATA);
+ writel(CIX_DP_CDB_SEL_WRITE, dp->base + CIX_DP_CDB_SEL_WR);
+ writel(1, dp->base + CIX_DP_CDB_ENABLE);
+
+ return cix_dp_phy_cdb_complete(dp);
+}
+
+static int cix_dp_phy_cdb_read(struct cix_dp *dp, u32 offset)
+{
+ int ret;
+
+ ret = cix_dp_phy_cdb_ready(dp);
+ if (ret)
+ return ret;
+
+ writel(offset, dp->base + CIX_DP_CDB_ADDR);
+ writel(CIX_DP_CDB_SEL_READ, dp->base + CIX_DP_CDB_SEL_WR);
+ writel(1, dp->base + CIX_DP_CDB_ENABLE);
+
+ ret = cix_dp_phy_cdb_complete(dp);
+ if (ret)
+ return ret;
+
+ return readl(dp->base + CIX_DP_CDB_RDATA) & GENMASK(15, 0);
+}
+
+static int cix_dp_phy_apply_reg(struct cix_dp *dp, const struct cix_dp_reg *r)
+{
+ unsigned int i;
+ int ret;
+
+ if (!r->per_lane)
+ return cix_dp_phy_cdb_write(dp, r->reg, r->val);
+
+ for (i = 0; i < CIX_DP_NUM_LANES; i++) {
+ ret = cix_dp_phy_cdb_write(dp, r->reg + CIX_DP_LANE_OFFSET(i),
+ r->val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cix_dp_common_ready_ack(struct cix_dp *dp)
+{
+ u32 value;
+
+ return readl_poll_timeout(dp->base + CIX_DP_PHY_CMN_READY, value,
+ value & BIT(0), CIX_DP_POLL_SLEEP_US,
+ CIX_DP_POLL_TIMEOUT_US);
+}
+
+static int cix_dp_pll_raw_ctrl_ack(struct cix_dp *dp, u32 mask)
+{
+ int value;
+ int ret;
+
+ ret = read_poll_timeout(cix_dp_phy_cdb_read, value,
+ value < 0 || value & mask,
+ CIX_DP_POLL_SLEEP_US, CIX_DP_POLL_TIMEOUT_US,
+ false, dp, CIX_DP_PHY_PMA_CMN_CTRL2);
+ if (ret)
+ return ret;
+
+ return value < 0 ? value : 0;
+}
+
+static int cix_dp_lane_pll_ack(struct cix_dp *dp, bool enabled)
+{
+ u32 value;
+
+ return readl_poll_timeout(dp->base + CIX_DP_PHY_LANE_PLLCLK_EN_ACK,
+ value, !!(value & BIT(0)) == enabled,
+ CIX_DP_POLL_SLEEP_US, CIX_DP_POLL_TIMEOUT_US);
+}
+
+static int cix_dp_pwr_state_ack(struct cix_dp *dp, u32 pwr_state)
+{
+ u32 value;
+
+ return readl_poll_timeout(dp->base + CIX_DP_PHY_LANE_PWR_STATE_ACK,
+ value, (value & GENMASK(4, 0)) == pwr_state,
+ CIX_DP_POLL_SLEEP_US, CIX_DP_PWR_TIMEOUT_US);
+}
+
+static int cix_dp_phy_pwr_req(struct cix_dp *dp, u32 pwr_state)
+{
+ int ret;
+
+ cix_dp_phy_write(dp, CIX_DP_PHY_LANE_PWR_STATE_REQ, pwr_state);
+ ret = cix_dp_pwr_state_ack(dp, pwr_state);
+ cix_dp_phy_write(dp, CIX_DP_PHY_LANE_PWR_STATE_REQ,
+ CIX_DP_PHY_PWR_STATE_IDLE);
+
+ return ret;
+}
+
+static int cix_dp_hw_power(struct cix_dp *dp, enum cix_dp_pwr pwr_state)
+{
+ switch (pwr_state) {
+ case CIX_DP_PWR_A0:
+ return cix_dp_phy_pwr_req(dp,
+ CIX_DP_PHY_PWR_STATE_A0_TXRX_ACTIVE);
+ case CIX_DP_PWR_A2:
+ return cix_dp_phy_pwr_req(dp,
+ CIX_DP_PHY_PWR_STATE_A2_POWERDOWN2);
+ case CIX_DP_PWR_A3:
+ return cix_dp_phy_pwr_req(dp,
+ CIX_DP_PHY_PWR_STATE_A3_POWERDOWN3);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int cix_dp_pll_disable(struct cix_dp *dp)
+{
+ u32 mask = CIX_DP_PMA_CMN_CTRL2_PLL0_DISABLED_BIT;
+ int ret;
+
+ cix_dp_phy_write(dp, CIX_DP_PHY_DATA_ENABLE, 0);
+ ret = cix_dp_hw_power(dp, CIX_DP_PWR_A3);
+ if (ret)
+ return ret;
+
+ cix_dp_phy_write(dp, CIX_DP_PHY_LANE_PLLCLK_ENABLE, 0);
+ ret = cix_dp_lane_pll_ack(dp, false);
+ if (ret)
+ return ret;
+
+ ret = cix_dp_phy_cdb_write(dp, CIX_DP_PHY_PMA_PLL_RAW_CTRL, 0);
+ if (ret)
+ return ret;
+
+ return cix_dp_pll_raw_ctrl_ack(dp, mask);
+}
+
+static int cix_dp_pll_enable(struct cix_dp *dp)
+{
+ u32 mask = CIX_DP_PMA_CMN_CTRL2_PLL0_READY_BIT;
+ int ret;
+
+ ret = cix_dp_phy_cdb_write(dp, CIX_DP_PHY_PMA_PLL_RAW_CTRL, 1);
+ if (ret)
+ return ret;
+
+ ret = cix_dp_pll_raw_ctrl_ack(dp, mask);
+ if (ret)
+ return ret;
+
+ cix_dp_phy_write(dp, CIX_DP_PHY_LANE_PLLCLK_ENABLE, 1);
+ ret = cix_dp_lane_pll_ack(dp, true);
+ if (ret)
+ return ret;
+
+ ret = cix_dp_hw_power(dp, CIX_DP_PWR_A2);
+ if (ret)
+ return ret;
+
+ ret = cix_dp_hw_power(dp, CIX_DP_PWR_A0);
+ if (ret)
+ return ret;
+
+ cix_dp_phy_write(dp, CIX_DP_PHY_DATA_ENABLE, 1);
+
+ return 0;
+}
+
+static int cix_dp_phy_set_ssc(struct cix_dp *dp, bool enable)
+{
+ u32 val = enable ? 0x0001 : 0x0000;
+ int ret;
+
+ ret = cix_dp_phy_cdb_write(dp, CIX_DP_CMN_PLL0_SS_CTRL1_M0, val);
+ if (ret)
+ return ret;
+
+ return cix_dp_phy_cdb_write(dp, CIX_DP_CMN_PLL1_SS_CTRL1_M0, val);
+}
+
+static int cix_dp_phy_set_lanes(struct cix_dp *dp, unsigned int lanes)
+{
+ u32 mask;
+
+ mask = cix_dp_phy_lane_bits(lanes);
+ if (!mask)
+ return -EINVAL;
+
+ dp->num_lanes = lanes;
+ cix_dp_phy_write(dp, CIX_DP_PHY_LANE_RSTN_BITS, mask);
+ cix_dp_phy_write(dp, CIX_DP_PHY_LANE_EN_BITS, mask);
+ cix_dp_phy_write(dp, CIX_DP_TX_ELEC_IDLE_BITS,
+ (~mask) & GENMASK(CIX_DP_NUM_LANES - 1, 0));
+
+ return 0;
+}
+
+static int cix_dp_phy_set_link_rate(struct cix_dp *dp,
+ const struct phy_configure_opts_dp *opts)
+{
+ const struct cix_dp_link_cfg *cfg = NULL;
+ unsigned int i;
+ u32 reg;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(cix_dp_link_cfg); i++) {
+ if (cix_dp_link_cfg[i].link_rate == opts->link_rate) {
+ cfg = &cix_dp_link_cfg[i];
+ break;
+ }
+ }
+
+ if (!cfg)
+ return -EINVAL;
+
+ if (dp->powered) {
+ ret = cix_dp_pll_disable(dp);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < CIX_DP_NUM_LANES; i++) {
+ reg = CIX_DP_XCVR_DIAG_HSCLK_DIV_LANE(i);
+ ret = cix_dp_phy_cdb_write(dp, reg, cfg->hsclk_div);
+ if (ret)
+ return ret;
+ }
+
+ ret = cix_dp_phy_cdb_write(dp, CIX_DP_CMN_PLL0_INTDIV_M0,
+ cfg->pll_intdiv);
+ if (ret)
+ return ret;
+
+ ret = cix_dp_phy_cdb_write(dp, CIX_DP_CMN_PLL0_FRACDIVL_M0,
+ cfg->pll_fracdivl);
+ if (ret)
+ return ret;
+
+ ret = cix_dp_phy_cdb_write(dp, CIX_DP_CMN_PLL0_HIGH_THR_M0,
+ cfg->pll_high_thr);
+ if (ret)
+ return ret;
+
+ ret = cix_dp_phy_cdb_write(dp, CIX_DP_CMN_PDIAG_PLL0_CLK_SEL_M0,
+ cfg->clk_sel);
+ if (ret)
+ return ret;
+
+ ret = cix_dp_phy_set_ssc(dp, opts->ssc);
+ if (ret)
+ return ret;
+
+ if (dp->powered)
+ return cix_dp_pll_enable(dp);
+
+ return 0;
+}
+
+static int cix_dp_phy_set_lane_voltage(struct cix_dp *dp, u32 lane,
+ const struct cix_dp_voltage_conf *cfg)
+{
+ int value;
+ int ret;
+
+ value = cix_dp_phy_cdb_read(dp, CIX_DP_TX_DIAG_ACYA_LANE(lane));
+ if (value < 0)
+ return value;
+
+ ret = cix_dp_phy_cdb_write(dp, CIX_DP_TX_DIAG_ACYA_LANE(lane),
+ value | BIT(0));
+ if (ret)
+ return ret;
+
+ ret = cix_dp_phy_cdb_write(dp, CIX_DP_TX_TXCC_CTRL_LANE(lane),
+ cfg->tx_txcc_ctrl);
+ if (ret)
+ return ret;
+
+ ret = cix_dp_phy_cdb_write(dp, CIX_DP_DRV_DIAG_TX_DRV_LANE(lane),
+ cfg->drv_diag_tx_drv);
+ if (ret)
+ return ret;
+
+ ret = cix_dp_phy_cdb_write(dp,
+ CIX_DP_TX_TXCC_MGNFS_MULT_000_LANE(lane),
+ cfg->tx_txcc_mgnfs_mult_000);
+ if (ret)
+ return ret;
+
+ ret = cix_dp_phy_cdb_write(dp,
+ CIX_DP_TX_TXCC_CPOST_MULT_00_LANE(lane),
+ cfg->tx_txcc_cpost_mult_00);
+ if (ret)
+ return ret;
+
+ return cix_dp_phy_cdb_write(dp, CIX_DP_TX_DIAG_ACYA_LANE(lane),
+ value & ~BIT(0));
+}
+
+static int cix_dp_phy_set_voltages(struct cix_dp *dp,
+ const struct phy_configure_opts_dp *opts)
+{
+ const struct cix_dp_voltage_conf *table;
+ const struct cix_dp_voltage_conf *cfg;
+ unsigned int lane;
+ unsigned int phy_lane;
+ unsigned int index;
+ int ret;
+
+ if (opts->lanes != 1 && opts->lanes != 2 && opts->lanes != 4)
+ return -EINVAL;
+
+ table = dp->use_low_volt ? cix_dp_volt_low_cfg : cix_dp_volt_cfg;
+
+ for (lane = 0; lane < opts->lanes; lane++) {
+ if (opts->voltage[lane] > 3 || opts->pre[lane] > 3 ||
+ opts->voltage[lane] + opts->pre[lane] > 3)
+ return -EINVAL;
+
+ index = opts->voltage[lane] * 4 + opts->pre[lane];
+ cfg = &table[index];
+
+ /* One- and two-lane modes use the upper physical lanes. */
+ phy_lane = opts->lanes == 4 ? lane : lane + 2;
+ ret = cix_dp_phy_set_lane_voltage(dp, phy_lane, cfg);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cix_dp_toggle_reset(struct cix_dp *dp)
+{
+ int ret;
+
+ ret = reset_control_assert(dp->reset);
+ if (ret)
+ return ret;
+ usleep_range(10, 20);
+
+ ret = reset_control_deassert(dp->reset);
+ if (ret)
+ return ret;
+ usleep_range(10, 20);
+
+ return 0;
+}
+
+static int cix_dp_hw_prepare(struct cix_dp *dp)
+{
+ struct device *dev = &dp->phy->dev;
+ u32 id;
+ int ret;
+
+ ret = cix_dp_toggle_reset(dp);
+ if (ret)
+ return ret;
+
+ id = readl(dp->base + CIX_DP_PHY_ID_REV_REG) >> 16;
+ if (id != CIX_DP_PHY_ID) {
+ dev_err(dev, "unsupported PHY id 0x%x\n", id);
+ return -ENODEV;
+ }
+
+ /* enable PHY's local configuration bus */
+ cix_dp_phy_write(dp, CIX_DP_CDB_RSTN, 1);
+
+ /* reset AUXHPD block */
+ cix_dp_phy_write(dp, CIX_DP_AUXHPD_ENABLE_BITS, 0);
+ cix_dp_phy_write(dp, CIX_DP_TX_ELEC_IDLE_BITS, 0xf);
+
+ /* reset PHY */
+ cix_dp_phy_write(dp, CIX_DP_PHY_DATA_ENABLE, 0);
+ cix_dp_phy_write(dp, CIX_DP_PHY_LANE_RSTN_BITS, 0);
+ cix_dp_phy_write(dp, CIX_DP_PHY_LANE_EN_BITS, 0);
+
+ cix_dp_phy_write(dp, CIX_DP_PHY_CONFIG_RSTN, 0);
+ udelay(1);
+
+ /* enable Cadence AUXHPD block */
+ cix_dp_phy_write(dp, CIX_DP_AUXHPD_ENABLE_BITS, 1);
+ udelay(1);
+ cix_dp_phy_write(dp, CIX_DP_AUXHPD_ENABLE_BITS, 3);
+ udelay(1);
+ cix_dp_phy_write(dp, CIX_DP_AUXHPD_ENABLE_BITS, 7);
+ udelay(5);
+
+ /* aux lines enabled for TX and RX */
+ cix_dp_phy_write(dp, CIX_DP_AUXHPD_ENABLE_BITS, 0xf);
+
+ return 0;
+}
+
+static int cix_dp_hw_load_regs(struct cix_dp *dp)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(cix_dp_reg_conf); i++) {
+ ret = cix_dp_phy_apply_reg(dp, &cix_dp_reg_conf[i]);
+ if (ret)
+ return ret;
+ }
+
+ return cix_dp_phy_cdb_write(dp, CIX_DP_PHY_PMA_PLL_RAW_CTRL,
+ CIX_DP_PMA_PLL_RAW_CTRL_PLL0_FORCE_RSTN);
+}
+
+static int cix_dp_hw_power_on(struct cix_dp *dp)
+{
+ int ret;
+
+ if (dp->powered)
+ return 0;
+
+ ret = cix_dp_phy_set_lanes(dp, dp->num_lanes);
+ if (ret)
+ return ret;
+
+ cix_dp_phy_write(dp, CIX_DP_PHY_CONFIG_RSTN, 0x0001);
+ ret = cix_dp_common_ready_ack(dp);
+ if (ret)
+ return ret;
+
+ ret = cix_dp_pll_enable(dp);
+ if (ret)
+ return ret;
+
+ dp->powered = true;
+
+ return 0;
+}
+
+static int cix_dp_hw_power_off(struct cix_dp *dp)
+{
+ int ret;
+
+ if (!dp->powered)
+ return 0;
+
+ ret = cix_dp_pll_disable(dp);
+ if (ret)
+ return ret;
+
+ dp->powered = false;
+
+ return 0;
+}
+
+static int cix_dp_hw_reset(struct cix_dp *dp)
+{
+ int ret;
+
+ ret = cix_dp_toggle_reset(dp);
+ if (ret)
+ return ret;
+
+ cix_dp_phy_write(dp, CIX_DP_PHY_DATA_ENABLE, 0);
+ cix_dp_phy_write(dp, CIX_DP_PHY_LANE_RSTN_BITS, 0);
+ cix_dp_phy_write(dp, CIX_DP_PHY_LANE_EN_BITS, 0);
+ cix_dp_phy_write(dp, CIX_DP_PHY_CONFIG_RSTN, 0);
+ dp->powered = false;
+
+ return 0;
+}
+
+static int cix_dp_hw_configure(struct cix_dp *dp,
+ union phy_configure_opts *opts)
+{
+ struct phy_configure_opts_dp *dp_opts = &opts->dp;
+ int ret;
+
+ if (dp_opts->set_lanes) {
+ ret = cix_dp_phy_set_lanes(dp, dp_opts->lanes);
+ if (ret)
+ return ret;
+ }
+
+ if (dp_opts->set_rate) {
+ ret = cix_dp_phy_set_link_rate(dp, dp_opts);
+ if (ret)
+ return ret;
+ }
+
+ if (dp_opts->set_voltages)
+ return cix_dp_phy_set_voltages(dp, dp_opts);
+
+ return 0;
+}
+
+static int cix_dp_init(struct phy *phy)
+{
+ struct cix_dp *dp = phy_get_drvdata(phy);
+ int ret;
+
+ ret = cix_dp_hw_prepare(dp);
+ if (ret)
+ return ret;
+
+ return cix_dp_hw_load_regs(dp);
+}
+
+static int cix_dp_exit(struct phy *phy)
+{
+ struct cix_dp *dp = phy_get_drvdata(phy);
+
+ return cix_dp_hw_reset(dp);
+}
+
+static int cix_dp_power_on(struct phy *phy)
+{
+ struct cix_dp *dp = phy_get_drvdata(phy);
+
+ return cix_dp_hw_power_on(dp);
+}
+
+static int cix_dp_power_off(struct phy *phy)
+{
+ struct cix_dp *dp = phy_get_drvdata(phy);
+
+ return cix_dp_hw_power_off(dp);
+}
+
+static int cix_dp_reset(struct phy *phy)
+{
+ struct cix_dp *dp = phy_get_drvdata(phy);
+
+ return cix_dp_hw_reset(dp);
+}
+
+static int cix_dp_configure(struct phy *phy,
+ union phy_configure_opts *opts)
+{
+ struct cix_dp *dp = phy_get_drvdata(phy);
+
+ return cix_dp_hw_configure(dp, opts);
+}
+
+static const struct phy_ops cix_dp_ops = {
+ .init = cix_dp_init,
+ .exit = cix_dp_exit,
+ .power_on = cix_dp_power_on,
+ .power_off = cix_dp_power_off,
+ .configure = cix_dp_configure,
+ .reset = cix_dp_reset,
+ .owner = THIS_MODULE,
+};
+
+static int cix_dp_probe(struct platform_device *pdev)
+{
+ struct phy_provider *phy_provider;
+ struct device *dev = &pdev->dev;
+ struct cix_dp *dp;
+
+ dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
+ if (!dp)
+ return -ENOMEM;
+
+ dp->num_lanes = CIX_DP_NUM_LANES;
+ dp->use_low_volt =
+ !device_property_read_bool(dev, "cix,external-dp");
+
+ dp->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(dp->base))
+ return PTR_ERR(dp->base);
+
+ dp->reset = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(dp->reset))
+ return dev_err_probe(dev, PTR_ERR(dp->reset),
+ "failed to get reset\n");
+
+ dp->phy = devm_phy_create(dev, dev->of_node, &cix_dp_ops);
+ if (IS_ERR(dp->phy))
+ return dev_err_probe(dev, PTR_ERR(dp->phy),
+ "failed to create PHY\n");
+
+ phy_set_drvdata(dp->phy, dp);
+ phy_set_bus_width(dp->phy, CIX_DP_NUM_LANES);
+ platform_set_drvdata(pdev, dp);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return dev_err_probe(dev, PTR_ERR(phy_provider),
+ "failed to register PHY provider\n");
+
+ return 0;
+}
+
+static const struct of_device_id cix_dp_of_match[] = {
+ { .compatible = "cix,sky1-dp-phy" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cix_dp_of_match);
+
+static struct platform_driver cix_dp_driver = {
+ .probe = cix_dp_probe,
+ .driver = {
+ .name = "cix-dp-phy",
+ .of_match_table = cix_dp_of_match,
+ },
+};
+module_platform_driver(cix_dp_driver);
+
+MODULE_AUTHOR("Luo Liu <Luo.Liu@cixtech.com>");
+MODULE_AUTHOR("Eastlake Yang <Eastlake.Yang@cixtech.com>");
+MODULE_DESCRIPTION("CIX DP PHY driver");
+MODULE_LICENSE("GPL");
--
2.25.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 3/3] arm64: dts: cix: Add Sky1 DP PHY node
2026-10-12 12:36 [PATCH v2 0/3] phy: cix: Add Sky1 DisplayPort PHY support Luo Liu
2026-10-12 12:36 ` [PATCH v2 1/3] dt-bindings: phy: Add CIX Sky1 DP PHY Luo Liu
2026-10-12 12:36 ` [PATCH v2 2/3] phy: cix: Add Sky1 DP PHY driver Luo Liu
@ 2026-10-12 12:36 ` Luo Liu
2 siblings, 0 replies; 8+ messages in thread
From: Luo Liu @ 2026-10-12 12:36 UTC (permalink / raw)
To: vkoul, neil.armstrong, mani, robh, krzk+dt, conor+dt, gary.yang,
fugang.duan, linux-phy, devicetree, linux-arm-kernel
Cc: cix-kernel-upstream, p.zabel, linux-kernel, Luo.Liu, Wuyi.Shen,
EastLake.Yang
Describe the Sky1 DP PHY in the SoC DTSI so DisplayPort can consume it
once the controller is enabled. Enable the PHY on the Radxa Orion O6
board.
Signed-off-by: Luo Liu <Luo.Liu@cixtech.com>
---
arch/arm64/boot/dts/cix/sky1-orion-o6.dts | 4 ++++
arch/arm64/boot/dts/cix/sky1.dtsi | 8 ++++++++
2 files changed, 12 insertions(+)
diff --git a/arch/arm64/boot/dts/cix/sky1-orion-o6.dts b/arch/arm64/boot/dts/cix/sky1-orion-o6.dts
index e39c87774c12..b659c10f1f4d 100644
--- a/arch/arm64/boot/dts/cix/sky1-orion-o6.dts
+++ b/arch/arm64/boot/dts/cix/sky1-orion-o6.dts
@@ -36,6 +36,10 @@ linux,cma {
};
+&dp_phy {
+ status = "okay";
+};
+
&fch_gpio0 {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/cix/sky1.dtsi b/arch/arm64/boot/dts/cix/sky1.dtsi
index 0a820f45feb9..33bd2173fb85 100644
--- a/arch/arm64/boot/dts/cix/sky1.dtsi
+++ b/arch/arm64/boot/dts/cix/sky1.dtsi
@@ -762,6 +762,14 @@ ppi_partition1: interrupt-partition-1 {
};
};
+ dp_phy: phy@1414c000 {
+ compatible = "cix,sky1-dp-phy";
+ reg = <0x0 0x1414c000 0x0 0x4000>;
+ resets = <&s5_syscon SKY1_DP_PHY_RST_N>;
+ #phy-cells = <0>;
+ status = "disabled";
+ };
+
s5_syscon: syscon@16000000 {
compatible = "cix,sky1-s5-system-control", "syscon";
reg = <0x0 0x16000000 0x0 0x1000>;
--
2.25.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/3] phy: cix: Add Sky1 DP PHY driver
2026-10-12 12:36 ` [PATCH v2 2/3] phy: cix: Add Sky1 DP PHY driver Luo Liu
@ 2026-10-12 12:47 ` sashiko-bot
2026-10-13 9:26 ` 回复: " Luo Liu (刘罗)
0 siblings, 1 reply; 8+ messages in thread
From: sashiko-bot @ 2026-10-12 12:47 UTC (permalink / raw)
To: Luo Liu
Cc: olteanv, devicetree, vkoul, linux-phy, neil.armstrong, conor+dt,
robh
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] phy: cix: missing state restore on cix_dp_phy_set_lane_voltage() error path
- [Medium] phy: cix: Race condition in CDB transaction completion due to ignored busy pulse timeout
--
commit 813f2a99f8250a74e6b3856914829e75ea21a786
Author: Luo Liu <Luo.Liu@cixtech.com>
phy: cix: Add Sky1 DP PHY driver
This commit adds a PHY driver for the CIX Sky1 dedicated DisplayPort PMA.
It supports configuring the link rate, lane count, SSC, and voltage swing
using the generic PHY DP operations.
> diff --git a/drivers/phy/cix/phy-cix-dp.c b/drivers/phy/cix/phy-cix-dp.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/phy/cix/phy-cix-dp.c
[ ... ]
> +static int cix_dp_phy_cdb_complete(struct cix_dp *dp)
> +{
> + u32 value;
> +
> + readl_poll_timeout_atomic(dp->base + CIX_DP_CDB_READY, value,
> + !(value & BIT(0)), 0, 1);
> +
> + return cix_dp_phy_cdb_ready(dp);
> +}
[Severity: Medium]
Does this explicitly suppress the return value from the busy-pulse poll?
If the hardware takes longer than 1us to drop the CIX_DP_CDB_READY bit to 0
after CIX_DP_CDB_ENABLE is written, the first polling loop will time out and
the error is ignored. The second polling loop in cix_dp_phy_cdb_ready()
could then immediately read the stale READY == 1 state and return success
before the hardware actually processes the command.
Can this race condition lead to PHY initialization failures by allowing
overlapping commands to be issued to the hardware?
[ ... ]
> +static int cix_dp_phy_set_lane_voltage(struct cix_dp *dp, u32 lane,
> + const struct cix_dp_voltage_conf *cfg)
> +{
> + int value;
> + int ret;
> +
> + value = cix_dp_phy_cdb_read(dp, CIX_DP_TX_DIAG_ACYA_LANE(lane));
> + if (value < 0)
> + return value;
> +
> + ret = cix_dp_phy_cdb_write(dp, CIX_DP_TX_DIAG_ACYA_LANE(lane),
> + value | BIT(0));
> + if (ret)
> + return ret;
> +
> + ret = cix_dp_phy_cdb_write(dp, CIX_DP_TX_TXCC_CTRL_LANE(lane),
> + cfg->tx_txcc_ctrl);
> + if (ret)
> + return ret;
[Severity: Medium]
If this write or any subsequent configuration write fails, the function
returns immediately. Does this skip the cleanup step at the end of the
function that restores the CIX_DP_TX_DIAG_ACYA_LANE register?
It appears that returning early leaves the hardware stuck in a diagnostic
override state (with BIT(0) still set), which might silently corrupt future
operations or link training attempts. Should these error paths ensure the
original state is restored?
> +
> + ret = cix_dp_phy_cdb_write(dp, CIX_DP_DRV_DIAG_TX_DRV_LANE(lane),
> + cfg->drv_diag_tx_drv);
> + if (ret)
> + return ret;
> +
> + ret = cix_dp_phy_cdb_write(dp,
> + CIX_DP_TX_TXCC_MGNFS_MULT_000_LANE(lane),
> + cfg->tx_txcc_mgnfs_mult_000);
> + if (ret)
> + return ret;
> +
> + ret = cix_dp_phy_cdb_write(dp,
> + CIX_DP_TX_TXCC_CPOST_MULT_00_LANE(lane),
> + cfg->tx_txcc_cpost_mult_00);
> + if (ret)
> + return ret;
> +
> + return cix_dp_phy_cdb_write(dp, CIX_DP_TX_DIAG_ACYA_LANE(lane),
> + value & ~BIT(0));
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261012123618.648930-1-Luo.Liu@cixtech.com?part=2
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/3] dt-bindings: phy: Add CIX Sky1 DP PHY
2026-10-12 12:36 ` [PATCH v2 1/3] dt-bindings: phy: Add CIX Sky1 DP PHY Luo Liu
@ 2026-10-12 18:54 ` Conor Dooley
2026-10-13 8:50 ` 回复: " Luo Liu (刘罗)
0 siblings, 1 reply; 8+ messages in thread
From: Conor Dooley @ 2026-10-12 18:54 UTC (permalink / raw)
To: Luo Liu
Cc: vkoul, neil.armstrong, mani, robh, krzk+dt, conor+dt, gary.yang,
fugang.duan, linux-phy, devicetree, linux-arm-kernel,
cix-kernel-upstream, p.zabel, linux-kernel, Wuyi.Shen,
EastLake.Yang
[-- Attachment #1.1: Type: text/plain, Size: 3040 bytes --]
On Mon, Oct 12, 2026 at 08:36:16PM +0800, Luo Liu wrote:
> Document the dedicated DisplayPort PHY on CIX Sky1, including the
> optional cix,external-dp board property for external connector swing.
> Add a MAINTAINERS entry for the binding and driver.
>
> Signed-off-by: Luo Liu <Luo.Liu@cixtech.com>
> ---
> .../bindings/phy/cix,sky1-dp-phy.yaml | 53 +++++++++++++++++++
> MAINTAINERS | 8 +++
> 2 files changed, 61 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
>
> diff --git a/Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml b/Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
> new file mode 100644
> index 000000000000..c6914cab74e0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
> @@ -0,0 +1,53 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/phy/cix,sky1-dp-phy.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: CIX Sky1 DisplayPort PHY
> +
> +maintainers:
> + - Luo Liu <Luo.Liu@cixtech.com>
> +
> +description:
> + The CIX Sky1 DP PHY provides the PMA/CDB register interface for the
> + dedicated DisplayPort instance on CIX Sky1.
> +
> +properties:
> + compatible:
> + const: cix,sky1-dp-phy
> +
> + reg:
> + maxItems: 1
> +
> + "#phy-cells":
> + const: 0
> +
> + resets:
> + maxItems: 1
> + description: PHY hardware reset
> +
> + cix,external-dp:
> + type: boolean
> + description:
> + Use voltage swing values suitable for an external DisplayPort
> + connector instead of the default low-voltage values.
> +
> +required:
> + - compatible
> + - reg
> + - "#phy-cells"
> + - resets
A reset but no clocks? That's a bit hard to believe.
Seems fine otherwise, unless I am missing some sort of common property
for the voltage swing stuff.
Thanks,
Conor.
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/reset/cix,sky1-s5-system-control.h>
> +
> + phy@1414c000 {
> + compatible = "cix,sky1-dp-phy";
> + reg = <0x1414c000 0x4000>;
> + resets = <&s5_syscon SKY1_DP_PHY_RST_N>;
> + #phy-cells = <0>;
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3a19da74d00c..b46d0f4220a9 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6360,6 +6360,14 @@ M: Satish Kharat <satishkh@cisco.com>
> S: Supported
> F: drivers/infiniband/hw/usnic/
>
> +CIX SKY1 DISPLAYPORT PHY DRIVER
> +M: Luo Liu <Luo.Liu@cixtech.com>
> +R: CIX Linux Kernel Upstream Group <cix-kernel-upstream@cixtech.com>
> +L: linux-phy@lists.infradead.org
> +S: Maintained
> +F: Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
> +F: drivers/phy/cix/
> +
> CLANG CONTEXT ANALYSIS
> M: Marco Elver <elver@google.com>
> R: Bart Van Assche <bvanassche@acm.org>
> --
> 2.25.1
>
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 112 bytes --]
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 8+ messages in thread
* 回复: [PATCH v2 1/3] dt-bindings: phy: Add CIX Sky1 DP PHY
2026-10-12 18:54 ` Conor Dooley
@ 2026-10-13 8:50 ` Luo Liu (刘罗)
0 siblings, 0 replies; 8+ messages in thread
From: Luo Liu (刘罗) @ 2026-10-13 8:50 UTC (permalink / raw)
To: Conor Dooley
Cc: vkoul@kernel.org, neil.armstrong@linaro.org, mani@kernel.org,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
Gary Yang (杨新伟),
Fugang Duan (段富刚),
linux-phy@lists.infradead.org, devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, cix-kernel-upstream,
p.zabel@pengutronix.de, linux-kernel@vger.kernel.org,
Wuyi Shen (沈武义),
Eastlake Yang (杨东虎)
HI Conor,
Thank you very much for your reply and suggestions.
-----邮件原件-----
发件人: Conor Dooley <conor@kernel.org>
发送时间: 2026年10月13日 2:55
收件人: Luo Liu (刘罗) <Luo.Liu@cixtech.com>
抄送: vkoul@kernel.org; neil.armstrong@linaro.org; mani@kernel.org; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org; Gary Yang (杨新伟) <gary.yang@cixtech.com>; Fugang Duan (段富刚) <fugang.duan@cixtech.com>; linux-phy@lists.infradead.org; devicetree@vger.kernel.org; linux-arm-kernel@lists.infradead.org; cix-kernel-upstream <cix-kernel-upstream@cixtech.com>; p.zabel@pengutronix.de; linux-kernel@vger.kernel.org; Wuyi Shen (沈武义) <Wuyi.Shen@cixtech.com>; Eastlake Yang (杨东虎) <EastLake.Yang@cixtech.com>
主题: Re: [PATCH v2 1/3] dt-bindings: phy: Add CIX Sky1 DP PHY
On Mon, Oct 12, 2026 at 08:36:16PM +0800, Luo Liu wrote:
> Document the dedicated DisplayPort PHY on CIX Sky1, including the
> optional cix,external-dp board property for external connector swing.
> Add a MAINTAINERS entry for the binding and driver.
>
> Signed-off-by: Luo Liu <Luo.Liu@cixtech.com>
> ---
> .../bindings/phy/cix,sky1-dp-phy.yaml | 53 +++++++++++++++++++
> MAINTAINERS | 8 +++
> 2 files changed, 61 insertions(+)
> create mode 100644
> Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
>
> diff --git
> a/Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
> b/Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
> new file mode 100644
> index 000000000000..c6914cab74e0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
> @@ -0,0 +1,53 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/phy/cix,sky1-dp-phy.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: CIX Sky1 DisplayPort PHY
> +
> +maintainers:
> + - Luo Liu <Luo.Liu@cixtech.com>
> +
> +description:
> + The CIX Sky1 DP PHY provides the PMA/CDB register interface for the
> + dedicated DisplayPort instance on CIX Sky1.
> +
> +properties:
> + compatible:
> + const: cix,sky1-dp-phy
> +
> + reg:
> + maxItems: 1
> +
> + "#phy-cells":
> + const: 0
> +
> + resets:
> + maxItems: 1
> + description: PHY hardware reset
> +
> + cix,external-dp:
> + type: boolean
> + description:
> + Use voltage swing values suitable for an external DisplayPort
> + connector instead of the default low-voltage values.
> +
> +required:
> + - compatible
> + - reg
> + - "#phy-cells"
> + - resets
A reset but no clocks? That's a bit hard to believe.
Seems fine otherwise, unless I am missing some sort of common property for the voltage swing stuff.
Thanks,
Conor.
1,Regarding the missing clocks property:
The PHY APB clock is physically the same clock as the DPTx controller APB clock. It is described and
managed only by the DPTx controller driver, so the PHY node does not list a separate clocks property.
The PHY driver only implements the standard PHY callbacks. It does not touch the hardware in probe;
All PHY programming happens later, when the DPTx driver actively calls phy_init() / phy_power_on() / phy_configure()
and similar interfaces.
By that time the shared APB clock is already under DPTx control.
So from this binding's point of view there are no clocks to describe ― only the reset line owned by the PHY node.
2,On the voltage swing property: there is no suitable common DT property for this.
The flag only selects which vendor calibration table to use for the same PHY IP ― the DisplayPort swing/EQ table
versus the eDP table.
Runtime swing/pre-emphasis levels still come from phy_configure_opts_dp as usual.
The old name cix,external-dp was misleading. I will rename it to cix,edp (present => eDP table, absent => DP table)
and update the driver and binding accordingly in v3.
Thanks,
Luo.
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/reset/cix,sky1-s5-system-control.h>
> +
> + phy@1414c000 {
> + compatible = "cix,sky1-dp-phy";
> + reg = <0x1414c000 0x4000>;
> + resets = <&s5_syscon SKY1_DP_PHY_RST_N>;
> + #phy-cells = <0>;
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS index
> 3a19da74d00c..b46d0f4220a9 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6360,6 +6360,14 @@ M: Satish Kharat <satishkh@cisco.com>
> S: Supported
> F: drivers/infiniband/hw/usnic/
>
> +CIX SKY1 DISPLAYPORT PHY DRIVER
> +M: Luo Liu <Luo.Liu@cixtech.com>
> +R: CIX Linux Kernel Upstream Group <cix-kernel-upstream@cixtech.com>
> +L: linux-phy@lists.infradead.org
> +S: Maintained
> +F: Documentation/devicetree/bindings/phy/cix,sky1-dp-phy.yaml
> +F: drivers/phy/cix/
> +
> CLANG CONTEXT ANALYSIS
> M: Marco Elver <elver@google.com>
> R: Bart Van Assche <bvanassche@acm.org>
> --
> 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] 8+ messages in thread
* 回复: [PATCH v2 2/3] phy: cix: Add Sky1 DP PHY driver
2026-10-12 12:47 ` sashiko-bot
@ 2026-10-13 9:26 ` Luo Liu (刘罗)
0 siblings, 0 replies; 8+ messages in thread
From: Luo Liu (刘罗) @ 2026-10-13 9:26 UTC (permalink / raw)
To: sashiko-reviews@lists.linux.dev
Cc: olteanv@gmail.com, devicetree@vger.kernel.org, vkoul@kernel.org,
linux-phy@lists.infradead.org, neil.armstrong@linaro.org,
conor+dt@kernel.org, robh@kernel.org
HI Sashiko,
Thank you very much for your reply and suggestions.
-----邮件原件-----
发件人: sashiko-bot@kernel.org <sashiko-bot@kernel.org>
发送时间: 2026年10月12日 20:48
收件人: Luo Liu (刘罗) <Luo.Liu@cixtech.com>
抄送: olteanv@gmail.com; devicetree@vger.kernel.org; vkoul@kernel.org; linux-phy@lists.infradead.org; neil.armstrong@linaro.org; conor+dt@kernel.org; robh@kernel.org
主题: Re: [PATCH v2 2/3] phy: cix: Add Sky1 DP PHY driver
[你通常不会收到来自 sashiko-bot@kernel.org 的电子邮件。请访问 https://aka.ms/LearnAboutSenderIdentification,以了解这一点为什么很重要]
EXTERNAL EMAIL
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] phy: cix: missing state restore on cix_dp_phy_set_lane_voltage() error path
- [Medium] phy: cix: Race condition in CDB transaction completion due to ignored busy pulse timeout
--
commit 813f2a99f8250a74e6b3856914829e75ea21a786
Author: Luo Liu <Luo.Liu@cixtech.com>
phy: cix: Add Sky1 DP PHY driver
This commit adds a PHY driver for the CIX Sky1 dedicated DisplayPort PMA.
It supports configuring the link rate, lane count, SSC, and voltage swing using the generic PHY DP operations.
> diff --git a/drivers/phy/cix/phy-cix-dp.c
> b/drivers/phy/cix/phy-cix-dp.c new file mode 100644
> --- /dev/null
> +++ b/drivers/phy/cix/phy-cix-dp.c
[ ... ]
> +static int cix_dp_phy_cdb_complete(struct cix_dp *dp) {
> + u32 value;
> +
> + readl_poll_timeout_atomic(dp->base + CIX_DP_CDB_READY, value,
> + !(value & BIT(0)), 0, 1);
> +
> + return cix_dp_phy_cdb_ready(dp); }
[Severity: Medium]
Does this explicitly suppress the return value from the busy-pulse poll?
If the hardware takes longer than 1us to drop the CIX_DP_CDB_READY bit to 0 after CIX_DP_CDB_ENABLE is written, the first polling loop will time out and the error is ignored. The second polling loop in cix_dp_phy_cdb_ready() could then immediately read the stale READY == 1 state and return success before the hardware actually processes the command.
Can this race condition lead to PHY initialization failures by allowing overlapping commands to be issued to the hardware?
Yes, the busy-poll return is intentionally ignored.
ASIC confirmed in RTL that READY drops within a few clocks after ENABLE, which is far below the 1 us atomic poll window, so we do observe busy before waiting for completion. Treating a missed busy pulse
as a hard error previously caused false timeouts and broke display bring-up.
[ ... ]
> +static int cix_dp_phy_set_lane_voltage(struct cix_dp *dp, u32 lane,
> + const struct cix_dp_voltage_conf
> +*cfg) {
> + int value;
> + int ret;
> +
> + value = cix_dp_phy_cdb_read(dp, CIX_DP_TX_DIAG_ACYA_LANE(lane));
> + if (value < 0)
> + return value;
> +
> + ret = cix_dp_phy_cdb_write(dp, CIX_DP_TX_DIAG_ACYA_LANE(lane),
> + value | BIT(0));
> + if (ret)
> + return ret;
> +
> + ret = cix_dp_phy_cdb_write(dp, CIX_DP_TX_TXCC_CTRL_LANE(lane),
> + cfg->tx_txcc_ctrl);
> + if (ret)
> + return ret;
[Severity: Medium]
If this write or any subsequent configuration write fails, the function returns immediately. Does this skip the cleanup step at the end of the function that restores the CIX_DP_TX_DIAG_ACYA_LANE register?
It appears that returning early leaves the hardware stuck in a diagnostic override state (with BIT(0) still set), which might silently corrupt future operations or link training attempts. Should these error paths ensure the original state is restored?
> +
> + ret = cix_dp_phy_cdb_write(dp, CIX_DP_DRV_DIAG_TX_DRV_LANE(lane),
> + cfg->drv_diag_tx_drv);
> + if (ret)
> + return ret;
> +
> + ret = cix_dp_phy_cdb_write(dp,
> + CIX_DP_TX_TXCC_MGNFS_MULT_000_LANE(lane),
> + cfg->tx_txcc_mgnfs_mult_000);
> + if (ret)
> + return ret;
> +
> + ret = cix_dp_phy_cdb_write(dp,
> + CIX_DP_TX_TXCC_CPOST_MULT_00_LANE(lane),
> + cfg->tx_txcc_cpost_mult_00);
> + if (ret)
> + return ret;
> +
> + return cix_dp_phy_cdb_write(dp, CIX_DP_TX_DIAG_ACYA_LANE(lane),
> + value & ~BIT(0)); }
Good catch, thanks. Early returns after setting BIT(0) can leave TX_DIAG_ACYA stuck in the diagnostic override state. I'll fix the error paths in v3 so the original ACYA state is always restored.
Thanks,
Luo.
--
Sashiko AI review ・ https://sashiko.dev/#/patchset/20261012123618.648930-1-Luo.Liu@cixtech.com?part=2
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-10-13 9:26 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-12 12:36 [PATCH v2 0/3] phy: cix: Add Sky1 DisplayPort PHY support Luo Liu
2026-10-12 12:36 ` [PATCH v2 1/3] dt-bindings: phy: Add CIX Sky1 DP PHY Luo Liu
2026-10-12 18:54 ` Conor Dooley
2026-10-13 8:50 ` 回复: " Luo Liu (刘罗)
2026-10-12 12:36 ` [PATCH v2 2/3] phy: cix: Add Sky1 DP PHY driver Luo Liu
2026-10-12 12:47 ` sashiko-bot
2026-10-13 9:26 ` 回复: " Luo Liu (刘罗)
2026-10-12 12:36 ` [PATCH v2 3/3] arm64: dts: cix: Add Sky1 DP PHY node Luo Liu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox