From 78a474b5a31a25e0a77e50df42be925f7cb575e6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 11 Aug 2025 15:54:04 +0200 Subject: [PATCH 01/64] dt-bindings: phy: fsl,imx8mq-usb: Drop 'db' suffix duplicating dtschema A common property unit suffix '-db' was added to dtschema, thus in-kernel bindings should not reference the type. Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250811-dt-bindings-db-v1-2-457301523bb5@linaro.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml index 22dd91591a09..6a47e08e0e97 100644 --- a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml +++ b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml @@ -76,7 +76,6 @@ properties: description: Adjust TX de-emphasis attenuation in dB at nominal 3.5dB point as per USB specification - $ref: /schemas/types.yaml#/definitions/uint32 minimum: 0 maximum: 36 From 689a54acb56858c85de8c7285db82b8ae6dbf683 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 23 Jul 2025 13:01:28 +0300 Subject: [PATCH 02/64] phy: cdns-dphy: Store hs_clk_rate and return it The DPHY driver does not return the actual hs_clk_rate, so the DSI driver has no idea what clock was actually achieved. Set the realized hs_clk_rate to the opts struct, so that the DSI driver gets it back. Reviewed-by: Aradhya Bhatia Tested-by: Parth Pancholi Tested-by: Jayesh Choudhary Acked-by: Vinod Koul Reviewed-by: Devarsh Thakkar Signed-off-by: Tomi Valkeinen Link: https://lore.kernel.org/r/20250723-cdns-dphy-hs-clk-rate-fix-v1-1-d4539d44cbe7@ideasonboard.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/cdns-dphy.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c index ed87a3970f83..f79ec4fab409 100644 --- a/drivers/phy/cadence/cdns-dphy.c +++ b/drivers/phy/cadence/cdns-dphy.c @@ -79,6 +79,7 @@ struct cdns_dphy_cfg { u8 pll_ipdiv; u8 pll_opdiv; u16 pll_fbdiv; + u32 hs_clk_rate; unsigned int nlanes; }; @@ -154,6 +155,9 @@ static int cdns_dsi_get_dphy_pll_cfg(struct cdns_dphy *dphy, cfg->pll_ipdiv, pll_ref_hz); + cfg->hs_clk_rate = div_u64((u64)pll_ref_hz * cfg->pll_fbdiv, + 2 * cfg->pll_opdiv * cfg->pll_ipdiv); + return 0; } @@ -297,6 +301,7 @@ static int cdns_dphy_config_from_opts(struct phy *phy, if (ret) return ret; + opts->hs_clk_rate = cfg->hs_clk_rate; opts->wakeup = cdns_dphy_get_wakeup_time_ns(dphy) / 1000; return 0; From 2674eb7114ff37a7da55767860d49642eba39329 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 23 Jul 2025 13:01:29 +0300 Subject: [PATCH 03/64] phy: cdns-dphy: Remove leftover code The code in cdns-dphy has probably been part of a DSI driver in the past. Remove DSI defines and variables which are not used or do not actually do anything. Also rename cdns_dsi_get_dphy_pll_cfg() to cdns_dphy_get_pll_cfg(), i.e. drop the "dsi", as it's not relevant here. Reviewed-by: Aradhya Bhatia Tested-by: Parth Pancholi Acked-by: Vinod Koul Tested-by: Jayesh Choudhary Reviewed-by: Devarsh Thakkar Signed-off-by: Tomi Valkeinen Link: https://lore.kernel.org/r/20250723-cdns-dphy-hs-clk-rate-fix-v1-2-d4539d44cbe7@ideasonboard.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/cdns-dphy.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c index f79ec4fab409..33a42e72362e 100644 --- a/drivers/phy/cadence/cdns-dphy.c +++ b/drivers/phy/cadence/cdns-dphy.c @@ -55,14 +55,6 @@ #define DPHY_PSM_CFG_FROM_REG BIT(0) #define DPHY_PSM_CLK_DIV(x) ((x) << 1) -#define DSI_HBP_FRAME_OVERHEAD 12 -#define DSI_HSA_FRAME_OVERHEAD 14 -#define DSI_HFP_FRAME_OVERHEAD 6 -#define DSI_HSS_VSS_VSE_FRAME_OVERHEAD 4 -#define DSI_BLANKING_FRAME_OVERHEAD 6 -#define DSI_NULL_FRAME_OVERHEAD 6 -#define DSI_EOT_PKT_SIZE 4 - #define DPHY_TX_J721E_WIZ_PLL_CTRL 0xF04 #define DPHY_TX_J721E_WIZ_STATUS 0xF08 #define DPHY_TX_J721E_WIZ_RST_CTRL 0xF0C @@ -117,10 +109,9 @@ static const unsigned int tx_bands[] = { 870, 950, 1000, 1200, 1400, 1600, 1800, 2000, 2200, 2500 }; -static int cdns_dsi_get_dphy_pll_cfg(struct cdns_dphy *dphy, - struct cdns_dphy_cfg *cfg, - struct phy_configure_opts_mipi_dphy *opts, - unsigned int *dsi_hfp_ext) +static int cdns_dphy_get_pll_cfg(struct cdns_dphy *dphy, + struct cdns_dphy_cfg *cfg, + struct phy_configure_opts_mipi_dphy *opts) { unsigned long pll_ref_hz = clk_get_rate(dphy->pll_ref_clk); u64 dlane_bps; @@ -289,15 +280,13 @@ static int cdns_dphy_config_from_opts(struct phy *phy, struct cdns_dphy_cfg *cfg) { struct cdns_dphy *dphy = phy_get_drvdata(phy); - unsigned int dsi_hfp_ext = 0; int ret; ret = phy_mipi_dphy_config_validate(opts); if (ret) return ret; - ret = cdns_dsi_get_dphy_pll_cfg(dphy, cfg, - opts, &dsi_hfp_ext); + ret = cdns_dphy_get_pll_cfg(dphy, cfg, opts); if (ret) return ret; From 497e78c7a3a069f4fc62ef501d067fea27db6af4 Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Mon, 24 Feb 2025 18:10:05 +0530 Subject: [PATCH 04/64] phy: cadence: cdns-dphy-rx: Add runtime PM support Enable runtime power management for the device. The PHY framework handles calling pm_runtime_(get|put)_sync when powering on/off this device. Signed-off-by: Jai Luthra Link: https://lore.kernel.org/r/20250224-cdns_phy_pm-v1-1-0fe2c544cc87@ideasonboard.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/cdns-dphy-rx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/cadence/cdns-dphy-rx.c b/drivers/phy/cadence/cdns-dphy-rx.c index 7729cf80a9bd..3ac80141189c 100644 --- a/drivers/phy/cadence/cdns-dphy-rx.c +++ b/drivers/phy/cadence/cdns-dphy-rx.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #define DPHY_PMA_CMN(reg) (reg) @@ -265,7 +266,7 @@ static int cdns_dphy_rx_probe(struct platform_device *pdev) return PTR_ERR(provider); } - return 0; + return devm_pm_runtime_enable(dev); } static const struct of_device_id cdns_dphy_rx_of_match[] = { From 8209b3f79703b8ff09f84a79c46ead0df7260d9f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 15:16:23 +0200 Subject: [PATCH 05/64] phy: ti: omap-usb2: enable compile testing Nothing seems to prevent the driver from being built on non-TI platforms so enable compile testing for wider build coverage. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724131623.2662-1-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/ti/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig index b905902d5750..b40f28019131 100644 --- a/drivers/phy/ti/Kconfig +++ b/drivers/phy/ti/Kconfig @@ -62,7 +62,7 @@ config OMAP_CONTROL_PHY config OMAP_USB2 tristate "OMAP USB2 PHY Driver" - depends on ARCH_OMAP2PLUS || ARCH_K3 + depends on ARCH_OMAP2PLUS || ARCH_K3 || COMPILE_TEST depends on USB_SUPPORT select GENERIC_PHY select USB_PHY From 7bb14b61b7d03db770b7e8871493f5b9b2be2b79 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 23 Jul 2025 07:23:22 +0000 Subject: [PATCH 06/64] phy: rockchip: naneng-combphy: Enable U3 OTG port for RK3568 The boot firmware may disable the U3 port early during boot and leave it up to the controller or PHY driver to re-enable U3 when needed. The Rockchip USBDP PHY driver currently does this for RK3576 and RK3588, something the Rockchip Naneng Combo PHY driver never does for RK3568. This may result in USB 3.0 ports being limited to only using USB 2.0 or in special cases not working at all on RK3568. Write to PIPE_GRF USB3OTGx_CON1 reg to ensure the U3 port is enabled when a PHY with PHY_TYPE_USB3 mode is used. Fixes: 7160820d742a ("phy: rockchip: add naneng combo phy for RK3568") Signed-off-by: Jonas Karlman Link: https://lore.kernel.org/r/20250723072324.2246498-1-jonas@kwiboo.se Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-naneng-combphy.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index ce91fb1d5167..17c6310f4b54 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -137,6 +137,8 @@ struct rockchip_combphy_grfcfg { struct combphy_reg pipe_xpcs_phy_ready; struct combphy_reg pipe_pcie1l0_sel; struct combphy_reg pipe_pcie1l1_sel; + struct combphy_reg u3otg0_port_en; + struct combphy_reg u3otg1_port_en; }; struct rockchip_combphy_cfg { @@ -594,6 +596,14 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false); rockchip_combphy_param_write(priv->phy_grf, &cfg->usb_mode_set, true); + switch (priv->id) { + case 0: + rockchip_combphy_param_write(priv->pipe_grf, &cfg->u3otg0_port_en, true); + break; + case 1: + rockchip_combphy_param_write(priv->pipe_grf, &cfg->u3otg1_port_en, true); + break; + } break; case PHY_TYPE_SATA: @@ -737,6 +747,8 @@ static const struct rockchip_combphy_grfcfg rk3568_combphy_grfcfgs = { /* pipe-grf */ .pipe_con0_for_sata = { 0x0000, 15, 0, 0x00, 0x2220 }, .pipe_xpcs_phy_ready = { 0x0040, 2, 2, 0x00, 0x01 }, + .u3otg0_port_en = { 0x0104, 15, 0, 0x0181, 0x1100 }, + .u3otg1_port_en = { 0x0144, 15, 0, 0x0181, 0x1100 }, }; static const struct rockchip_combphy_cfg rk3568_combphy_cfgs = { From 4ca28157bd52dfa6df665f8854d754cc03f45acf Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 28 Jul 2025 10:29:43 +0000 Subject: [PATCH 07/64] dt-bindings: soc: rockchip: Add RK3528 pipe-phy GRF syscon Add compatible string for pipe-phy GRF found on RK3528 SoC, which controls misc settings for the integrated naneng-combphy. Signed-off-by: Yao Zi Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250728102947.38984-3-ziyao@disroot.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/soc/rockchip/grf.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml index 1ab0b092e2a5..fe5361713167 100644 --- a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml +++ b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml @@ -16,6 +16,7 @@ properties: - enum: - rockchip,rk3288-sgrf - rockchip,rk3528-ioc-grf + - rockchip,rk3528-pipe-phy-grf - rockchip,rk3528-vo-grf - rockchip,rk3528-vpu-grf - rockchip,rk3562-ioc-grf From 43a9fade69799bd10e315e87cdc60a3f75b85414 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 28 Jul 2025 10:29:44 +0000 Subject: [PATCH 08/64] dt-bindings: phy: rockchip: naneng-combphy: Add power-domains property Though isn't described in existing devicetrees, most Rockchip combphys belong to a specific power-domain of the SoC. Taking RK3588 as example, combphy 0 and combphy 2 belong to the PD_BUS domain. Document the power-domains property to allow describing the information correctly in devicetree. Signed-off-by: Yao Zi Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250728102947.38984-4-ziyao@disroot.org Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml index 3e101c3c5ea9..db293d2fbf1a 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml @@ -45,6 +45,9 @@ properties: phy-supply: description: Single PHY regulator + power-domains: + maxItems: 1 + rockchip,enable-ssc: type: boolean description: From b6c02cba32b9902b2b51dee740f1d3af8271820a Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 28 Jul 2025 10:29:45 +0000 Subject: [PATCH 09/64] dt-bindings: phy: rockchip: naneng-combphy: Add RK3528 variant Rockchip RK3528 ships one naneng-combphy which operates in either PCIe or USB 3 mode. Document its compatible string. Signed-off-by: Yao Zi Acked-by: Conor Dooley Reviewed-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250728102947.38984-5-ziyao@disroot.org Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml index db293d2fbf1a..379b08bd9e97 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml @@ -12,6 +12,7 @@ maintainers: properties: compatible: enum: + - rockchip,rk3528-naneng-combphy - rockchip,rk3562-naneng-combphy - rockchip,rk3568-naneng-combphy - rockchip,rk3576-naneng-combphy @@ -108,7 +109,9 @@ allOf: properties: compatible: contains: - const: rockchip,rk3588-naneng-combphy + enum: + - rockchip,rk3528-naneng-combphy + - rockchip,rk3588-naneng-combphy then: properties: resets: From b3bbc6afcff50e2fd4d51dd64929e62d66fdc814 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 28 Jul 2025 10:29:46 +0000 Subject: [PATCH 10/64] phy: rockchip: naneng-combphy: Add SoC prefix to register definitions All supported variants of naneng-combphy follow a register layout similar to the RK3568 variant with some exceptions of SoC-specific registers. Add RK3568 prefix for the common set of registers and the corresponding SoC prefix for SoC-specific registers, making usage of definitions clear and preparing for future COMBPHY variants with a different register layout. Signed-off-by: Yao Zi Reviewed-by: Heiko Stuebner Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250728102947.38984-6-ziyao@disroot.org Signed-off-by: Vinod Koul --- .../rockchip/phy-rockchip-naneng-combphy.c | 522 +++++++++--------- 1 file changed, 269 insertions(+), 253 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index 17c6310f4b54..ce84166cd772 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -21,78 +21,80 @@ #define REF_CLOCK_100MHz (100 * HZ_PER_MHZ) /* COMBO PHY REG */ -#define PHYREG6 0x14 -#define PHYREG6_PLL_DIV_MASK GENMASK(7, 6) -#define PHYREG6_PLL_DIV_SHIFT 6 -#define PHYREG6_PLL_DIV_2 1 +#define RK3568_PHYREG6 0x14 +#define RK3568_PHYREG6_PLL_DIV_MASK GENMASK(7, 6) +#define RK3568_PHYREG6_PLL_DIV_SHIFT 6 +#define RK3568_PHYREG6_PLL_DIV_2 1 -#define PHYREG7 0x18 -#define PHYREG7_TX_RTERM_MASK GENMASK(7, 4) -#define PHYREG7_TX_RTERM_SHIFT 4 -#define PHYREG7_TX_RTERM_50OHM 8 -#define PHYREG7_RX_RTERM_MASK GENMASK(3, 0) -#define PHYREG7_RX_RTERM_SHIFT 0 -#define PHYREG7_RX_RTERM_44OHM 15 +#define RK3568_PHYREG7 0x18 +#define RK3568_PHYREG7_TX_RTERM_MASK GENMASK(7, 4) +#define RK3568_PHYREG7_TX_RTERM_SHIFT 4 +#define RK3568_PHYREG7_TX_RTERM_50OHM 8 +#define RK3568_PHYREG7_RX_RTERM_MASK GENMASK(3, 0) +#define RK3568_PHYREG7_RX_RTERM_SHIFT 0 +#define RK3568_PHYREG7_RX_RTERM_44OHM 15 -#define PHYREG8 0x1C -#define PHYREG8_SSC_EN BIT(4) +#define RK3568_PHYREG8 0x1C +#define RK3568_PHYREG8_SSC_EN BIT(4) -#define PHYREG10 0x24 -#define PHYREG10_SSC_PCM_MASK GENMASK(3, 0) -#define PHYREG10_SSC_PCM_3500PPM 7 +#define RK3568_PHYREG11 0x28 +#define RK3568_PHYREG11_SU_TRIM_0_7 0xF0 -#define PHYREG11 0x28 -#define PHYREG11_SU_TRIM_0_7 0xF0 +#define RK3568_PHYREG12 0x2C +#define RK3568_PHYREG12_PLL_LPF_ADJ_VALUE 4 -#define PHYREG12 0x2C -#define PHYREG12_PLL_LPF_ADJ_VALUE 4 +#define RK3568_PHYREG13 0x30 +#define RK3568_PHYREG13_RESISTER_MASK GENMASK(5, 4) +#define RK3568_PHYREG13_RESISTER_SHIFT 0x4 +#define RK3568_PHYREG13_RESISTER_HIGH_Z 3 +#define RK3568_PHYREG13_CKRCV_AMP0 BIT(7) -#define PHYREG13 0x30 -#define PHYREG13_RESISTER_MASK GENMASK(5, 4) -#define PHYREG13_RESISTER_SHIFT 0x4 -#define PHYREG13_RESISTER_HIGH_Z 3 -#define PHYREG13_CKRCV_AMP0 BIT(7) +#define RK3568_PHYREG14 0x34 +#define RK3568_PHYREG14_CKRCV_AMP1 BIT(0) -#define PHYREG14 0x34 -#define PHYREG14_CKRCV_AMP1 BIT(0) +#define RK3568_PHYREG15 0x38 +#define RK3568_PHYREG15_CTLE_EN BIT(0) +#define RK3568_PHYREG15_SSC_CNT_MASK GENMASK(7, 6) +#define RK3568_PHYREG15_SSC_CNT_SHIFT 6 +#define RK3568_PHYREG15_SSC_CNT_VALUE 1 -#define PHYREG15 0x38 -#define PHYREG15_CTLE_EN BIT(0) -#define PHYREG15_SSC_CNT_MASK GENMASK(7, 6) -#define PHYREG15_SSC_CNT_SHIFT 6 -#define PHYREG15_SSC_CNT_VALUE 1 +#define RK3568_PHYREG16 0x3C +#define RK3568_PHYREG16_SSC_CNT_VALUE 0x5f -#define PHYREG16 0x3C -#define PHYREG16_SSC_CNT_VALUE 0x5f +#define RK3568_PHYREG18 0x44 +#define RK3568_PHYREG18_PLL_LOOP 0x32 -#define PHYREG17 0x40 +#define RK3568_PHYREG32 0x7C +#define RK3568_PHYREG32_SSC_MASK GENMASK(7, 4) +#define RK3568_PHYREG32_SSC_DIR_MASK GENMASK(5, 4) +#define RK3568_PHYREG32_SSC_DIR_SHIFT 4 +#define RK3568_PHYREG32_SSC_UPWARD 0 +#define RK3568_PHYREG32_SSC_DOWNWARD 1 +#define RK3568_PHYREG32_SSC_OFFSET_MASK GENMASK(7, 6) +#define RK3568_PHYREG32_SSC_OFFSET_SHIFT 6 +#define RK3568_PHYREG32_SSC_OFFSET_500PPM 1 -#define PHYREG18 0x44 -#define PHYREG18_PLL_LOOP 0x32 +#define RK3568_PHYREG33 0x80 +#define RK3568_PHYREG33_PLL_KVCO_MASK GENMASK(4, 2) +#define RK3568_PHYREG33_PLL_KVCO_SHIFT 2 +#define RK3568_PHYREG33_PLL_KVCO_VALUE 2 +#define RK3576_PHYREG33_PLL_KVCO_VALUE 4 -#define PHYREG21 0x50 -#define PHYREG21_RX_SQUELCH_VAL 0x0D +/* RK3588 COMBO PHY registers */ +#define RK3588_PHYREG27 0x6C +#define RK3588_PHYREG27_RX_TRIM 0x4C -#define PHYREG27 0x6C -#define PHYREG27_RX_TRIM_RK3588 0x4C +/* RK3576 COMBO PHY registers */ +#define RK3576_PHYREG10 0x24 +#define RK3576_PHYREG10_SSC_PCM_MASK GENMASK(3, 0) +#define RK3576_PHYREG10_SSC_PCM_3500PPM 7 -#define PHYREG30 0x74 +#define RK3576_PHYREG17 0x40 -#define PHYREG32 0x7C -#define PHYREG32_SSC_MASK GENMASK(7, 4) -#define PHYREG32_SSC_DIR_MASK GENMASK(5, 4) -#define PHYREG32_SSC_DIR_SHIFT 4 -#define PHYREG32_SSC_UPWARD 0 -#define PHYREG32_SSC_DOWNWARD 1 -#define PHYREG32_SSC_OFFSET_MASK GENMASK(7, 6) -#define PHYREG32_SSC_OFFSET_SHIFT 6 -#define PHYREG32_SSC_OFFSET_500PPM 1 +#define RK3576_PHYREG21 0x50 +#define RK3576_PHYREG21_RX_SQUELCH_VAL 0x0D -#define PHYREG33 0x80 -#define PHYREG33_PLL_KVCO_MASK GENMASK(4, 2) -#define PHYREG33_PLL_KVCO_SHIFT 2 -#define PHYREG33_PLL_KVCO_VALUE 2 -#define PHYREG33_PLL_KVCO_VALUE_RK3576 4 +#define RK3576_PHYREG30 0x74 struct rockchip_combphy_priv; @@ -407,9 +409,8 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) switch (priv->type) { case PHY_TYPE_PCIE: /* Set SSC downward spread spectrum */ - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, - PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, - PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, RK3568_PHYREG32); rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true); @@ -418,29 +419,30 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) break; case PHY_TYPE_USB3: /* Set SSC downward spread spectrum */ - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, - PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, - PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, + RK3568_PHYREG32); /* Enable adaptive CTLE for USB3.0 Rx */ - rockchip_combphy_updatel(priv, PHYREG15_CTLE_EN, - PHYREG15_CTLE_EN, PHYREG15); + rockchip_combphy_updatel(priv, RK3568_PHYREG15_CTLE_EN, + RK3568_PHYREG15_CTLE_EN, RK3568_PHYREG15); /* Set PLL KVCO fine tuning signals */ - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, BIT(3), PHYREG33); + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + BIT(3), RK3568_PHYREG33); /* Set PLL LPF R1 to su_trim[10:7]=1001 */ - writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + writel(RK3568_PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + RK3568_PHYREG12); /* Set PLL input clock divider 1/2 */ - val = FIELD_PREP(PHYREG6_PLL_DIV_MASK, PHYREG6_PLL_DIV_2); - rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, val, PHYREG6); + val = FIELD_PREP(RK3568_PHYREG6_PLL_DIV_MASK, RK3568_PHYREG6_PLL_DIV_2); + rockchip_combphy_updatel(priv, RK3568_PHYREG6_PLL_DIV_MASK, val, RK3568_PHYREG6); /* Set PLL loop divider */ - writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18); + writel(RK3568_PHYREG18_PLL_LOOP, priv->mmio + RK3568_PHYREG18); /* Set PLL KVCO to min and set PLL charge pump current to max */ - writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + writel(RK3568_PHYREG11_SU_TRIM_0_7, priv->mmio + RK3568_PHYREG11); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_sel_usb, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false); @@ -458,11 +460,12 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) case REF_CLOCK_24MHz: if (priv->type == PHY_TYPE_USB3) { /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz */ - val = FIELD_PREP(PHYREG15_SSC_CNT_MASK, PHYREG15_SSC_CNT_VALUE); - rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK, - val, PHYREG15); + val = FIELD_PREP(RK3568_PHYREG15_SSC_CNT_MASK, + RK3568_PHYREG15_SSC_CNT_VALUE); + rockchip_combphy_updatel(priv, RK3568_PHYREG15_SSC_CNT_MASK, + val, RK3568_PHYREG15); - writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16); + writel(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); } break; case REF_CLOCK_25MHz: @@ -472,19 +475,20 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); if (priv->type == PHY_TYPE_PCIE) { /* PLL KVCO tuning fine */ - val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE); - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - val, PHYREG33); + val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, + RK3568_PHYREG33_PLL_KVCO_VALUE); + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + val, RK3568_PHYREG33); /* Enable controlling random jitter, aka RMJ */ - writel(0x4, priv->mmio + PHYREG12); + writel(0x4, priv->mmio + RK3568_PHYREG12); - val = PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT; - rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, - val, PHYREG6); + val = RK3568_PHYREG6_PLL_DIV_2 << RK3568_PHYREG6_PLL_DIV_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG6_PLL_DIV_MASK, + val, RK3568_PHYREG6); - writel(0x32, priv->mmio + PHYREG18); - writel(0xf0, priv->mmio + PHYREG11); + writel(0x32, priv->mmio + RK3568_PHYREG18); + writel(0xf0, priv->mmio + RK3568_PHYREG11); } break; default: @@ -495,20 +499,21 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) if (priv->ext_refclk) { rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true); if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) { - val = PHYREG13_RESISTER_HIGH_Z << PHYREG13_RESISTER_SHIFT; - val |= PHYREG13_CKRCV_AMP0; - rockchip_combphy_updatel(priv, PHYREG13_RESISTER_MASK, val, PHYREG13); + val = RK3568_PHYREG13_RESISTER_HIGH_Z << RK3568_PHYREG13_RESISTER_SHIFT; + val |= RK3568_PHYREG13_CKRCV_AMP0; + rockchip_combphy_updatel(priv, RK3568_PHYREG13_RESISTER_MASK, val, + RK3568_PHYREG13); - val = readl(priv->mmio + PHYREG14); - val |= PHYREG14_CKRCV_AMP1; - writel(val, priv->mmio + PHYREG14); + val = readl(priv->mmio + RK3568_PHYREG14); + val |= RK3568_PHYREG14_CKRCV_AMP1; + writel(val, priv->mmio + RK3568_PHYREG14); } } if (priv->enable_ssc) { - val = readl(priv->mmio + PHYREG8); - val |= PHYREG8_SSC_EN; - writel(val, priv->mmio + PHYREG8); + val = readl(priv->mmio + RK3568_PHYREG8); + val |= RK3568_PHYREG8_SSC_EN; + writel(val, priv->mmio + RK3568_PHYREG8); } return 0; @@ -555,9 +560,9 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) switch (priv->type) { case PHY_TYPE_PCIE: /* Set SSC downward spread spectrum. */ - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, - PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, - PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT; + + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, RK3568_PHYREG32); rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true); @@ -567,30 +572,28 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) case PHY_TYPE_USB3: /* Set SSC downward spread spectrum. */ - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, - PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, - PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT, + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, RK3568_PHYREG32); /* Enable adaptive CTLE for USB3.0 Rx. */ - val = readl(priv->mmio + PHYREG15); - val |= PHYREG15_CTLE_EN; - writel(val, priv->mmio + PHYREG15); + val = readl(priv->mmio + RK3568_PHYREG15); + val |= RK3568_PHYREG15_CTLE_EN; + writel(val, priv->mmio + RK3568_PHYREG15); /* Set PLL KVCO fine tuning signals. */ - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - PHYREG33_PLL_KVCO_VALUE << PHYREG33_PLL_KVCO_SHIFT, - PHYREG33); + val = RK3568_PHYREG33_PLL_KVCO_VALUE << RK3568_PHYREG33_PLL_KVCO_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, val, RK3568_PHYREG33); /* Enable controlling random jitter. */ - writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + writel(RK3568_PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + RK3568_PHYREG12); /* Set PLL input clock divider 1/2. */ - rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, - PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT, - PHYREG6); + rockchip_combphy_updatel(priv, RK3568_PHYREG6_PLL_DIV_MASK, + RK3568_PHYREG6_PLL_DIV_2 << RK3568_PHYREG6_PLL_DIV_SHIFT, + RK3568_PHYREG6); - writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18); - writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + writel(RK3568_PHYREG18_PLL_LOOP, priv->mmio + RK3568_PHYREG18); + writel(RK3568_PHYREG11_SU_TRIM_0_7, priv->mmio + RK3568_PHYREG11); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_sel_usb, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false); @@ -608,16 +611,16 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) case PHY_TYPE_SATA: /* Enable adaptive CTLE for SATA Rx. */ - val = readl(priv->mmio + PHYREG15); - val |= PHYREG15_CTLE_EN; - writel(val, priv->mmio + PHYREG15); + val = readl(priv->mmio + RK3568_PHYREG15); + val |= RK3568_PHYREG15_CTLE_EN; + writel(val, priv->mmio + RK3568_PHYREG15); /* * Set tx_rterm=50ohm and rx_rterm=44ohm for SATA. * 0: 60ohm, 8: 50ohm 15: 44ohm (by step abort 1ohm) */ - val = PHYREG7_TX_RTERM_50OHM << PHYREG7_TX_RTERM_SHIFT; - val |= PHYREG7_RX_RTERM_44OHM << PHYREG7_RX_RTERM_SHIFT; - writel(val, priv->mmio + PHYREG7); + val = RK3568_PHYREG7_TX_RTERM_50OHM << RK3568_PHYREG7_TX_RTERM_SHIFT; + val |= RK3568_PHYREG7_RX_RTERM_44OHM << RK3568_PHYREG7_RX_RTERM_SHIFT; + writel(val, priv->mmio + RK3568_PHYREG7); rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_sata, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_sata, true); @@ -652,11 +655,11 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) case REF_CLOCK_24MHz: if (priv->type == PHY_TYPE_USB3 || priv->type == PHY_TYPE_SATA) { /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz. */ - val = PHYREG15_SSC_CNT_VALUE << PHYREG15_SSC_CNT_SHIFT; - rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK, - val, PHYREG15); + val = RK3568_PHYREG15_SSC_CNT_VALUE << RK3568_PHYREG15_SSC_CNT_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG15_SSC_CNT_MASK, + val, RK3568_PHYREG15); - writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16); + writel(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); } break; @@ -668,24 +671,26 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); if (priv->type == PHY_TYPE_PCIE) { /* PLL KVCO fine tuning. */ - val = PHYREG33_PLL_KVCO_VALUE << PHYREG33_PLL_KVCO_SHIFT; - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - val, PHYREG33); + val = RK3568_PHYREG33_PLL_KVCO_VALUE << RK3568_PHYREG33_PLL_KVCO_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + val, RK3568_PHYREG33); /* Enable controlling random jitter. */ - writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + writel(RK3568_PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + RK3568_PHYREG12); - val = PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT; - rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, - val, PHYREG6); + val = RK3568_PHYREG6_PLL_DIV_2 << RK3568_PHYREG6_PLL_DIV_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG6_PLL_DIV_MASK, + val, RK3568_PHYREG6); - writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18); - writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + writel(RK3568_PHYREG18_PLL_LOOP, priv->mmio + RK3568_PHYREG18); + writel(RK3568_PHYREG11_SU_TRIM_0_7, priv->mmio + RK3568_PHYREG11); } else if (priv->type == PHY_TYPE_SATA) { /* downward spread spectrum +500ppm */ - val = PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT; - val |= PHYREG32_SSC_OFFSET_500PPM << PHYREG32_SSC_OFFSET_SHIFT; - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT; + val |= RK3568_PHYREG32_SSC_OFFSET_500PPM << + RK3568_PHYREG32_SSC_OFFSET_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, + RK3568_PHYREG32); } break; @@ -697,20 +702,21 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) if (priv->ext_refclk) { rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true); if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) { - val = PHYREG13_RESISTER_HIGH_Z << PHYREG13_RESISTER_SHIFT; - val |= PHYREG13_CKRCV_AMP0; - rockchip_combphy_updatel(priv, PHYREG13_RESISTER_MASK, val, PHYREG13); + val = RK3568_PHYREG13_RESISTER_HIGH_Z << RK3568_PHYREG13_RESISTER_SHIFT; + val |= RK3568_PHYREG13_CKRCV_AMP0; + rockchip_combphy_updatel(priv, RK3568_PHYREG13_RESISTER_MASK, val, + RK3568_PHYREG13); - val = readl(priv->mmio + PHYREG14); - val |= PHYREG14_CKRCV_AMP1; - writel(val, priv->mmio + PHYREG14); + val = readl(priv->mmio + RK3568_PHYREG14); + val |= RK3568_PHYREG14_CKRCV_AMP1; + writel(val, priv->mmio + RK3568_PHYREG14); } } if (priv->enable_ssc) { - val = readl(priv->mmio + PHYREG8); - val |= PHYREG8_SSC_EN; - writel(val, priv->mmio + PHYREG8); + val = readl(priv->mmio + RK3568_PHYREG8); + val |= RK3568_PHYREG8_SSC_EN; + writel(val, priv->mmio + RK3568_PHYREG8); } return 0; @@ -771,8 +777,8 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) switch (priv->type) { case PHY_TYPE_PCIE: /* Set SSC downward spread spectrum */ - val = FIELD_PREP(PHYREG32_SSC_MASK, PHYREG32_SSC_DOWNWARD); - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32); + val = FIELD_PREP(RK3568_PHYREG32_SSC_MASK, RK3568_PHYREG32_SSC_DOWNWARD); + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, RK3568_PHYREG32); rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true); @@ -782,32 +788,33 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) case PHY_TYPE_USB3: /* Set SSC downward spread spectrum */ - val = FIELD_PREP(PHYREG32_SSC_MASK, PHYREG32_SSC_DOWNWARD); - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32); + val = FIELD_PREP(RK3568_PHYREG32_SSC_MASK, RK3568_PHYREG32_SSC_DOWNWARD); + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, RK3568_PHYREG32); /* Enable adaptive CTLE for USB3.0 Rx */ - val = readl(priv->mmio + PHYREG15); - val |= PHYREG15_CTLE_EN; - writel(val, priv->mmio + PHYREG15); + val = readl(priv->mmio + RK3568_PHYREG15); + val |= RK3568_PHYREG15_CTLE_EN; + writel(val, priv->mmio + RK3568_PHYREG15); /* Set PLL KVCO fine tuning signals */ - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, BIT(3), PHYREG33); + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, BIT(3), + RK3568_PHYREG33); /* Set PLL LPF R1 to su_trim[10:7]=1001 */ - writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + writel(RK3568_PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + RK3568_PHYREG12); /* Set PLL input clock divider 1/2 */ - val = FIELD_PREP(PHYREG6_PLL_DIV_MASK, PHYREG6_PLL_DIV_2); - rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, val, PHYREG6); + val = FIELD_PREP(RK3568_PHYREG6_PLL_DIV_MASK, RK3568_PHYREG6_PLL_DIV_2); + rockchip_combphy_updatel(priv, RK3568_PHYREG6_PLL_DIV_MASK, val, RK3568_PHYREG6); /* Set PLL loop divider */ - writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18); + writel(RK3568_PHYREG18_PLL_LOOP, priv->mmio + RK3568_PHYREG18); /* Set PLL KVCO to min and set PLL charge pump current to max */ - writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + writel(RK3568_PHYREG11_SU_TRIM_0_7, priv->mmio + RK3568_PHYREG11); /* Set Rx squelch input filler bandwidth */ - writel(PHYREG21_RX_SQUELCH_VAL, priv->mmio + PHYREG21); + writel(RK3576_PHYREG21_RX_SQUELCH_VAL, priv->mmio + RK3576_PHYREG21); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false); @@ -816,14 +823,14 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) case PHY_TYPE_SATA: /* Enable adaptive CTLE for SATA Rx */ - val = readl(priv->mmio + PHYREG15); - val |= PHYREG15_CTLE_EN; - writel(val, priv->mmio + PHYREG15); + val = readl(priv->mmio + RK3568_PHYREG15); + val |= RK3568_PHYREG15_CTLE_EN; + writel(val, priv->mmio + RK3568_PHYREG15); /* Set tx_rterm = 50 ohm and rx_rterm = 43.5 ohm */ - val = PHYREG7_TX_RTERM_50OHM << PHYREG7_TX_RTERM_SHIFT; - val |= PHYREG7_RX_RTERM_44OHM << PHYREG7_RX_RTERM_SHIFT; - writel(val, priv->mmio + PHYREG7); + val = RK3568_PHYREG7_TX_RTERM_50OHM << RK3568_PHYREG7_TX_RTERM_SHIFT; + val |= RK3568_PHYREG7_RX_RTERM_44OHM << RK3568_PHYREG7_RX_RTERM_SHIFT; + writel(val, priv->mmio + RK3568_PHYREG7); rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_sata, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_sata, true); @@ -845,19 +852,21 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_24m, true); if (priv->type == PHY_TYPE_USB3 || priv->type == PHY_TYPE_SATA) { /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz */ - val = FIELD_PREP(PHYREG15_SSC_CNT_MASK, PHYREG15_SSC_CNT_VALUE); - rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK, - val, PHYREG15); + val = FIELD_PREP(RK3568_PHYREG15_SSC_CNT_MASK, + RK3568_PHYREG15_SSC_CNT_VALUE); + rockchip_combphy_updatel(priv, RK3568_PHYREG15_SSC_CNT_MASK, + val, RK3568_PHYREG15); - writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16); + writel(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); } else if (priv->type == PHY_TYPE_PCIE) { /* PLL KVCO tuning fine */ - val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576); - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - val, PHYREG33); + val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, + RK3576_PHYREG33_PLL_KVCO_VALUE); + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + val, RK3568_PHYREG33); /* Set up rx_pck invert and rx msb to disable */ - writel(0x00, priv->mmio + PHYREG27); + writel(0x00, priv->mmio + RK3588_PHYREG27); /* * Set up SU adjust signal: @@ -865,11 +874,11 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) * su_trim[15:8], PLL LPF R1 adujst bits[9:7]=3'b011 * su_trim[31:24], CKDRV adjust */ - writel(0x90, priv->mmio + PHYREG11); - writel(0x02, priv->mmio + PHYREG12); - writel(0x57, priv->mmio + PHYREG14); + writel(0x90, priv->mmio + RK3568_PHYREG11); + writel(0x02, priv->mmio + RK3568_PHYREG12); + writel(0x57, priv->mmio + RK3568_PHYREG14); - writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16); + writel(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); } break; @@ -881,15 +890,16 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); if (priv->type == PHY_TYPE_PCIE) { /* gate_tx_pck_sel length select work for L1SS */ - writel(0xc0, priv->mmio + PHYREG30); + writel(0xc0, priv->mmio + RK3576_PHYREG30); /* PLL KVCO tuning fine */ - val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576); - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - val, PHYREG33); + val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, + RK3576_PHYREG33_PLL_KVCO_VALUE); + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + val, RK3568_PHYREG33); /* Set up rx_trim: PLL LPF C1 85pf R1 1.25kohm */ - writel(0x4c, priv->mmio + PHYREG27); + writel(0x4c, priv->mmio + RK3588_PHYREG27); /* * Set up SU adjust signal: @@ -899,20 +909,23 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) * su_trim[23:16], CKRCV adjust * su_trim[31:24], CKDRV adjust */ - writel(0x90, priv->mmio + PHYREG11); - writel(0x43, priv->mmio + PHYREG12); - writel(0x88, priv->mmio + PHYREG13); - writel(0x56, priv->mmio + PHYREG14); + writel(0x90, priv->mmio + RK3568_PHYREG11); + writel(0x43, priv->mmio + RK3568_PHYREG12); + writel(0x88, priv->mmio + RK3568_PHYREG13); + writel(0x56, priv->mmio + RK3568_PHYREG14); } else if (priv->type == PHY_TYPE_SATA) { /* downward spread spectrum +500ppm */ - val = FIELD_PREP(PHYREG32_SSC_DIR_MASK, PHYREG32_SSC_DOWNWARD); - val |= FIELD_PREP(PHYREG32_SSC_OFFSET_MASK, PHYREG32_SSC_OFFSET_500PPM); - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32); + val = FIELD_PREP(RK3568_PHYREG32_SSC_DIR_MASK, + RK3568_PHYREG32_SSC_DOWNWARD); + val |= FIELD_PREP(RK3568_PHYREG32_SSC_OFFSET_MASK, + RK3568_PHYREG32_SSC_OFFSET_500PPM); + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, + RK3568_PHYREG32); /* ssc ppm adjust to 3500ppm */ - rockchip_combphy_updatel(priv, PHYREG10_SSC_PCM_MASK, - PHYREG10_SSC_PCM_3500PPM, - PHYREG10); + rockchip_combphy_updatel(priv, RK3576_PHYREG10_SSC_PCM_MASK, + RK3576_PHYREG10_SSC_PCM_3500PPM, + RK3576_PHYREG10); } break; @@ -924,12 +937,13 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) if (priv->ext_refclk) { rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true); if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) { - val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576); - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - val, PHYREG33); + val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, + RK3576_PHYREG33_PLL_KVCO_VALUE); + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + val, RK3568_PHYREG33); /* Set up rx_trim: PLL LPF C1 85pf R1 2.5kohm */ - writel(0x0c, priv->mmio + PHYREG27); + writel(0x0c, priv->mmio + RK3588_PHYREG27); /* * Set up SU adjust signal: @@ -939,25 +953,25 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) * su_trim[23:16], CKRCV adjust * su_trim[31:24], CKDRV adjust */ - writel(0x90, priv->mmio + PHYREG11); - writel(0x43, priv->mmio + PHYREG12); - writel(0x88, priv->mmio + PHYREG13); - writel(0x56, priv->mmio + PHYREG14); + writel(0x90, priv->mmio + RK3568_PHYREG11); + writel(0x43, priv->mmio + RK3568_PHYREG12); + writel(0x88, priv->mmio + RK3568_PHYREG13); + writel(0x56, priv->mmio + RK3568_PHYREG14); } } if (priv->enable_ssc) { - val = readl(priv->mmio + PHYREG8); - val |= PHYREG8_SSC_EN; - writel(val, priv->mmio + PHYREG8); + val = readl(priv->mmio + RK3568_PHYREG8); + val |= RK3568_PHYREG8_SSC_EN; + writel(val, priv->mmio + RK3568_PHYREG8); if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_24MHz) { /* Set PLL loop divider */ - writel(0x00, priv->mmio + PHYREG17); - writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18); + writel(0x00, priv->mmio + RK3576_PHYREG17); + writel(RK3568_PHYREG18_PLL_LOOP, priv->mmio + RK3568_PHYREG18); /* Set up rx_pck invert and rx msb to disable */ - writel(0x00, priv->mmio + PHYREG27); + writel(0x00, priv->mmio + RK3588_PHYREG27); /* * Set up SU adjust signal: @@ -966,16 +980,17 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) * su_trim[23:16], CKRCV adjust * su_trim[31:24], CKDRV adjust */ - writel(0x90, priv->mmio + PHYREG11); - writel(0x02, priv->mmio + PHYREG12); - writel(0x08, priv->mmio + PHYREG13); - writel(0x57, priv->mmio + PHYREG14); - writel(0x40, priv->mmio + PHYREG15); + writel(0x90, priv->mmio + RK3568_PHYREG11); + writel(0x02, priv->mmio + RK3568_PHYREG12); + writel(0x08, priv->mmio + RK3568_PHYREG13); + writel(0x57, priv->mmio + RK3568_PHYREG14); + writel(0x40, priv->mmio + RK3568_PHYREG15); - writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16); + writel(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); - val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576); - writel(val, priv->mmio + PHYREG33); + val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, + RK3576_PHYREG33_PLL_KVCO_VALUE); + writel(val, priv->mmio + RK3568_PHYREG33); } } @@ -1045,30 +1060,28 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) break; case PHY_TYPE_USB3: /* Set SSC downward spread spectrum */ - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, - PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, - PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, RK3568_PHYREG32); /* Enable adaptive CTLE for USB3.0 Rx. */ - val = readl(priv->mmio + PHYREG15); - val |= PHYREG15_CTLE_EN; - writel(val, priv->mmio + PHYREG15); + val = readl(priv->mmio + RK3568_PHYREG15); + val |= RK3568_PHYREG15_CTLE_EN; + writel(val, priv->mmio + RK3568_PHYREG15); /* Set PLL KVCO fine tuning signals. */ - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - PHYREG33_PLL_KVCO_VALUE << PHYREG33_PLL_KVCO_SHIFT, - PHYREG33); + val = RK3568_PHYREG33_PLL_KVCO_VALUE << RK3568_PHYREG33_PLL_KVCO_SHIFT, + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, val, RK3568_PHYREG33); /* Enable controlling random jitter. */ - writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + writel(RK3568_PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + RK3568_PHYREG12); /* Set PLL input clock divider 1/2. */ - rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, - PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT, - PHYREG6); + rockchip_combphy_updatel(priv, RK3568_PHYREG6_PLL_DIV_MASK, + RK3568_PHYREG6_PLL_DIV_2 << RK3568_PHYREG6_PLL_DIV_SHIFT, + RK3568_PHYREG6); - writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18); - writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + writel(RK3568_PHYREG18_PLL_LOOP, priv->mmio + RK3568_PHYREG18); + writel(RK3568_PHYREG11_SU_TRIM_0_7, priv->mmio + RK3568_PHYREG11); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false); @@ -1076,16 +1089,16 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) break; case PHY_TYPE_SATA: /* Enable adaptive CTLE for SATA Rx. */ - val = readl(priv->mmio + PHYREG15); - val |= PHYREG15_CTLE_EN; - writel(val, priv->mmio + PHYREG15); + val = readl(priv->mmio + RK3568_PHYREG15); + val |= RK3568_PHYREG15_CTLE_EN; + writel(val, priv->mmio + RK3568_PHYREG15); /* * Set tx_rterm=50ohm and rx_rterm=44ohm for SATA. * 0: 60ohm, 8: 50ohm 15: 44ohm (by step abort 1ohm) */ - val = PHYREG7_TX_RTERM_50OHM << PHYREG7_TX_RTERM_SHIFT; - val |= PHYREG7_RX_RTERM_44OHM << PHYREG7_RX_RTERM_SHIFT; - writel(val, priv->mmio + PHYREG7); + val = RK3568_PHYREG7_TX_RTERM_50OHM << RK3568_PHYREG7_TX_RTERM_SHIFT; + val |= RK3568_PHYREG7_RX_RTERM_44OHM << RK3568_PHYREG7_RX_RTERM_SHIFT; + writel(val, priv->mmio + RK3568_PHYREG7); rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_sata, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_sata, true); @@ -1107,11 +1120,11 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) case REF_CLOCK_24MHz: if (priv->type == PHY_TYPE_USB3 || priv->type == PHY_TYPE_SATA) { /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz. */ - val = PHYREG15_SSC_CNT_VALUE << PHYREG15_SSC_CNT_SHIFT; - rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK, - val, PHYREG15); + val = RK3568_PHYREG15_SSC_CNT_VALUE << RK3568_PHYREG15_SSC_CNT_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG15_SSC_CNT_MASK, + val, RK3568_PHYREG15); - writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16); + writel(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); } break; @@ -1122,23 +1135,25 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); if (priv->type == PHY_TYPE_PCIE) { /* PLL KVCO fine tuning. */ - val = 4 << PHYREG33_PLL_KVCO_SHIFT; - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - val, PHYREG33); + val = 4 << RK3568_PHYREG33_PLL_KVCO_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + val, RK3568_PHYREG33); /* Enable controlling random jitter. */ - writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + writel(RK3568_PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + RK3568_PHYREG12); /* Set up rx_trim: PLL LPF C1 85pf R1 1.25kohm */ - writel(PHYREG27_RX_TRIM_RK3588, priv->mmio + PHYREG27); + writel(RK3588_PHYREG27_RX_TRIM, priv->mmio + RK3588_PHYREG27); /* Set up su_trim: */ - writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + writel(RK3568_PHYREG11_SU_TRIM_0_7, priv->mmio + RK3568_PHYREG11); } else if (priv->type == PHY_TYPE_SATA) { /* downward spread spectrum +500ppm */ - val = PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT; - val |= PHYREG32_SSC_OFFSET_500PPM << PHYREG32_SSC_OFFSET_SHIFT; - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT; + val |= RK3568_PHYREG32_SSC_OFFSET_500PPM << + RK3568_PHYREG32_SSC_OFFSET_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, + RK3568_PHYREG32); } break; default: @@ -1149,20 +1164,21 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) if (priv->ext_refclk) { rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true); if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) { - val = PHYREG13_RESISTER_HIGH_Z << PHYREG13_RESISTER_SHIFT; - val |= PHYREG13_CKRCV_AMP0; - rockchip_combphy_updatel(priv, PHYREG13_RESISTER_MASK, val, PHYREG13); + val = RK3568_PHYREG13_RESISTER_HIGH_Z << RK3568_PHYREG13_RESISTER_SHIFT; + val |= RK3568_PHYREG13_CKRCV_AMP0; + rockchip_combphy_updatel(priv, RK3568_PHYREG13_RESISTER_MASK, val, + RK3568_PHYREG13); - val = readl(priv->mmio + PHYREG14); - val |= PHYREG14_CKRCV_AMP1; - writel(val, priv->mmio + PHYREG14); + val = readl(priv->mmio + RK3568_PHYREG14); + val |= RK3568_PHYREG14_CKRCV_AMP1; + writel(val, priv->mmio + RK3568_PHYREG14); } } if (priv->enable_ssc) { - val = readl(priv->mmio + PHYREG8); - val |= PHYREG8_SSC_EN; - writel(val, priv->mmio + PHYREG8); + val = readl(priv->mmio + RK3568_PHYREG8); + val |= RK3568_PHYREG8_SSC_EN; + writel(val, priv->mmio + RK3568_PHYREG8); } return 0; From bbcca4fac873c66388c687eeecd9ca6b12b601b7 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 28 Jul 2025 10:29:47 +0000 Subject: [PATCH 11/64] phy: rockchip: naneng-combphy: Add RK3528 support Rockchip RK3528 integrates one naneng-combphy that is able to operate in PCIe and USB3 mode. The control logic is similar to previous variants of naneng-combphy but the register layout is apparently different from the RK3568 one. Signed-off-by: Yao Zi Reviewed-by: Heiko Stuebner Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250728102947.38984-7-ziyao@disroot.org Signed-off-by: Vinod Koul --- .../rockchip/phy-rockchip-naneng-combphy.c | 189 +++++++++++++++++- 1 file changed, 188 insertions(+), 1 deletion(-) diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index ce84166cd772..0d25872e6712 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -20,7 +20,46 @@ #define REF_CLOCK_25MHz (25 * HZ_PER_MHZ) #define REF_CLOCK_100MHz (100 * HZ_PER_MHZ) -/* COMBO PHY REG */ +/* RK3528 COMBO PHY REG */ +#define RK3528_PHYREG6 0x18 +#define RK3528_PHYREG6_PLL_KVCO GENMASK(12, 10) +#define RK3528_PHYREG6_PLL_KVCO_VALUE 0x2 +#define RK3528_PHYREG6_SSC_DIR GENMASK(5, 4) +#define RK3528_PHYREG6_SSC_UPWARD 0 +#define RK3528_PHYREG6_SSC_DOWNWARD 1 + +#define RK3528_PHYREG40 0x100 +#define RK3528_PHYREG40_SSC_EN BIT(20) +#define RK3528_PHYREG40_SSC_CNT GENMASK(10, 0) +#define RK3528_PHYREG40_SSC_CNT_VALUE 0x17d + +#define RK3528_PHYREG42 0x108 +#define RK3528_PHYREG42_CKDRV_CLK_SEL BIT(29) +#define RK3528_PHYREG42_CKDRV_CLK_PLL 0 +#define RK3528_PHYREG42_CKDRV_CLK_CKRCV 1 +#define RK3528_PHYREG42_PLL_LPF_R1_ADJ GENMASK(10, 7) +#define RK3528_PHYREG42_PLL_LPF_R1_ADJ_VALUE 0x9 +#define RK3528_PHYREG42_PLL_CHGPUMP_CUR_ADJ GENMASK(6, 4) +#define RK3528_PHYREG42_PLL_CHGPUMP_CUR_ADJ_VALUE 0x7 +#define RK3528_PHYREG42_PLL_KVCO_ADJ GENMASK(2, 0) +#define RK3528_PHYREG42_PLL_KVCO_ADJ_VALUE 0x0 + +#define RK3528_PHYREG80 0x200 +#define RK3528_PHYREG80_CTLE_EN BIT(17) + +#define RK3528_PHYREG81 0x204 +#define RK3528_PHYREG81_CDR_PHASE_PATH_GAIN_2X BIT(5) +#define RK3528_PHYREG81_SLEW_RATE_CTRL GENMASK(2, 0) +#define RK3528_PHYREG81_SLEW_RATE_CTRL_SLOW 0x7 + +#define RK3528_PHYREG83 0x20c +#define RK3528_PHYREG83_RX_SQUELCH GENMASK(2, 0) +#define RK3528_PHYREG83_RX_SQUELCH_VALUE 0x6 + +#define RK3528_PHYREG86 0x218 +#define RK3528_PHYREG86_RTERM_DET_CLK_EN BIT(14) + +/* RK3568 COMBO PHY REG */ #define RK3568_PHYREG6 0x14 #define RK3568_PHYREG6_PLL_DIV_MASK GENMASK(7, 6) #define RK3568_PHYREG6_PLL_DIV_SHIFT 6 @@ -400,6 +439,150 @@ static int rockchip_combphy_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(phy_provider); } +static int rk3528_combphy_cfg(struct rockchip_combphy_priv *priv) +{ + const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg; + unsigned long rate; + u32 val; + + /* Set SSC downward spread spectrum */ + val = FIELD_PREP(RK3528_PHYREG6_SSC_DIR, RK3528_PHYREG6_SSC_DOWNWARD); + rockchip_combphy_updatel(priv, RK3528_PHYREG6_SSC_DIR, val, RK3528_PHYREG6); + + switch (priv->type) { + case PHY_TYPE_PCIE: + rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true); + rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true); + rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_pcie, true); + rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_pcie, true); + break; + case PHY_TYPE_USB3: + /* Enable adaptive CTLE for USB3.0 Rx */ + rockchip_combphy_updatel(priv, RK3528_PHYREG80_CTLE_EN, RK3528_PHYREG80_CTLE_EN, + RK3528_PHYREG80); + + /* Set slow slew rate control for PI */ + val = FIELD_PREP(RK3528_PHYREG81_SLEW_RATE_CTRL, + RK3528_PHYREG81_SLEW_RATE_CTRL_SLOW); + rockchip_combphy_updatel(priv, RK3528_PHYREG81_SLEW_RATE_CTRL, val, + RK3528_PHYREG81); + + /* Set CDR phase path with 2x gain */ + rockchip_combphy_updatel(priv, RK3528_PHYREG81_CDR_PHASE_PATH_GAIN_2X, + RK3528_PHYREG81_CDR_PHASE_PATH_GAIN_2X, RK3528_PHYREG81); + + /* Set Rx squelch input filler bandwidth */ + val = FIELD_PREP(RK3528_PHYREG83_RX_SQUELCH, RK3528_PHYREG83_RX_SQUELCH_VALUE); + rockchip_combphy_updatel(priv, RK3528_PHYREG83_RX_SQUELCH, val, RK3528_PHYREG83); + + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false); + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false); + rockchip_combphy_param_write(priv->phy_grf, &cfg->usb_mode_set, true); + rockchip_combphy_param_write(priv->pipe_grf, &cfg->u3otg0_port_en, true); + break; + default: + dev_err(priv->dev, "incompatible PHY type\n"); + return -EINVAL; + } + + rate = clk_get_rate(priv->refclk); + + switch (rate) { + case REF_CLOCK_24MHz: + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_24m, true); + if (priv->type == PHY_TYPE_USB3) { + /* Set ssc_cnt[10:0]=00101111101 & 31.5KHz */ + val = FIELD_PREP(RK3528_PHYREG40_SSC_CNT, RK3528_PHYREG40_SSC_CNT_VALUE); + rockchip_combphy_updatel(priv, RK3528_PHYREG40_SSC_CNT, val, + RK3528_PHYREG40); + } else if (priv->type == PHY_TYPE_PCIE) { + /* tx_trim[14]=1, Enable the counting clock of the rterm detect */ + rockchip_combphy_updatel(priv, RK3528_PHYREG86_RTERM_DET_CLK_EN, + RK3528_PHYREG86_RTERM_DET_CLK_EN, RK3528_PHYREG86); + } + break; + case REF_CLOCK_100MHz: + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); + if (priv->type == PHY_TYPE_PCIE) { + /* PLL KVCO tuning fine */ + val = FIELD_PREP(RK3528_PHYREG6_PLL_KVCO, RK3528_PHYREG6_PLL_KVCO_VALUE); + rockchip_combphy_updatel(priv, RK3528_PHYREG6_PLL_KVCO, val, + RK3528_PHYREG6); + + /* su_trim[6:4]=111, [10:7]=1001, [2:0]=000, swing 650mv */ + writel(0x570804f0, priv->mmio + RK3528_PHYREG42); + } + break; + default: + dev_err(priv->dev, "Unsupported rate: %lu\n", rate); + return -EINVAL; + } + + if (device_property_read_bool(priv->dev, "rockchip,ext-refclk")) { + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true); + + if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) { + val = FIELD_PREP(RK3528_PHYREG42_CKDRV_CLK_SEL, + RK3528_PHYREG42_CKDRV_CLK_CKRCV); + val |= FIELD_PREP(RK3528_PHYREG42_PLL_LPF_R1_ADJ, + RK3528_PHYREG42_PLL_LPF_R1_ADJ_VALUE); + val |= FIELD_PREP(RK3528_PHYREG42_PLL_CHGPUMP_CUR_ADJ, + RK3528_PHYREG42_PLL_CHGPUMP_CUR_ADJ_VALUE); + val |= FIELD_PREP(RK3528_PHYREG42_PLL_KVCO_ADJ, + RK3528_PHYREG42_PLL_KVCO_ADJ_VALUE); + rockchip_combphy_updatel(priv, + RK3528_PHYREG42_CKDRV_CLK_SEL | + RK3528_PHYREG42_PLL_LPF_R1_ADJ | + RK3528_PHYREG42_PLL_CHGPUMP_CUR_ADJ | + RK3528_PHYREG42_PLL_KVCO_ADJ, + val, RK3528_PHYREG42); + + val = FIELD_PREP(RK3528_PHYREG6_PLL_KVCO, RK3528_PHYREG6_PLL_KVCO_VALUE); + rockchip_combphy_updatel(priv, RK3528_PHYREG6_PLL_KVCO, val, + RK3528_PHYREG6); + } + } + + if (priv->type == PHY_TYPE_PCIE) { + if (device_property_read_bool(priv->dev, "rockchip,enable-ssc")) + rockchip_combphy_updatel(priv, RK3528_PHYREG40_SSC_EN, + RK3528_PHYREG40_SSC_EN, RK3528_PHYREG40); + } + + return 0; +} + +static const struct rockchip_combphy_grfcfg rk3528_combphy_grfcfgs = { + /* pipe-phy-grf */ + .pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x11 }, + .usb_mode_set = { 0x0000, 5, 0, 0x00, 0x04 }, + .pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x01 }, + .pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x01 }, + .pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x01 }, + .pipe_clk_24m = { 0x0004, 14, 13, 0x00, 0x00 }, + .pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x02 }, + .pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x01 }, + .pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x01 }, + .pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x01 }, + .pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x01 }, + .pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x00 }, + .con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x110 }, + .con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x00 }, + .con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x101 }, + .con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 }, + /* pipe-grf */ + .u3otg0_port_en = { 0x0044, 15, 0, 0x0181, 0x1100 }, +}; + +static const struct rockchip_combphy_cfg rk3528_combphy_cfgs = { + .num_phys = 1, + .phy_ids = { + 0xffdc0000, + }, + .grfcfg = &rk3528_combphy_grfcfgs, + .combphy_cfg = rk3528_combphy_cfg, +}; + static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) { const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg; @@ -1225,6 +1408,10 @@ static const struct rockchip_combphy_cfg rk3588_combphy_cfgs = { }; static const struct of_device_id rockchip_combphy_of_match[] = { + { + .compatible = "rockchip,rk3528-naneng-combphy", + .data = &rk3528_combphy_cfgs, + }, { .compatible = "rockchip,rk3562-naneng-combphy", .data = &rk3562_combphy_cfgs, From 09d1b78cdec9a615d16610b3ba235988eaafec28 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:13 +0200 Subject: [PATCH 12/64] phy: broadcom: brcm-sata: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-2-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/broadcom/phy-brcm-sata.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/broadcom/phy-brcm-sata.c b/drivers/phy/broadcom/phy-brcm-sata.c index d52dd065e862..fb69e21a0292 100644 --- a/drivers/phy/broadcom/phy-brcm-sata.c +++ b/drivers/phy/broadcom/phy-brcm-sata.c @@ -850,4 +850,3 @@ MODULE_DESCRIPTION("Broadcom SATA PHY driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marc Carino"); MODULE_AUTHOR("Brian Norris"); -MODULE_ALIAS("platform:phy-brcm-sata"); From b05d249ecef55bdf9a6da4cd4ec4ba469df5c0ba Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:14 +0200 Subject: [PATCH 13/64] phy: broadcom: brcm-usb: drop unused module alias Since commit 9d5f51dcdb64 ("phy: usb: Add support for new Synopsys USB controller on the 7211b0") the driver only supports OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-3-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/broadcom/phy-brcm-usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c index 0666864c2f77..59d756a10d6c 100644 --- a/drivers/phy/broadcom/phy-brcm-usb.c +++ b/drivers/phy/broadcom/phy-brcm-usb.c @@ -691,7 +691,6 @@ static struct platform_driver brcm_usb_driver = { module_platform_driver(brcm_usb_driver); -MODULE_ALIAS("platform:brcmstb-usb-phy"); MODULE_AUTHOR("Al Cooper "); MODULE_DESCRIPTION("BRCM USB PHY driver"); MODULE_LICENSE("GPL v2"); From 3531c467843812ca87c5349cd4c5b35cdfbd63df Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:15 +0200 Subject: [PATCH 14/64] phy: cadence: Sierra: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-4-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-sierra.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index 74613382ccb0..92ab1a31646a 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -2919,7 +2919,6 @@ static struct platform_driver cdns_sierra_driver = { }; module_platform_driver(cdns_sierra_driver); -MODULE_ALIAS("platform:cdns_sierra"); MODULE_AUTHOR("Cadence Design Systems"); MODULE_DESCRIPTION("CDNS sierra phy driver"); MODULE_LICENSE("GPL v2"); From 48d420835fab3df9ae4afbce65d96ab9f485ff04 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:16 +0200 Subject: [PATCH 15/64] phy: hisilicon: hi6220-usb: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-5-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/hisilicon/phy-hi6220-usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/hisilicon/phy-hi6220-usb.c b/drivers/phy/hisilicon/phy-hi6220-usb.c index 97bd363dfe87..22d8d8a8dabe 100644 --- a/drivers/phy/hisilicon/phy-hi6220-usb.c +++ b/drivers/phy/hisilicon/phy-hi6220-usb.c @@ -161,5 +161,4 @@ static struct platform_driver hi6220_phy_driver = { module_platform_driver(hi6220_phy_driver); MODULE_DESCRIPTION("HISILICON HI6220 USB PHY driver"); -MODULE_ALIAS("platform:hi6220-usb-phy"); MODULE_LICENSE("GPL"); From bd86f188b4e698b04416160495a8387785a0f021 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:17 +0200 Subject: [PATCH 16/64] phy: qualcomm: ipq806x-usb: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-6-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c index 06392ed7c91b..f22c0000479f 100644 --- a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c @@ -559,7 +559,6 @@ static struct platform_driver qcom_ipq806x_usb_phy_driver = { module_platform_driver(qcom_ipq806x_usb_phy_driver); -MODULE_ALIAS("platform:phy-qcom-ipq806x-usb"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Andy Gross "); MODULE_AUTHOR("Ivan T. Ivanov "); From c6986f867a330ff58ded64bda47484f20b7e2ef2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:18 +0200 Subject: [PATCH 17/64] phy: samsung: exynos5-usbdrd: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-7-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/samsung/phy-exynos5-usbdrd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c index dd660ebe8045..a88ba95bdc8f 100644 --- a/drivers/phy/samsung/phy-exynos5-usbdrd.c +++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c @@ -2417,4 +2417,3 @@ module_platform_driver(exynos5_usb3drd_phy); MODULE_DESCRIPTION("Samsung Exynos5 SoCs USB 3.0 DRD controller PHY driver"); MODULE_AUTHOR("Vivek Gautam "); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:exynos5_usb3drd_phy"); From 824cdd26af27479458ae3472c64b4ebd31c1d82d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:19 +0200 Subject: [PATCH 18/64] phy: samsung: usb2: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-8-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/samsung/phy-samsung-usb2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/samsung/phy-samsung-usb2.c b/drivers/phy/samsung/phy-samsung-usb2.c index 9de744cd6f39..d2749b67cf8f 100644 --- a/drivers/phy/samsung/phy-samsung-usb2.c +++ b/drivers/phy/samsung/phy-samsung-usb2.c @@ -258,4 +258,3 @@ module_platform_driver(samsung_usb2_phy_driver); MODULE_DESCRIPTION("Samsung S5P/Exynos SoC USB PHY driver"); MODULE_AUTHOR("Kamil Debski "); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:samsung-usb2-phy"); From 9cbc01aad21fcdff6a2139c2d8656a8ec61a79e4 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:20 +0200 Subject: [PATCH 19/64] phy: ti: omap-usb2: drop unused module alias Since commit 478b6c7436c2 ("usb: phy: omap-usb2: Don't use omap_get_control_dev()") the driver only supports OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-9-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-omap-usb2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/ti/phy-omap-usb2.c b/drivers/phy/ti/phy-omap-usb2.c index c1a0ef979142..7096d9c89a96 100644 --- a/drivers/phy/ti/phy-omap-usb2.c +++ b/drivers/phy/ti/phy-omap-usb2.c @@ -520,7 +520,6 @@ static struct platform_driver omap_usb2_driver = { module_platform_driver(omap_usb2_driver); -MODULE_ALIAS("platform:omap_usb2"); MODULE_AUTHOR("Texas Instruments Inc."); MODULE_DESCRIPTION("OMAP USB2 phy driver"); MODULE_LICENSE("GPL v2"); From dbe76a96ad784fbb1872a92999479bf9d02b900e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:21 +0200 Subject: [PATCH 20/64] phy: ti: ti-pipe3: drop unused module alias Since commit 918ee0d21ba4 ("usb: phy: omap-usb3: Don't use omap_get_control_dev()") the driver only supports OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-10-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-ti-pipe3.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/ti/phy-ti-pipe3.c b/drivers/phy/ti/phy-ti-pipe3.c index da2cbacb982c..a910c179ea6e 100644 --- a/drivers/phy/ti/phy-ti-pipe3.c +++ b/drivers/phy/ti/phy-ti-pipe3.c @@ -929,7 +929,6 @@ static struct platform_driver ti_pipe3_driver = { module_platform_driver(ti_pipe3_driver); -MODULE_ALIAS("platform:ti_pipe3"); MODULE_AUTHOR("Texas Instruments Inc."); MODULE_DESCRIPTION("TI PIPE3 phy driver"); MODULE_LICENSE("GPL v2"); From a27576076b6befd634154715220298a97ad4b24a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:22 +0200 Subject: [PATCH 21/64] phy: ti: dm816x-usb: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-11-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-dm816x-usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/ti/phy-dm816x-usb.c b/drivers/phy/ti/phy-dm816x-usb.c index e8f842d4e841..d274831b731c 100644 --- a/drivers/phy/ti/phy-dm816x-usb.c +++ b/drivers/phy/ti/phy-dm816x-usb.c @@ -269,7 +269,6 @@ static struct platform_driver dm816x_usb_phy_driver = { module_platform_driver(dm816x_usb_phy_driver); -MODULE_ALIAS("platform:dm816x_usb"); MODULE_AUTHOR("Tony Lindgren "); MODULE_DESCRIPTION("dm816x usb phy driver"); MODULE_LICENSE("GPL v2"); From 8eb3a6f7a1881d2cfd4f7d741e263ce6999bcbc9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:23 +0200 Subject: [PATCH 22/64] phy: ti: omap-control: drop unused module alias Since commit 4fd06af96b93 ("usb: phy: omap-control: Get rid of platform data") the driver only supports OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-12-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-omap-control.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/ti/phy-omap-control.c b/drivers/phy/ti/phy-omap-control.c index 2fdb8f4241c7..4968434312f8 100644 --- a/drivers/phy/ti/phy-omap-control.c +++ b/drivers/phy/ti/phy-omap-control.c @@ -334,7 +334,6 @@ static void __exit omap_control_phy_exit(void) } module_exit(omap_control_phy_exit); -MODULE_ALIAS("platform:omap_control_phy"); MODULE_AUTHOR("Texas Instruments Inc."); MODULE_DESCRIPTION("OMAP Control Module PHY Driver"); MODULE_LICENSE("GPL v2"); From 791cfbe1c56076c9d3bcf856b5175bfbc9c5a2d4 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 9 Jul 2025 16:55:14 +0200 Subject: [PATCH 23/64] dt-bindings: phy: qcom,snps-eusb2-repeater: Document qcom,tune-res-fsdif Document the FS Differential TX Output Resistance Tuning value found on the eUSB2 repeater on Qualcomm PMICs. The tuning values have special meanings, being different offsets of the resistance to the default value in Ohms but the exact meaning is not relevant here, as the correct tuning is determined by hardware engineers to make sure the electrical properties are as expected. Signed-off-by: Luca Weiss Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250709-sm7635-eusb-repeater-v2-1-b6eff075c097@fairphone.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml index 27f064a71c9f..6bfd11657e29 100644 --- a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml @@ -52,6 +52,12 @@ properties: minimum: 0 maximum: 7 + qcom,tune-res-fsdif: + $ref: /schemas/types.yaml#/definitions/uint8 + description: FS Differential TX Output Resistance Tuning + minimum: 0 + maximum: 7 + required: - compatible - reg From 08bde1e7c71396fcf96b0410b1c4cb6bee5b8741 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 9 Jul 2025 16:55:15 +0200 Subject: [PATCH 24/64] phy: qualcomm: phy-qcom-eusb2-repeater: Support tune-res-fsdif prop Support reading the FS Differential TX Output Resistance Tuning from devicetree and writing the register, as required on some boards. Reviewed-by: Abel Vesa Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20250709-sm7635-eusb-repeater-v2-2-b6eff075c097@fairphone.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c index e0f2acc8109c..b2f8f1314e90 100644 --- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c +++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c @@ -136,6 +136,9 @@ static int eusb2_repeater_init(struct phy *phy) if (!of_property_read_u8(np, "qcom,tune-usb2-preem", &val)) regmap_write(regmap, base + EUSB2_TUNE_IUSB2, val); + if (!of_property_read_u8(np, "qcom,tune-res-fsdif", &val)) + regmap_write(regmap, base + EUSB2_TUNE_RES_FSDIF, val); + /* Wait for status OK */ ret = regmap_read_poll_timeout(regmap, base + EUSB2_RPTR_STATUS, poll_val, poll_val & RPTR_OK, 10, 5); From 5edc4054655009691deb79142af1ffe5aba0a224 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 9 Jul 2025 16:55:16 +0200 Subject: [PATCH 25/64] dt-bindings: phy: qcom,snps-eusb2-repeater: Add compatible for PMIV0104 Add a dt-bindings compatible string for the Qualcomm's PMIV0104 PMIC. Acked-by: Krzysztof Kozlowski Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20250709-sm7635-eusb-repeater-v2-3-b6eff075c097@fairphone.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml index 6bfd11657e29..5bf0d6c9c025 100644 --- a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml @@ -22,6 +22,7 @@ properties: - const: qcom,pm8550b-eusb2-repeater - enum: - qcom,pm8550b-eusb2-repeater + - qcom,pmiv0104-eusb2-repeater - qcom,smb2360-eusb2-repeater reg: From ce872bce1140eec07ed624e537687244a5c01397 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 9 Jul 2025 16:55:17 +0200 Subject: [PATCH 26/64] phy: qualcomm: phy-qcom-eusb2-repeater: Add support for PMIV0104 Add support for the eUSB2 repeater found on the PMIV0104. There is no default init table for this PMIC, just the board-specific tuning parameters are used on top of the default tuning values. Reviewed-by: Abel Vesa Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20250709-sm7635-eusb-repeater-v2-4-b6eff075c097@fairphone.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c index b2f8f1314e90..3629b926108a 100644 --- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c +++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c @@ -82,6 +82,14 @@ static const struct eusb2_repeater_cfg pm8550b_eusb2_cfg = { .num_vregs = ARRAY_SIZE(pm8550b_vreg_l), }; +static const struct eusb2_repeater_cfg pmiv0104_eusb2_cfg = { + /* No PMIC-specific init sequence, only board level tuning via DT */ + .init_tbl = (struct eusb2_repeater_init_tbl_reg[]) {}, + .init_tbl_num = 0, + .vreg_list = pm8550b_vreg_l, + .num_vregs = ARRAY_SIZE(pm8550b_vreg_l), +}; + static const struct eusb2_repeater_cfg smb2360_eusb2_cfg = { .init_tbl = smb2360_init_tbl, .init_tbl_num = ARRAY_SIZE(smb2360_init_tbl), @@ -262,6 +270,10 @@ static const struct of_device_id eusb2_repeater_of_match_table[] = { .compatible = "qcom,pm8550b-eusb2-repeater", .data = &pm8550b_eusb2_cfg, }, + { + .compatible = "qcom,pmiv0104-eusb2-repeater", + .data = &pmiv0104_eusb2_cfg, + }, { .compatible = "qcom,smb2360-eusb2-repeater", .data = &smb2360_eusb2_cfg, From edafd4f3fd52a614c5cee2684559367eac2286dc Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Sat, 9 Aug 2025 15:29:16 +0530 Subject: [PATCH 27/64] dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Document the SM8750 QMP PCIe PHY Gen3 x2 Document the QMP PCIe PHY on the SM8750 platform. Signed-off-by: Krishna Chaitanya Chundru Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250809-pakala-v1-1-abf1c416dbaa@oss.qualcomm.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml index a1ae8c7988c8..cb706cf8219d 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -42,6 +42,7 @@ properties: - qcom,sm8550-qmp-gen4x2-pcie-phy - qcom,sm8650-qmp-gen3x2-pcie-phy - qcom,sm8650-qmp-gen4x2-pcie-phy + - qcom,sm8750-qmp-gen3x2-pcie-phy - qcom,x1e80100-qmp-gen3x2-pcie-phy - qcom,x1e80100-qmp-gen4x2-pcie-phy - qcom,x1e80100-qmp-gen4x4-pcie-phy @@ -164,6 +165,7 @@ allOf: - qcom,sm8550-qmp-gen4x2-pcie-phy - qcom,sm8650-qmp-gen3x2-pcie-phy - qcom,sm8650-qmp-gen4x2-pcie-phy + - qcom,sm8750-qmp-gen3x2-pcie-phy then: properties: clocks: From 0f051749c804b5a4f485013c0e3c932e1dd9f70b Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Sat, 9 Aug 2025 15:29:17 +0530 Subject: [PATCH 28/64] phy: qcom-qmp-pcie: add dual lane PHY support for SM8750 The PCIe Gen3 x2 PHY for SM8750 uses new phy, add the required registers and offsets for this phy. Signed-off-by: Krishna Chaitanya Chundru Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250809-pakala-v1-2-abf1c416dbaa@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 149 ++++++++++++++++++ drivers/phy/qualcomm/phy-qcom-qmp-pcs-v7.h | 2 + .../qualcomm/phy-qcom-qmp-qserdes-txrx-v7.h | 4 +- 3 files changed, 154 insertions(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 95830dcfdec9..8fdc146ef732 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -93,6 +93,13 @@ static const unsigned int pciephy_v6_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V6_PCS_POWER_DOWN_CONTROL, }; +static const unsigned int pciephy_v7_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V7_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V7_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V7_PCS_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V7_PCS_POWER_DOWN_CONTROL, +}; + static const struct qmp_phy_init_tbl msm8998_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x14), QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), @@ -2590,6 +2597,108 @@ static const struct qmp_phy_init_tbl sm8650_qmp_gen4x2_pcie_rx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B6, 0xff), }; +static const struct qmp_phy_init_tbl sm8750_qmp_gen3x2_pcie_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_EN_CENTER, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_PER1, 0x62), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_PER2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_STEP_SIZE1_MODE0, 0xf8), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_STEP_SIZE2_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_STEP_SIZE1_MODE1, 0x93), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_STEP_SIZE2_MODE1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CLK_ENABLE1, 0x90), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SYS_CLK_CTRL, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_PLL_IVCO, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CP_CTRL_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CP_CTRL_MODE1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SYSCLK_EN_SEL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_LOCK_CMP_EN, 0x42), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_LOCK_CMP1_MODE0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_LOCK_CMP2_MODE0, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_LOCK_CMP1_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_LOCK_CMP2_MODE1, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DEC_START_MODE0, 0x41), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DEC_START_MODE1, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DIV_FRAC_START2_MODE0, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DIV_FRAC_START3_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DIV_FRAC_START1_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DIV_FRAC_START2_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DIV_FRAC_START3_MODE1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_VCO_TUNE_MAP, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CLK_SELECT, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_HSCLK_SEL_1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CORECLK_DIV_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CMN_CONFIG_1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_ADDITIONAL_MISC_3, 0x0F), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CORE_CLK_EN, 0xA0), +}; + +static const struct qmp_phy_init_tbl sm8750_qmp_gen3x2_pcie_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V7_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_GM_CAL, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_00_HIGH, 0xBF), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_00_HIGH2, 0xBF), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_00_HIGH3, 0xB7), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_00_HIGH4, 0xEA), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_00_LOW, 0x3F), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_01_HIGH, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_01_HIGH2, 0x49), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_01_HIGH3, 0x1B), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_01_HIGH4, 0x9C), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_01_LOW, 0xD1), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_10_HIGH, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_10_HIGH2, 0x49), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_10_HIGH3, 0x1B), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_10_HIGH4, 0x9C), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_10_LOW, 0xD1), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_TX_ADAPT_PRE_THRESH1, 0x3E), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_TX_ADAPT_PRE_THRESH2, 0x1E), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_TX_ADAPT_POST_THRESH, 0xD2), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_UCDR_FO_GAIN, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_UCDR_SO_GAIN, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_UCDR_SB2_THRESH1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_UCDR_SB2_THRESH2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_VGA_CAL_CNTRL2, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_SIGDET_ENABLES, 0x1C), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_SIGDET_CNTRL, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_IDAC_TSETTLE_LOW, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_SIGDET_CAL_TRIM, 0x08), +}; + +static const struct qmp_phy_init_tbl sm8750_qmp_gen3x2_pcie_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V7_TX_LANE_MODE_1, 0x35), + QMP_PHY_INIT_CFG(QSERDES_V7_TX_LANE_MODE_3, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V7_TX_LANE_MODE_4, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V7_TX_LANE_MODE_5, 0x7F), + QMP_PHY_INIT_CFG(QSERDES_V7_TX_PI_QEC_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V7_TX_RES_CODE_LANE_OFFSET_RX, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V7_TX_RES_CODE_LANE_OFFSET_TX, 0x14), +}; + +static const struct qmp_phy_init_tbl sm8750_qmp_gen3x2_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V7_PCS_REFGEN_REQ_CONFIG1, 0x05), + QMP_PHY_INIT_CFG(QPHY_V7_PCS_RX_SIGDET_LVL, 0x77), + QMP_PHY_INIT_CFG(QPHY_V7_PCS_RATE_SLEW_CNTRL1, 0x0B), + QMP_PHY_INIT_CFG(QPHY_V7_PCS_EQ_CONFIG2, 0x0F), + QMP_PHY_INIT_CFG(QPHY_V7_PCS_PCS_TX_RX_CONFIG, 0x8C), + QMP_PHY_INIT_CFG(QPHY_V7_PCS_G12S1_TXDEEMPH_M6DB, 0x17), + QMP_PHY_INIT_CFG(QPHY_V7_PCS_G3S2_PRE_GAIN, 0x2E), +}; + +static const struct qmp_phy_init_tbl sm8750_qmp_gen3x2_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_EQ_CONFIG1, 0x1E), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_RXEQEVAL_TIME, 0x27), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG2, 0x1D), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG4, 0x07), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xC1), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00), +}; + static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x2_pcie_serdes_alt_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x14), QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_IVCO, 0x0f), @@ -3207,6 +3316,16 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v5_30 = { .rx2 = 0x3a00, }; +static const struct qmp_pcie_offsets qmp_pcie_offsets_v7 = { + .serdes = 0x0, + .pcs = 0x400, + .pcs_misc = 0x800, + .tx = 0x1000, + .rx = 0x1200, + .tx2 = 0x1800, + .rx2 = 0x1a00, +}; + static const struct qmp_pcie_offsets qmp_pcie_offsets_v6_20 = { .serdes = 0x1000, .pcs = 0x1200, @@ -3996,6 +4115,33 @@ static const struct qmp_phy_cfg sm8550_qmp_gen3x2_pciephy_cfg = { .phy_status = PHYSTATUS, }; +static const struct qmp_phy_cfg sm8750_qmp_gen3x2_pciephy_cfg = { + .lanes = 2, + + .offsets = &qmp_pcie_offsets_v7, + + .tbls = { + .serdes = sm8750_qmp_gen3x2_pcie_serdes_tbl, + .serdes_num = ARRAY_SIZE(sm8750_qmp_gen3x2_pcie_serdes_tbl), + .tx = sm8750_qmp_gen3x2_pcie_tx_tbl, + .tx_num = ARRAY_SIZE(sm8750_qmp_gen3x2_pcie_tx_tbl), + .rx = sm8750_qmp_gen3x2_pcie_rx_tbl, + .rx_num = ARRAY_SIZE(sm8750_qmp_gen3x2_pcie_rx_tbl), + .pcs = sm8750_qmp_gen3x2_pcie_pcs_tbl, + .pcs_num = ARRAY_SIZE(sm8750_qmp_gen3x2_pcie_pcs_tbl), + .pcs_misc = sm8750_qmp_gen3x2_pcie_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(sm8750_qmp_gen3x2_pcie_pcs_misc_tbl), + }, + .reset_list = sdm845_pciephy_reset_l, + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = pciephy_v7_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS, +}; + static const struct qmp_phy_cfg sm8550_qmp_gen4x2_pciephy_cfg = { .lanes = 2, @@ -5099,6 +5245,9 @@ static const struct of_device_id qmp_pcie_of_match_table[] = { }, { .compatible = "qcom,sm8650-qmp-gen4x2-pcie-phy", .data = &sm8650_qmp_gen4x2_pciephy_cfg, + }, { + .compatible = "qcom,sm8750-qmp-gen3x2-pcie-phy", + .data = &sm8750_qmp_gen3x2_pciephy_cfg, }, { .compatible = "qcom,x1e80100-qmp-gen3x2-pcie-phy", .data = &sm8550_qmp_gen3x2_pciephy_cfg, diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v7.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v7.h index c7759892ed2e..4b7fcaa6a374 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v7.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v7.h @@ -17,6 +17,8 @@ #define QPHY_V7_PCS_LOCK_DETECT_CONFIG3 0x0cc #define QPHY_V7_PCS_LOCK_DETECT_CONFIG6 0x0d8 #define QPHY_V7_PCS_REFGEN_REQ_CONFIG1 0x0dc +#define QPHY_V7_PCS_G12S1_TXDEEMPH_M6DB 0x168 +#define QPHY_V7_PCS_G3S2_PRE_GAIN 0x170 #define QPHY_V7_PCS_RX_SIGDET_LVL 0x188 #define QPHY_V7_PCS_RCVR_DTCT_DLY_P1U2_L 0x190 #define QPHY_V7_PCS_RCVR_DTCT_DLY_P1U2_H 0x194 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v7.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v7.h index 91f865b11347..6ab943ff57ff 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v7.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v7.h @@ -40,6 +40,8 @@ #define QSERDES_V7_RX_UCDR_SB2_GAIN1 0x54 #define QSERDES_V7_RX_UCDR_SB2_GAIN2 0x58 #define QSERDES_V7_RX_AUX_DATA_TCOARSE_TFINE 0x60 +#define QSERDES_V7_RX_TX_ADAPT_PRE_THRESH1 0xc4 +#define QSERDES_V7_RX_TX_ADAPT_PRE_THRESH2 0xc8 #define QSERDES_V7_RX_TX_ADAPT_POST_THRESH 0xcc #define QSERDES_V7_RX_VGA_CAL_CNTRL1 0xd4 #define QSERDES_V7_RX_VGA_CAL_CNTRL2 0xd8 @@ -50,7 +52,7 @@ #define QSERDES_V7_RX_RX_IDAC_TSETTLE_LOW 0xf8 #define QSERDES_V7_RX_RX_IDAC_TSETTLE_HIGH 0xfc #define QSERDES_V7_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x110 -#define QSERDES_V7_RX_SIDGET_ENABLES 0x118 +#define QSERDES_V7_RX_SIGDET_ENABLES 0x118 #define QSERDES_V7_RX_SIGDET_CNTRL 0x11c #define QSERDES_V7_RX_SIGDET_DEGLITCH_CNTRL 0x124 #define QSERDES_V7_RX_RX_MODE_00_LOW 0x15c From 75c21418beb92382dda164fdc2554610b49ed441 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 19 Aug 2025 01:15:22 +0100 Subject: [PATCH 29/64] phy: sun4i-usb: drop num_phys assumption So far we set a number of expected Allwinner USB PHY instances for any given compatible string, and would fail if we do not find every PHY described properly in the DT (missing reset/PMU/clocks). This is somewhat redundant, as the DT only describes the resources for the implemented PHYs, but goes in line with being strict about firmware descriptions, and rather fixing things in the driver code, based on the compatible string. However this causes issues when we make a mistake, like we did recently on the A523: there are actually three USB PHYs, not two, as we assumed. Changing the number in the driver and the compatible string would cause all kinds of compatibility issues, both with older and newer DTs. To avoid problems with newer kernels and older or newer DTs, we can change the driver code to deduce the number of PHY instances from what's described in the DT. This has the added advantage of not requiring new compatible strings for new SoCs when just the number of PHYs change, which already happened and might occur again in the future. Drop the num_phys member from the config struct, and remove the fixed number of PHYs from each SoC's config description. Then enumerate the usb_reset properties for all of the maximum four PHY instances, and just stop once we cannot find such a property anymore. The binding describes the reset property as mandatory for each PHY instance, and each DT in the kernel tree matches exactly the num_phys value in the current driver code, so we can rely on that. Apart from being more future proof, this will solve the A523 mishap: Older DTs would just describe two PHYs, whereas newer ones would feature all three of them. In any case we would get a valid number, matching the other nodes in the DT. Older kernels would always enumerate two PHYs, which at least does not cause any regressions. Signed-off-by: Andre Przywara Link: https://lore.kernel.org/r/20250819001522.13011-1-andre.przywara@arm.com Signed-off-by: Vinod Koul --- drivers/phy/allwinner/phy-sun4i-usb.c | 38 +++++++++------------------ 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index 8873aed3a52a..59d38d88efb0 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -97,7 +97,6 @@ #define POLL_TIME msecs_to_jiffies(250) struct sun4i_usb_phy_cfg { - int num_phys; int hsic_index; u32 disc_thresh; u32 hci_phy_ctl_clear; @@ -115,6 +114,7 @@ struct sun4i_usb_phy_data { const struct sun4i_usb_phy_cfg *cfg; enum usb_dr_mode dr_mode; spinlock_t reg_lock; /* guard access to phyctl reg */ + int num_phys; struct sun4i_usb_phy { struct phy *phy; void __iomem *pmu; @@ -686,7 +686,7 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev, { struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); - if (args->args[0] >= data->cfg->num_phys) + if (args->args[0] >= data->num_phys) return ERR_PTR(-ENODEV); if (data->cfg->missing_phys & BIT(args->args[0])) @@ -779,13 +779,22 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) return ret; } - for (i = 0; i < data->cfg->num_phys; i++) { + for (i = 0; i < MAX_PHYS; i++) { struct sun4i_usb_phy *phy = data->phys + i; char name[32]; if (data->cfg->missing_phys & BIT(i)) continue; + snprintf(name, sizeof(name), "usb%d_reset", i); + phy->reset = devm_reset_control_get(dev, name); + if (IS_ERR(phy->reset)) { + if (PTR_ERR(phy->reset) == -ENOENT) + break; + dev_err(dev, "failed to get reset %s\n", name); + return PTR_ERR(phy->reset); + } + snprintf(name, sizeof(name), "usb%d_vbus", i); phy->vbus = devm_regulator_get_optional(dev, name); if (IS_ERR(phy->vbus)) { @@ -828,13 +837,6 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) } } - snprintf(name, sizeof(name), "usb%d_reset", i); - phy->reset = devm_reset_control_get(dev, name); - if (IS_ERR(phy->reset)) { - dev_err(dev, "failed to get reset %s\n", name); - return PTR_ERR(phy->reset); - } - if (i || data->cfg->phy0_dual_route) { /* No pmu for musb */ snprintf(name, sizeof(name), "pmu%d", i); phy->pmu = devm_platform_ioremap_resource_byname(pdev, name); @@ -851,6 +853,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) phy->index = i; phy_set_drvdata(phy->phy, &data->phys[i]); } + data->num_phys = i; data->id_det_irq = gpiod_to_irq(data->id_det_gpio); if (data->id_det_irq > 0) { @@ -901,28 +904,24 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) } static const struct sun4i_usb_phy_cfg suniv_f1c100s_cfg = { - .num_phys = 1, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = true, }; static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = { - .num_phys = 3, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = false, }; static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = { - .num_phys = 2, .disc_thresh = 2, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = false, }; static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = { - .num_phys = 3, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = true, @@ -930,14 +929,12 @@ static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = { }; static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = { - .num_phys = 3, .disc_thresh = 2, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = false, }; static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = { - .num_phys = 2, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = true, @@ -945,7 +942,6 @@ static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = { }; static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = { - .num_phys = 2, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, @@ -953,7 +949,6 @@ static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = { }; static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = { - .num_phys = 3, .hsic_index = 2, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, @@ -961,7 +956,6 @@ static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = { }; static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { - .num_phys = 4, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, @@ -970,7 +964,6 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { }; static const struct sun4i_usb_phy_cfg sun8i_r40_cfg = { - .num_phys = 3, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, @@ -979,7 +972,6 @@ static const struct sun4i_usb_phy_cfg sun8i_r40_cfg = { }; static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = { - .num_phys = 1, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, @@ -988,7 +980,6 @@ static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = { }; static const struct sun4i_usb_phy_cfg sun20i_d1_cfg = { - .num_phys = 2, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, .hci_phy_ctl_clear = PHY_CTL_SIDDQ, @@ -997,7 +988,6 @@ static const struct sun4i_usb_phy_cfg sun20i_d1_cfg = { }; static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = { - .num_phys = 2, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, @@ -1006,7 +996,6 @@ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = { }; static const struct sun4i_usb_phy_cfg sun50i_h6_cfg = { - .num_phys = 4, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, .phy0_dual_route = true, @@ -1015,7 +1004,6 @@ static const struct sun4i_usb_phy_cfg sun50i_h6_cfg = { }; static const struct sun4i_usb_phy_cfg sun50i_h616_cfg = { - .num_phys = 4, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, From e1e1e77f7df7cbee959ba024e5475907fe561c98 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:14:58 +0200 Subject: [PATCH 30/64] phy: remove unneeded 'fast_io' parameter in regmap_config When using MMIO with regmap, fast_io is implied. No need to set it again. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250813161517.4746-13-wsa+renesas@sang-engineering.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 1 - drivers/phy/rockchip/phy-rockchip-usbdp.c | 1 - drivers/phy/ti/phy-am654-serdes.c | 1 - drivers/phy/ti/phy-j721e-wiz.c | 1 - 4 files changed, 4 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c index 79db57ee90d1..01bbf668e05e 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c @@ -795,7 +795,6 @@ static const struct regmap_config rk_hdptx_phy_regmap_config = { .val_bits = 32, .writeable_reg = rk_hdptx_phy_is_rw_reg, .readable_reg = rk_hdptx_phy_is_rw_reg, - .fast_io = true, .max_register = 0x18b4, }; diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c index c066cc0a7b4f..010e9d2d6fac 100644 --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c @@ -1430,7 +1430,6 @@ static const struct regmap_config rk_udphy_pma_regmap_cfg = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .fast_io = true, .max_register = 0x20dc, }; diff --git a/drivers/phy/ti/phy-am654-serdes.c b/drivers/phy/ti/phy-am654-serdes.c index 431b223996e0..5b6c27aa7e8b 100644 --- a/drivers/phy/ti/phy-am654-serdes.c +++ b/drivers/phy/ti/phy-am654-serdes.c @@ -99,7 +99,6 @@ static const struct regmap_config serdes_am654_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .fast_io = true, .max_register = 0x1ffc, }; diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index ab2a4f2c0a5b..a8b440c6c46b 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -1319,7 +1319,6 @@ static const struct regmap_config wiz_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .fast_io = true, }; static struct wiz_data j721e_16g_data = { From a8f9de937dbf7bdabda72bd0c51e201e550129c2 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Thu, 14 Aug 2025 09:39:43 +0800 Subject: [PATCH 31/64] phy: rockchip: naneng-combphy: Convert comma to semicolon Replace comma between expressions with semicolons. Using a ',' in place of a ';' can have unintended side effects. Although that is not the case here, it is seems best to use ';' unless ',' is intended. Found by inspection. No functional change intended. Compile tested only. Signed-off-by: Chen Ni Link: https://lore.kernel.org/r/20250814013943.2905307-1-nichen@iscas.ac.cn Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-naneng-combphy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index 0d25872e6712..a3ef19807b9e 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -1252,7 +1252,7 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) writel(val, priv->mmio + RK3568_PHYREG15); /* Set PLL KVCO fine tuning signals. */ - val = RK3568_PHYREG33_PLL_KVCO_VALUE << RK3568_PHYREG33_PLL_KVCO_SHIFT, + val = RK3568_PHYREG33_PLL_KVCO_VALUE << RK3568_PHYREG33_PLL_KVCO_SHIFT; rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, val, RK3568_PHYREG33); /* Enable controlling random jitter. */ From 3bad7fe22796a420c6e16b591c37ed1bd6cc2a30 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 7 Aug 2025 18:33:19 +0200 Subject: [PATCH 32/64] dt-bindings: phy: qcom,sc8280xp-qmp-usb43dp: Reference usb-switch.yaml to allow mode-switch The QMP USB3/DP Combo PHY can work in 3 modes: - DisplayPort Only - USB3 Only - USB3 + DisplayPort Combo mode In order to switch between those modes, the PHY needs to receive Type-C events, allow marking to the phy with the mode-switch property in order to allow the PHY to Type-C events. Reference usb-switch.yaml as a simpler way to allow the mode-switch property instead of duplicating the property definition. Signed-off-by: Neil Armstrong Reviewed-by: Krzysztof Kozlowski Signed-off-by: Konrad Dybcio Tested-by: Neil Armstrong # on Lenovo Thinkpad T14S Link: https://lore.kernel.org/r/20250807-topic-4ln_dp_respin-v4-1-43272d6eca92@oss.qualcomm.com Signed-off-by: Vinod Koul --- .../bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml index 38ce04c35d94..c8bc512df08b 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml @@ -73,10 +73,8 @@ properties: description: See include/dt-bindings/phy/phy-qcom-qmp.h - orientation-switch: - description: - Flag the PHY as possible handler of USB Type-C orientation switching - type: boolean + mode-switch: true + orientation-switch: true ports: $ref: /schemas/graph.yaml#/properties/ports @@ -106,6 +104,7 @@ required: - "#phy-cells" allOf: + - $ref: /schemas/usb/usb-switch.yaml# - if: properties: compatible: From 5daf1bbc73e249075373e030e7221f46c175e04b Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 7 Aug 2025 18:33:20 +0200 Subject: [PATCH 33/64] phy: qcom: qmp-combo: Rename 'mode' to 'phy_mode' There are a numbers of ""modes"" involved: USB mode, Type-C mode (with its altmodes), phy_mode and QMP_PHY mode (DP/combo/USB/off). Rename the generic sounding 'mode' to 'phy_mode' to hopefully make the code easier to follow. Reviewed-by: Dmitry Baryshkov Signed-off-by: Konrad Dybcio Reviewed-by: Neil Armstrong Tested-by: Neil Armstrong # on Lenovo Thinkpad T14S Link: https://lore.kernel.org/r/20250807-topic-4ln_dp_respin-v4-2-43272d6eca92@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index f07d097b129f..30749943f662 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -1846,7 +1846,7 @@ struct qmp_combo { int init_count; struct phy *usb_phy; - enum phy_mode mode; + enum phy_mode phy_mode; unsigned int usb_init_count; struct phy *dp_phy; @@ -3282,7 +3282,7 @@ static int qmp_combo_usb_set_mode(struct phy *phy, enum phy_mode mode, int submo { struct qmp_combo *qmp = phy_get_drvdata(phy); - qmp->mode = mode; + qmp->phy_mode = mode; return 0; } @@ -3311,8 +3311,8 @@ static void qmp_combo_enable_autonomous_mode(struct qmp_combo *qmp) void __iomem *pcs_misc = qmp->pcs_misc; u32 intr_mask; - if (qmp->mode == PHY_MODE_USB_HOST_SS || - qmp->mode == PHY_MODE_USB_DEVICE_SS) + if (qmp->phy_mode == PHY_MODE_USB_HOST_SS || + qmp->phy_mode == PHY_MODE_USB_DEVICE_SS) intr_mask = ARCVR_DTCT_EN | ALFPS_DTCT_EN; else intr_mask = ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL; @@ -3355,7 +3355,7 @@ static int __maybe_unused qmp_combo_runtime_suspend(struct device *dev) { struct qmp_combo *qmp = dev_get_drvdata(dev); - dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode); + dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->phy_mode); if (!qmp->init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); @@ -3375,7 +3375,7 @@ static int __maybe_unused qmp_combo_runtime_resume(struct device *dev) struct qmp_combo *qmp = dev_get_drvdata(dev); int ret = 0; - dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode); + dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->phy_mode); if (!qmp->init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); From 86390472554b2e8fb4cba16a139cade94be58f72 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 7 Aug 2025 18:33:21 +0200 Subject: [PATCH 34/64] phy: qcom: qmp-combo: store DP phy power state Switching the PHY Mode requires the DisplayPort PHY to be powered off, keep track of the DisplayPort phy power state. Reviewed-by: Dmitry Baryshkov Signed-off-by: Neil Armstrong Signed-off-by: Konrad Dybcio Tested-by: Neil Armstrong # on Lenovo Thinkpad T14S Link: https://lore.kernel.org/r/20250807-topic-4ln_dp_respin-v4-3-43272d6eca92@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 30749943f662..839503575497 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -1853,6 +1853,7 @@ struct qmp_combo { unsigned int dp_aux_cfg; struct phy_configure_opts_dp dp_opts; unsigned int dp_init_count; + bool dp_powered_on; struct clk_fixed_rate pipe_clk_fixed; struct clk_hw dp_link_hw; @@ -3133,6 +3134,8 @@ static int qmp_combo_dp_power_on(struct phy *phy) /* Configure link rate, swing, etc. */ cfg->configure_dp_phy(qmp); + qmp->dp_powered_on = true; + mutex_unlock(&qmp->phy_mutex); return 0; @@ -3147,6 +3150,8 @@ static int qmp_combo_dp_power_off(struct phy *phy) /* Assert DP PHY power down */ writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); + qmp->dp_powered_on = false; + mutex_unlock(&qmp->phy_mutex); return 0; From dd331112c0adaebbc8fc767fc805da4a641576db Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 7 Aug 2025 18:33:22 +0200 Subject: [PATCH 35/64] phy: qcom: qmp-combo: introduce QMPPHY_MODE Introduce an enum for the QMP Combo PHY modes, use it in the QMP commmon phy init function and default to COMBO mode. Signed-off-by: Neil Armstrong [konrad: some renaming and rewording] Signed-off-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Tested-by: Neil Armstrong # on Lenovo Thinkpad T14S Link: https://lore.kernel.org/r/20250807-topic-4ln_dp_respin-v4-4-43272d6eca92@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 44 ++++++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 839503575497..c65837fc9e4c 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -62,6 +62,12 @@ #define PHY_INIT_COMPLETE_TIMEOUT 10000 +enum qmpphy_mode { + QMPPHY_MODE_USB3DP = 0, + QMPPHY_MODE_DP_ONLY, + QMPPHY_MODE_USB3_ONLY, +}; + /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { /* PCS registers */ @@ -1844,6 +1850,7 @@ struct qmp_combo { struct mutex phy_mutex; int init_count; + enum qmpphy_mode qmpphy_mode; struct phy *usb_phy; enum phy_mode phy_mode; @@ -3037,12 +3044,33 @@ static int qmp_combo_com_init(struct qmp_combo *qmp, bool force) if (qmp->orientation == TYPEC_ORIENTATION_REVERSE) val |= SW_PORTSELECT_VAL; writel(val, com + QPHY_V3_DP_COM_TYPEC_CTRL); - writel(USB3_MODE | DP_MODE, com + QPHY_V3_DP_COM_PHY_MODE_CTRL); - /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ - qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, - SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | - SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); + switch (qmp->qmpphy_mode) { + case QMPPHY_MODE_USB3DP: + writel(USB3_MODE | DP_MODE, com + QPHY_V3_DP_COM_PHY_MODE_CTRL); + + /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ + qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, + SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | + SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); + break; + + case QMPPHY_MODE_DP_ONLY: + writel(DP_MODE, com + QPHY_V3_DP_COM_PHY_MODE_CTRL); + + /* bring QMP DP PHY PCS block out of reset */ + qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, + SW_DPPHY_RESET_MUX | SW_DPPHY_RESET); + break; + + case QMPPHY_MODE_USB3_ONLY: + writel(USB3_MODE, com + QPHY_V3_DP_COM_PHY_MODE_CTRL); + + /* bring QMP USB PHY PCS block out of reset */ + qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, + SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); + break; + } qphy_clrbits(com, QPHY_V3_DP_COM_SWI_CTRL, 0x03); qphy_clrbits(com, QPHY_V3_DP_COM_SW_RESET, SW_RESET); @@ -4053,6 +4081,12 @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) goto err_node_put; + /* + * The hw default is USB3_ONLY, but USB3+DP mode lets us more easily + * check both sub-blocks' init tables for blunders at probe time. + */ + qmp->qmpphy_mode = QMPPHY_MODE_USB3DP; + qmp->usb_phy = devm_phy_create(dev, usb_np, &qmp_combo_usb_phy_ops); if (IS_ERR(qmp->usb_phy)) { ret = PTR_ERR(qmp->usb_phy); From 896277138c1344cf9f5c415298f048ee29da274d Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 7 Aug 2025 18:33:23 +0200 Subject: [PATCH 36/64] phy: qcom: qmp-combo: register a typec mux to change the QMPPHY_MODE Register a typec mux in order to change the PHY mode on the Type-C mux events depending on the mode and the svid when in Altmode setup. The DisplayPort phy should be left enabled if is still powered on by the DRM DisplayPort controller, so bail out until the DisplayPort PHY is not powered off. The Type-C Mode/SVID only changes on plug/unplug, and USB SAFE states will be set in between of USB-Only, Combo and DisplayPort Only so this will leave enough time to the DRM DisplayPort controller to turn of the DisplayPort PHY. Signed-off-by: Neil Armstrong [konrad: renaming, rewording, bug fixes] Signed-off-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Tested-by: Neil Armstrong # on Lenovo Thinkpad T14S Link: https://lore.kernel.org/r/20250807-topic-4ln_dp_respin-v4-5-43272d6eca92@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 118 +++++++++++++++++++++- 1 file changed, 113 insertions(+), 5 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index c65837fc9e4c..7b5af30f1d02 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -1868,6 +1869,8 @@ struct qmp_combo { struct typec_switch_dev *sw; enum typec_orientation orientation; + + struct typec_mux_dev *mux; }; static void qmp_v3_dp_aux_init(struct qmp_combo *qmp); @@ -3802,17 +3805,109 @@ static int qmp_combo_typec_switch_set(struct typec_switch_dev *sw, return 0; } -static void qmp_combo_typec_unregister(void *data) +static int qmp_combo_typec_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state) +{ + struct qmp_combo *qmp = typec_mux_get_drvdata(mux); + const struct qmp_phy_cfg *cfg = qmp->cfg; + enum qmpphy_mode new_mode; + unsigned int svid; + + guard(mutex)(&qmp->phy_mutex); + + if (state->alt) + svid = state->alt->svid; + else + svid = 0; + + if (svid == USB_TYPEC_DP_SID) { + switch (state->mode) { + /* DP Only */ + case TYPEC_DP_STATE_C: + case TYPEC_DP_STATE_E: + new_mode = QMPPHY_MODE_DP_ONLY; + break; + + /* DP + USB */ + case TYPEC_DP_STATE_D: + case TYPEC_DP_STATE_F: + + /* Safe fallback...*/ + default: + new_mode = QMPPHY_MODE_USB3DP; + break; + } + } else { + /* No DP SVID => don't care, assume it's just USB3 */ + new_mode = QMPPHY_MODE_USB3_ONLY; + } + + if (new_mode == qmp->qmpphy_mode) { + dev_dbg(qmp->dev, "typec_mux_set: same qmpphy mode, bail out\n"); + return 0; + } + + if (qmp->qmpphy_mode != QMPPHY_MODE_USB3_ONLY && qmp->dp_powered_on) { + dev_dbg(qmp->dev, "typec_mux_set: DP PHY is still in use, delaying switch\n"); + return 0; + } + + dev_dbg(qmp->dev, "typec_mux_set: switching from qmpphy mode %d to %d\n", + qmp->qmpphy_mode, new_mode); + + qmp->qmpphy_mode = new_mode; + + if (qmp->init_count) { + if (qmp->usb_init_count) + qmp_combo_usb_power_off(qmp->usb_phy); + + if (qmp->dp_init_count) + writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); + + qmp_combo_com_exit(qmp, true); + + /* Now everything's powered down, power up the right PHYs */ + qmp_combo_com_init(qmp, true); + + if (new_mode == QMPPHY_MODE_DP_ONLY) { + if (qmp->usb_init_count) + qmp->usb_init_count--; + } + + if (new_mode == QMPPHY_MODE_USB3DP || new_mode == QMPPHY_MODE_USB3_ONLY) { + qmp_combo_usb_power_on(qmp->usb_phy); + if (!qmp->usb_init_count) + qmp->usb_init_count++; + } + + if (new_mode == QMPPHY_MODE_DP_ONLY || new_mode == QMPPHY_MODE_USB3DP) { + if (qmp->dp_init_count) + cfg->dp_aux_init(qmp); + } + } + + return 0; +} + +static void qmp_combo_typec_switch_unregister(void *data) { struct qmp_combo *qmp = data; typec_switch_unregister(qmp->sw); } -static int qmp_combo_typec_switch_register(struct qmp_combo *qmp) +static void qmp_combo_typec_mux_unregister(void *data) +{ + struct qmp_combo *qmp = data; + + typec_mux_unregister(qmp->mux); +} + +static int qmp_combo_typec_register(struct qmp_combo *qmp) { struct typec_switch_desc sw_desc = {}; + struct typec_mux_desc mux_desc = { }; struct device *dev = qmp->dev; + int ret; sw_desc.drvdata = qmp; sw_desc.fwnode = dev->fwnode; @@ -3823,10 +3918,23 @@ static int qmp_combo_typec_switch_register(struct qmp_combo *qmp) return PTR_ERR(qmp->sw); } - return devm_add_action_or_reset(dev, qmp_combo_typec_unregister, qmp); + ret = devm_add_action_or_reset(dev, qmp_combo_typec_switch_unregister, qmp); + if (ret) + return ret; + + mux_desc.drvdata = qmp; + mux_desc.fwnode = dev->fwnode; + mux_desc.set = qmp_combo_typec_mux_set; + qmp->mux = typec_mux_register(dev, &mux_desc); + if (IS_ERR(qmp->mux)) { + dev_err(dev, "Unable to register typec mux: %pe\n", qmp->mux); + return PTR_ERR(qmp->mux); + } + + return devm_add_action_or_reset(dev, qmp_combo_typec_mux_unregister, qmp); } #else -static int qmp_combo_typec_switch_register(struct qmp_combo *qmp) +static int qmp_combo_typec_register(struct qmp_combo *qmp) { return 0; } @@ -4059,7 +4167,7 @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) goto err_node_put; - ret = qmp_combo_typec_switch_register(qmp); + ret = qmp_combo_typec_register(qmp); if (ret) goto err_node_put; From ab9c8aeb2d208381a7c948ea2f753cbe8a451502 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 8 Aug 2025 22:52:05 +0100 Subject: [PATCH 37/64] dt-bindings: phy: renesas,usb2-phy: Add RZ/T2H and RZ/N2H support Document the USB2 PHY controller for the Renesas RZ/T2H (r9a09g077) and RZ/N2H (r9a09g087) SoCs. These SoCs share the same PHY block, which is similar to the one on RZ/G2L but differs in clocks, resets, and register bits. To account for these differences, a new compatible string `renesas,usb2-phy-r9a09g077` is introduced. The RZ/N2H SoC uses the same PHY as RZ/T2H, so it reuses the RZ/T2H compatible string as a fallback. Signed-off-by: Lad Prabhakar Acked-by: Conor Dooley Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20250808215209.3692744-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Vinod Koul --- .../bindings/phy/renesas,usb2-phy.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml b/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml index f45c5f039ae8..179cb4bfc424 100644 --- a/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml @@ -44,6 +44,12 @@ properties: - const: renesas,usb2-phy-r9a09g056 # RZ/V2N - const: renesas,usb2-phy-r9a09g057 + - const: renesas,usb2-phy-r9a09g077 # RZ/T2H + + - items: + - const: renesas,usb2-phy-r9a09g087 # RZ/N2H + - const: renesas,usb2-phy-r9a09g077 + reg: maxItems: 1 @@ -120,6 +126,17 @@ allOf: required: - resets + - if: + properties: + compatible: + contains: + const: renesas,usb2-phy-r9a09g077 + then: + properties: + clocks: + minItems: 2 + resets: false + additionalProperties: false examples: From f75806d26318c08ddb79652cce89086e4da17257 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 8 Aug 2025 22:52:06 +0100 Subject: [PATCH 38/64] phy: renesas: rcar-gen3-usb2: store drvdata pointer in channel Store the SoC-specific driver data pointer (struct rcar_gen3_phy_drv_data) directly in struct rcar_gen3_chan instead of copying individual flags into separate channel members. Obtain the drvdata with of_device_get_match_data() in probe and assign it to channel->phy_data. Update all call sites to reference `channel->phy_data->*` for SoC-specific behaviour (for example no_adp_ctrl and utmi_ctrl). Remove the redundant soc_no_adp_ctrl and utmi_ctrl fields from struct rcar_gen3_chan. This simplifies the probe path, reduces duplication, and makes it easier to extend the driver with additional platform-specific fields in the future. Signed-off-by: Lad Prabhakar Link: https://lore.kernel.org/r/20250808215209.3692744-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 27 ++++++++++-------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 47beb94cd424..7ac56102aed0 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -122,6 +122,7 @@ struct rcar_gen3_phy { struct rcar_gen3_chan { void __iomem *base; struct device *dev; /* platform_device's device */ + const struct rcar_gen3_phy_drv_data *phy_data; struct extcon_dev *extcon; struct rcar_gen3_phy rphys[NUM_OF_PHYS]; struct regulator *vbus; @@ -133,8 +134,6 @@ struct rcar_gen3_chan { bool extcon_host; bool is_otg_channel; bool uses_otg_pins; - bool soc_no_adp_ctrl; - bool utmi_ctrl; }; struct rcar_gen3_phy_drv_data { @@ -204,7 +203,7 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) u32 val; dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); - if (ch->soc_no_adp_ctrl) { + if (ch->phy_data->no_adp_ctrl) { if (ch->vbus) regulator_hardware_enable(ch->vbus, vbus); @@ -290,7 +289,7 @@ static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) if (!ch->uses_otg_pins) return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true; - if (ch->soc_no_adp_ctrl) + if (ch->phy_data->no_adp_ctrl) return !!(readl(ch->base + USB2_LINECTRL1) & USB2_LINECTRL1_USB2_IDMON); return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); @@ -421,7 +420,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) USB2_LINECTRL1_DMRPD_EN | USB2_LINECTRL1_DM_RPD; writel(val, usb2_base + USB2_LINECTRL1); - if (!ch->soc_no_adp_ctrl) { + if (!ch->phy_data->no_adp_ctrl) { val = readl(usb2_base + USB2_VBCTRL); val &= ~USB2_VBCTRL_OCCLREN; writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); @@ -487,7 +486,7 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) if (rphy->int_enable_bits) rcar_gen3_init_otg(channel); - if (channel->utmi_ctrl) { + if (channel->phy_data->utmi_ctrl) { val = readl(usb2_base + USB2_REGEN_CG_CTRL) | USB2_REGEN_CG_CTRL_UPHY_WEN; writel(val, usb2_base + USB2_REGEN_CG_CTRL); @@ -730,7 +729,6 @@ static int rcar_gen3_phy_usb2_init_bus(struct rcar_gen3_chan *channel) static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) { - const struct rcar_gen3_phy_drv_data *phy_data; struct device *dev = &pdev->dev; struct rcar_gen3_chan *channel; struct phy_provider *provider; @@ -773,8 +771,8 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) */ pm_runtime_enable(dev); - phy_data = of_device_get_match_data(dev); - if (!phy_data) { + channel->phy_data = of_device_get_match_data(dev); + if (!channel->phy_data) { ret = -EINVAL; goto error; } @@ -782,22 +780,19 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) platform_set_drvdata(pdev, channel); channel->dev = dev; - if (phy_data->init_bus) { + if (channel->phy_data->init_bus) { ret = rcar_gen3_phy_usb2_init_bus(channel); if (ret) goto error; } - channel->soc_no_adp_ctrl = phy_data->no_adp_ctrl; - if (phy_data->no_adp_ctrl) + if (channel->phy_data->no_adp_ctrl) channel->obint_enable_bits = USB2_OBINT_IDCHG_EN; - channel->utmi_ctrl = phy_data->utmi_ctrl; - spin_lock_init(&channel->lock); for (i = 0; i < NUM_OF_PHYS; i++) { channel->rphys[i].phy = devm_phy_create(dev, NULL, - phy_data->phy_usb2_ops); + channel->phy_data->phy_usb2_ops); if (IS_ERR(channel->rphys[i].phy)) { dev_err(dev, "Failed to create USB2 PHY\n"); ret = PTR_ERR(channel->rphys[i].phy); @@ -808,7 +803,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) phy_set_drvdata(channel->rphys[i].phy, &channel->rphys[i]); } - if (channel->soc_no_adp_ctrl && channel->is_otg_channel) + if (channel->phy_data->no_adp_ctrl && channel->is_otg_channel) channel->vbus = devm_regulator_get_exclusive(dev, "vbus"); else channel->vbus = devm_regulator_get_optional(dev, "vbus"); From 4b7aa47e4c2c921b9511389bf42a4e30d64373e6 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 8 Aug 2025 22:52:07 +0100 Subject: [PATCH 39/64] phy: renesas: rcar-gen3-usb2: Allow SoC-specific OBINT bits via phy_data Update the PHY driver to support SoC-specific OBINT enable bits by introducing the `obint_enable_bits` field in the `rcar_gen3_phy_drv_data` structure. This allows each SoC to specify bits required. Signed-off-by: Lad Prabhakar Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250808215209.3692744-4-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 27 ++++++++++++------------ 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 7ac56102aed0..a37af7d8f2f4 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -71,8 +71,7 @@ /* OBINTSTA and OBINTEN */ #define USB2_OBINT_SESSVLDCHG BIT(12) #define USB2_OBINT_IDDIGCHG BIT(11) -#define USB2_OBINT_BITS (USB2_OBINT_SESSVLDCHG | \ - USB2_OBINT_IDDIGCHG) +#define USB2_OBINT_IDCHG_EN BIT(0) /* RZ/G2L specific */ /* VBCTRL */ #define USB2_VBCTRL_OCCLREN BIT(16) @@ -93,7 +92,6 @@ #define USB2_ADPCTRL_DRVVBUS BIT(4) /* RZ/G2L specific */ -#define USB2_OBINT_IDCHG_EN BIT(0) #define USB2_LINECTRL1_USB2_IDMON BIT(0) #define NUM_OF_PHYS 4 @@ -130,7 +128,6 @@ struct rcar_gen3_chan { struct work_struct work; spinlock_t lock; /* protects access to hardware and driver data structure. */ enum usb_dr_mode dr_mode; - u32 obint_enable_bits; bool extcon_host; bool is_otg_channel; bool uses_otg_pins; @@ -141,6 +138,7 @@ struct rcar_gen3_phy_drv_data { bool no_adp_ctrl; bool init_bus; bool utmi_ctrl; + u32 obint_enable_bits; }; /* @@ -225,9 +223,9 @@ static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable) u32 val = readl(usb2_base + USB2_OBINTEN); if (ch->uses_otg_pins && enable) - val |= ch->obint_enable_bits; + val |= ch->phy_data->obint_enable_bits; else - val &= ~ch->obint_enable_bits; + val &= ~ch->phy_data->obint_enable_bits; writel(val, usb2_base + USB2_OBINTEN); } @@ -430,7 +428,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) mdelay(20); writel(0xffffffff, usb2_base + USB2_OBINTSTA); - writel(ch->obint_enable_bits, usb2_base + USB2_OBINTEN); + writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTEN); rcar_gen3_device_recognition(ch); } @@ -450,9 +448,9 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) scoped_guard(spinlock, &ch->lock) { status = readl(usb2_base + USB2_OBINTSTA); - if (status & ch->obint_enable_bits) { + if (status & ch->phy_data->obint_enable_bits) { dev_vdbg(dev, "%s: %08x\n", __func__, status); - writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA); + writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTSTA); rcar_gen3_device_recognition(ch); ret = IRQ_HANDLED; } @@ -591,28 +589,35 @@ static const struct phy_ops rz_g1c_phy_usb2_ops = { static const struct rcar_gen3_phy_drv_data rcar_gen3_phy_usb2_data = { .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, .no_adp_ctrl = false, + .obint_enable_bits = USB2_OBINT_SESSVLDCHG | + USB2_OBINT_IDDIGCHG, }; static const struct rcar_gen3_phy_drv_data rz_g1c_phy_usb2_data = { .phy_usb2_ops = &rz_g1c_phy_usb2_ops, .no_adp_ctrl = false, + .obint_enable_bits = USB2_OBINT_SESSVLDCHG | + USB2_OBINT_IDDIGCHG, }; static const struct rcar_gen3_phy_drv_data rz_g2l_phy_usb2_data = { .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, .no_adp_ctrl = true, + .obint_enable_bits = USB2_OBINT_IDCHG_EN, }; static const struct rcar_gen3_phy_drv_data rz_g3s_phy_usb2_data = { .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, .no_adp_ctrl = true, .init_bus = true, + .obint_enable_bits = USB2_OBINT_IDCHG_EN, }; static const struct rcar_gen3_phy_drv_data rz_v2h_phy_usb2_data = { .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, .no_adp_ctrl = true, .utmi_ctrl = true, + .obint_enable_bits = USB2_OBINT_IDCHG_EN, }; static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { @@ -747,7 +752,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) if (IS_ERR(channel->base)) return PTR_ERR(channel->base); - channel->obint_enable_bits = USB2_OBINT_BITS; channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node); if (channel->dr_mode != USB_DR_MODE_UNKNOWN) { channel->is_otg_channel = true; @@ -786,9 +790,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) goto error; } - if (channel->phy_data->no_adp_ctrl) - channel->obint_enable_bits = USB2_OBINT_IDCHG_EN; - spin_lock_init(&channel->lock); for (i = 0; i < NUM_OF_PHYS; i++) { channel->rphys[i].phy = devm_phy_create(dev, NULL, From b725741f1c21e8507a58ae86c5a80ca383f96852 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 8 Aug 2025 22:52:08 +0100 Subject: [PATCH 40/64] phy: renesas: rcar-gen3-usb2: Add support for RZ/T2H SoC Add initial support for the Renesas RZ/T2H SoC to the R-Car Gen3 USB2 PHY driver. The RZ/T2H SoC requires configuration of additional hardware-specific bits for proper VBUS level control and OTG operation. Introduce the `vblvl_ctrl` flag in the SoC-specific driver data to enable handling of VBUS level selection logic using `VBCTRL.VBLVL` bits. This is required for managing the VBUS status detection and drive logic based on SoC-specific needs. Signed-off-by: Lad Prabhakar Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250808215209.3692744-5-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 82 ++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 7 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index a37af7d8f2f4..8caef9cb228c 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -9,6 +9,8 @@ * Copyright (C) 2014 Cogent Embedded, Inc. */ +#include +#include #include #include #include @@ -69,13 +71,20 @@ #define USB2_COMMCTRL_OTG_PERI BIT(31) /* 1 = Peripheral mode */ /* OBINTSTA and OBINTEN */ +#define USB2_OBINTSTA_CLEAR GENMASK(31, 0) #define USB2_OBINT_SESSVLDCHG BIT(12) #define USB2_OBINT_IDDIGCHG BIT(11) +#define USB2_OBINT_VBSTAINT BIT(3) #define USB2_OBINT_IDCHG_EN BIT(0) /* RZ/G2L specific */ /* VBCTRL */ +#define USB2_VBCTRL_VBSTA_MASK GENMASK(31, 28) +#define USB2_VBCTRL_VBSTA_DEFAULT 2 +#define USB2_VBCTRL_VBLVL_MASK GENMASK(23, 20) +#define USB2_VBCTRL_VBLVL(m) FIELD_PREP_CONST(USB2_VBCTRL_VBLVL_MASK, (m)) #define USB2_VBCTRL_OCCLREN BIT(16) #define USB2_VBCTRL_DRVVBUSSEL BIT(8) +#define USB2_VBCTRL_SIDDQREL BIT(2) #define USB2_VBCTRL_VBOUT BIT(0) /* LINECTRL1 */ @@ -88,6 +97,7 @@ /* ADPCTRL */ #define USB2_ADPCTRL_OTGSESSVLD BIT(20) #define USB2_ADPCTRL_IDDIG BIT(19) +#define USB2_ADPCTRL_VBUSVALID BIT(18) #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ #define USB2_ADPCTRL_DRVVBUS BIT(4) @@ -138,6 +148,7 @@ struct rcar_gen3_phy_drv_data { bool no_adp_ctrl; bool init_bus; bool utmi_ctrl; + bool vblvl_ctrl; u32 obint_enable_bits; }; @@ -201,7 +212,7 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) u32 val; dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); - if (ch->phy_data->no_adp_ctrl) { + if (ch->phy_data->no_adp_ctrl || ch->phy_data->vblvl_ctrl) { if (ch->vbus) regulator_hardware_enable(ch->vbus, vbus); @@ -284,6 +295,16 @@ static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch) static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) { + if (ch->phy_data->vblvl_ctrl) { + bool vbus_valid; + bool device; + + device = !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); + vbus_valid = !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_VBUSVALID); + + return !(device && !vbus_valid); + } + if (!ch->uses_otg_pins) return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true; @@ -419,11 +440,20 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) writel(val, usb2_base + USB2_LINECTRL1); if (!ch->phy_data->no_adp_ctrl) { - val = readl(usb2_base + USB2_VBCTRL); - val &= ~USB2_VBCTRL_OCCLREN; - writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); - val = readl(usb2_base + USB2_ADPCTRL); - writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); + if (ch->phy_data->vblvl_ctrl) { + val = readl(usb2_base + USB2_VBCTRL); + val = (val & ~USB2_VBCTRL_VBLVL_MASK) | USB2_VBCTRL_VBLVL(2); + writel(val, usb2_base + USB2_VBCTRL); + val = readl(usb2_base + USB2_ADPCTRL); + writel(val | USB2_ADPCTRL_IDPULLUP | USB2_ADPCTRL_DRVVBUS, + usb2_base + USB2_ADPCTRL); + } else { + val = readl(usb2_base + USB2_VBCTRL); + val &= ~USB2_VBCTRL_OCCLREN; + writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); + val = readl(usb2_base + USB2_ADPCTRL); + writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); + } } mdelay(20); @@ -433,6 +463,23 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) rcar_gen3_device_recognition(ch); } +static void rcar_gen3_configure_vblvl_ctrl(struct rcar_gen3_chan *ch) +{ + void __iomem *usb2_base = ch->base; + u32 val; + + if (!ch->phy_data->vblvl_ctrl) + return; + + val = readl(usb2_base + USB2_VBCTRL); + if ((val & USB2_VBCTRL_VBSTA_MASK) == + FIELD_PREP_CONST(USB2_VBCTRL_VBSTA_MASK, USB2_VBCTRL_VBSTA_DEFAULT)) + val &= ~USB2_VBCTRL_VBLVL_MASK; + else + val |= USB2_VBCTRL_VBLVL(USB2_VBCTRL_VBSTA_DEFAULT); + writel(val, usb2_base + USB2_VBCTRL); +} + static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) { struct rcar_gen3_chan *ch = _ch; @@ -450,8 +497,12 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) status = readl(usb2_base + USB2_OBINTSTA); if (status & ch->phy_data->obint_enable_bits) { dev_vdbg(dev, "%s: %08x\n", __func__, status); - writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTSTA); + if (ch->phy_data->vblvl_ctrl) + writel(USB2_OBINTSTA_CLEAR, usb2_base + USB2_OBINTSTA); + else + writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTSTA); rcar_gen3_device_recognition(ch); + rcar_gen3_configure_vblvl_ctrl(ch); ret = IRQ_HANDLED; } } @@ -484,6 +535,13 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) if (rphy->int_enable_bits) rcar_gen3_init_otg(channel); + if (channel->phy_data->vblvl_ctrl) { + /* SIDDQ mode release */ + writel(readl(usb2_base + USB2_VBCTRL) | USB2_VBCTRL_SIDDQREL, + usb2_base + USB2_VBCTRL); + udelay(250); + } + if (channel->phy_data->utmi_ctrl) { val = readl(usb2_base + USB2_REGEN_CG_CTRL) | USB2_REGEN_CG_CTRL_UPHY_WEN; writel(val, usb2_base + USB2_REGEN_CG_CTRL); @@ -613,6 +671,12 @@ static const struct rcar_gen3_phy_drv_data rz_g3s_phy_usb2_data = { .obint_enable_bits = USB2_OBINT_IDCHG_EN, }; +static const struct rcar_gen3_phy_drv_data rz_t2h_phy_usb2_data = { + .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, + .vblvl_ctrl = true, + .obint_enable_bits = USB2_OBINT_IDCHG_EN | USB2_OBINT_VBSTAINT, +}; + static const struct rcar_gen3_phy_drv_data rz_v2h_phy_usb2_data = { .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, .no_adp_ctrl = true, @@ -645,6 +709,10 @@ static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { .compatible = "renesas,usb2-phy-r9a09g057", .data = &rz_v2h_phy_usb2_data, }, + { + .compatible = "renesas,usb2-phy-r9a09g077", + .data = &rz_t2h_phy_usb2_data, + }, { .compatible = "renesas,rzg2l-usb2-phy", .data = &rz_g2l_phy_usb2_data, From 5f54134428b48261151c725c64b40be54e373345 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 8 Aug 2025 22:52:09 +0100 Subject: [PATCH 41/64] phy: renesas: rcar-gen3-usb2: Move debug print after register value is updated Relocate the debug print in rcar_gen3_enable_vbus_ctrl() to appear after the `val` variable is assigned and updated based on the VBUS state. This ensures that the debug log reflects the actual register value being written, improving debugging accuracy. Signed-off-by: Lad Prabhakar Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250808215209.3692744-6-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 8caef9cb228c..7b4a6e8b7508 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -211,7 +211,6 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) u32 vbus_ctrl_val = USB2_ADPCTRL_DRVVBUS; u32 val; - dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); if (ch->phy_data->no_adp_ctrl || ch->phy_data->vblvl_ctrl) { if (ch->vbus) regulator_hardware_enable(ch->vbus, vbus); @@ -225,6 +224,7 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) val |= vbus_ctrl_val; else val &= ~vbus_ctrl_val; + dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); writel(val, usb2_base + vbus_ctrl_reg); } From ce489635960a6a3fcb0abe0918994f2d8deb02ed Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Wed, 30 Jul 2025 15:27:25 +0800 Subject: [PATCH 42/64] dt-bindings: phy: Add eDP PHY compatible for QCS8300 Add compatible string for the supported eDP PHY on QCS8300 platform. QCS8300 have the same eDP PHY with SA8775P. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yongxing Mou Link: https://lore.kernel.org/r/20250730072725.1433360-1-quic_yongmou@quicinc.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,edp-phy.yaml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml index 293fb6a9b1c3..eb97181cbb95 100644 --- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml @@ -16,13 +16,18 @@ description: properties: compatible: - enum: - - qcom,sa8775p-edp-phy - - qcom,sc7280-edp-phy - - qcom,sc8180x-edp-phy - - qcom,sc8280xp-dp-phy - - qcom,sc8280xp-edp-phy - - qcom,x1e80100-dp-phy + oneOf: + - enum: + - qcom,sa8775p-edp-phy + - qcom,sc7280-edp-phy + - qcom,sc8180x-edp-phy + - qcom,sc8280xp-dp-phy + - qcom,sc8280xp-edp-phy + - qcom,x1e80100-dp-phy + - items: + - enum: + - qcom,qcs8300-edp-phy + - const: qcom,sa8775p-edp-phy reg: items: From 38404274bbee1f0001a490c0dc98aac32a4d7c9d Mon Sep 17 00:00:00 2001 From: Akhilesh Patil Date: Thu, 24 Jul 2025 16:05:07 +0530 Subject: [PATCH 43/64] phy: ingenic: use core driver model helper to handle probe errors Use core driver model helper dev_err_probe() defined at drivers/base/core.c in driver probe path to propagate errors. standardize and improve the code of deferred probe error handling using this helper for ingenic usb phy driver. Inspired by, commit a787e5400a1ce ("driver core: add device probe log helper") Signed-off-by: Akhilesh Patil Cc: Andrzej Hajda Link: https://lore.kernel.org/r/aIIMW971BYsIk4As@bhairav-test.ee.iitb.ac.in Signed-off-by: Vinod Koul --- drivers/phy/ingenic/phy-ingenic-usb.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/phy/ingenic/phy-ingenic-usb.c b/drivers/phy/ingenic/phy-ingenic-usb.c index eb2721f72a4c..7e62d46850fd 100644 --- a/drivers/phy/ingenic/phy-ingenic-usb.c +++ b/drivers/phy/ingenic/phy-ingenic-usb.c @@ -339,17 +339,13 @@ static int ingenic_usb_phy_probe(struct platform_device *pdev) priv->clk = devm_clk_get(dev, NULL); if (IS_ERR(priv->clk)) { err = PTR_ERR(priv->clk); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get clock\n"); - return err; + return dev_err_probe(dev, err, "Failed to get clock\n"); } priv->vcc_supply = devm_regulator_get(dev, "vcc"); if (IS_ERR(priv->vcc_supply)) { err = PTR_ERR(priv->vcc_supply); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get regulator\n"); - return err; + return dev_err_probe(dev, err, "Failed to get regulator\n"); } priv->phy = devm_phy_create(dev, NULL, &ingenic_usb_phy_ops); From 0c4916aadb8df892399eec99f775655c31049195 Mon Sep 17 00:00:00 2001 From: Nitin Rawat Date: Sat, 30 Aug 2025 12:33:52 +0530 Subject: [PATCH 44/64] phy: qcom-qmp-ufs: Add regulator load voting for UFS QMP PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On certain SoCs, power regulators are shared between the QMP UFS PHY and other IP blocks. To ensure proper operation, the regulator framework must be informed of the UFS PHY's load requirements. This is essential because the regulator's operating mode—whether Low Power or High Power—depends on the maximum expected load at any given time, which the regulator driver needs to manage accordingly. To support this, replace devm_regulator_bulk_get() with devm_regulator_bulk_get_const() and inline the qmp_ufs_vreg_init() function. additionally replace the array of regulator names with a bulk regulator data structure, and utilize the init_load_uA field provided by the regulator framework. This ensures that regulator_set_load() is automatically invoked before the first enable operation. Reviewed-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Signed-off-by: Nitin Rawat Link: https://lore.kernel.org/r/20250830070353.2694-2-nitin.rawat@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 29 +++++++------------------ 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 9c69c77d10c8..aaa88ca0ef07 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -1107,7 +1107,7 @@ struct qmp_phy_cfg { const struct qmp_phy_cfg_tbls tbls_hs_overlay[NUM_OVERLAY]; /* regulators to be requested */ - const char * const *vreg_list; + const struct regulator_bulk_data *vreg_list; int num_vregs; /* array of registers with different offsets */ @@ -1164,9 +1164,10 @@ static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) readl(base + offset); } -/* list of regulators */ -static const char * const qmp_phy_vreg_l[] = { - "vdda-phy", "vdda-pll", +/* Default regulator bulk data (no load used) */ +static const struct regulator_bulk_data qmp_phy_vreg_l[] = { + { .supply = "vdda-phy" }, + { .supply = "vdda-pll" }, }; static const struct qmp_ufs_offsets qmp_ufs_offsets = { @@ -1890,22 +1891,6 @@ static const struct phy_ops qcom_qmp_ufs_phy_ops = { .owner = THIS_MODULE, }; -static int qmp_ufs_vreg_init(struct qmp_ufs *qmp) -{ - const struct qmp_phy_cfg *cfg = qmp->cfg; - struct device *dev = qmp->dev; - int num = cfg->num_vregs; - int i; - - qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); - if (!qmp->vregs) - return -ENOMEM; - - for (i = 0; i < num; i++) - qmp->vregs[i].supply = cfg->vreg_list[i]; - - return devm_regulator_bulk_get(dev, num, qmp->vregs); -} static int qmp_ufs_clk_init(struct qmp_ufs *qmp) { @@ -2068,7 +2053,9 @@ static int qmp_ufs_probe(struct platform_device *pdev) if (ret) return ret; - ret = qmp_ufs_vreg_init(qmp); + ret = devm_regulator_bulk_get_const(dev, qmp->cfg->num_vregs, + qmp->cfg->vreg_list, + &qmp->vregs); if (ret) return ret; From df4beac9da5f162770c8563d11cda327d748c20b Mon Sep 17 00:00:00 2001 From: Nitin Rawat Date: Sat, 30 Aug 2025 12:33:53 +0530 Subject: [PATCH 45/64] phy: qcom-qmp-ufs: Add PHY and PLL regulator load Add phy and pll regulator load voting support for all supported platforms by introducing dedicated regulator bulk data arrays with their load values. This ensures stable operation and proper power management for these platforms where regulators are shared between the QMP UFS PHY and other IP blocks by setting appropriate regulator load currents during PHY operations. Signed-off-by: Nitin Rawat Acked-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20250830070353.2694-3-nitin.rawat@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 138 ++++++++++++++++++------ 1 file changed, 104 insertions(+), 34 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index aaa88ca0ef07..8a280433a42b 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -1164,10 +1164,80 @@ static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) readl(base + offset); } -/* Default regulator bulk data (no load used) */ -static const struct regulator_bulk_data qmp_phy_vreg_l[] = { - { .supply = "vdda-phy" }, - { .supply = "vdda-pll" }, +/* Regulator bulk data with load values for specific configurations */ +static const struct regulator_bulk_data msm8996_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 51400 }, + { .supply = "vdda-pll", .init_load_uA = 14600 }, +}; + +static const struct regulator_bulk_data sa8775p_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 137000 }, + { .supply = "vdda-pll", .init_load_uA = 18300 }, +}; + +static const struct regulator_bulk_data sc7280_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 97500 }, + { .supply = "vdda-pll", .init_load_uA = 18400 }, +}; + +static const struct regulator_bulk_data sc8280xp_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 85700 }, + { .supply = "vdda-pll", .init_load_uA = 18300 }, +}; + +static const struct regulator_bulk_data sdm845_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 51400 }, + { .supply = "vdda-pll", .init_load_uA = 14600 }, +}; + +static const struct regulator_bulk_data sm6115_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 51400 }, + { .supply = "vdda-pll", .init_load_uA = 14200 }, +}; + +static const struct regulator_bulk_data sm7150_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 62900 }, + { .supply = "vdda-pll", .init_load_uA = 18300 }, +}; + +static const struct regulator_bulk_data sm8150_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 90200 }, + { .supply = "vdda-pll", .init_load_uA = 19000 }, +}; + +static const struct regulator_bulk_data sm8250_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 89900 }, + { .supply = "vdda-pll", .init_load_uA = 18800 }, +}; + +static const struct regulator_bulk_data sm8350_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 91600 }, + { .supply = "vdda-pll", .init_load_uA = 19000 }, +}; + +static const struct regulator_bulk_data sm8450_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 173000 }, + { .supply = "vdda-pll", .init_load_uA = 24900 }, +}; + +static const struct regulator_bulk_data sm8475_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 213030 }, + { .supply = "vdda-pll", .init_load_uA = 18340 }, +}; + +static const struct regulator_bulk_data sm8550_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 188000 }, + { .supply = "vdda-pll", .init_load_uA = 18300 }, +}; + +static const struct regulator_bulk_data sm8650_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 205000 }, + { .supply = "vdda-pll", .init_load_uA = 17500 }, +}; + +static const struct regulator_bulk_data sm8750_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 213000 }, + { .supply = "vdda-pll", .init_load_uA = 18300 }, }; static const struct qmp_ufs_offsets qmp_ufs_offsets = { @@ -1203,8 +1273,8 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = { .rx_num = ARRAY_SIZE(msm8996_ufsphy_rx), }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = msm8996_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(msm8996_ufsphy_vreg_l), .regs = ufsphy_v2_regs_layout, @@ -1240,8 +1310,8 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sa8775p_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sa8775p_ufsphy_vreg_l), .regs = ufsphy_v5_regs_layout, }; @@ -1274,8 +1344,8 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sc7280_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sc7280_ufsphy_vreg_l), .regs = ufsphy_v4_regs_layout, }; @@ -1308,8 +1378,8 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sc8280xp_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sc8280xp_ufsphy_vreg_l), .regs = ufsphy_v5_regs_layout, }; @@ -1333,8 +1403,8 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { .serdes = sdm845_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sdm845_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sdm845_ufsphy_vreg_l), .regs = ufsphy_v3_regs_layout, .no_pcs_sw_reset = true, @@ -1360,8 +1430,8 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = { .serdes = sm6115_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm6115_ufsphy_hs_b_serdes), }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm6115_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm6115_ufsphy_vreg_l), .regs = ufsphy_v2_regs_layout, .no_pcs_sw_reset = true, @@ -1387,8 +1457,8 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = { .serdes = sdm845_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm7150_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm7150_ufsphy_vreg_l), .regs = ufsphy_v3_regs_layout, .no_pcs_sw_reset = true, @@ -1423,8 +1493,8 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8150_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8150_ufsphy_vreg_l), .regs = ufsphy_v4_regs_layout, }; @@ -1457,8 +1527,8 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8250_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8250_ufsphy_vreg_l), .regs = ufsphy_v4_regs_layout, }; @@ -1491,8 +1561,8 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8350_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8350_ufsphy_vreg_l), .regs = ufsphy_v5_regs_layout, }; @@ -1525,8 +1595,8 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8450_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8450_ufsphy_vreg_l), .regs = ufsphy_v5_regs_layout, }; @@ -1561,8 +1631,8 @@ static const struct qmp_phy_cfg sm8475_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8475_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8475_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8475_ufsphy_vreg_l), .regs = ufsphy_v6_regs_layout, }; @@ -1606,8 +1676,8 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g5_pcs), .max_gear = UFS_HS_G5, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8550_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8550_ufsphy_vreg_l), .regs = ufsphy_v6_regs_layout, }; @@ -1638,8 +1708,8 @@ static const struct qmp_phy_cfg sm8650_ufsphy_cfg = { .max_gear = UFS_HS_G5, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8650_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8650_ufsphy_vreg_l), .regs = ufsphy_v6_regs_layout, }; @@ -1676,8 +1746,8 @@ static const struct qmp_phy_cfg sm8750_ufsphy_cfg = { .max_gear = UFS_HS_G5, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8750_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8750_ufsphy_vreg_l), .regs = ufsphy_v6_regs_layout, }; From da938e39a81642748db3ec2385e8a53fe03d9bd1 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Thu, 28 Aug 2025 20:23:55 +0800 Subject: [PATCH 46/64] phy: hisilicon: Remove redundant ternary operators Remove redundant ternary operators to clean up the code. Signed-off-by: Liao Yuanhong Link: https://lore.kernel.org/r/20250828122401.17441-2-liaoyuanhong@vivo.com Signed-off-by: Vinod Koul --- drivers/phy/hisilicon/phy-histb-combphy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/hisilicon/phy-histb-combphy.c b/drivers/phy/hisilicon/phy-histb-combphy.c index 7436dcae3981..9dd0bd00b4e4 100644 --- a/drivers/phy/hisilicon/phy-histb-combphy.c +++ b/drivers/phy/hisilicon/phy-histb-combphy.c @@ -73,7 +73,7 @@ static void nano_register_write(struct histb_combphy_priv *priv, static int is_mode_fixed(struct histb_combphy_mode *mode) { - return (mode->fixed != PHY_NONE) ? true : false; + return mode->fixed != PHY_NONE; } static int histb_combphy_set_mode(struct histb_combphy_priv *priv) From e7ec351347b6325f872b9059453c9c9bf22c159c Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Thu, 28 Aug 2025 20:23:56 +0800 Subject: [PATCH 47/64] phy: renesas: rcar-gen3-usb2: Remove redundant ternary operators Remove redundant ternary operators to clean up the code. Signed-off-by: Liao Yuanhong Reviewed-by: Wolfram Sang Link: https://lore.kernel.org/r/20250828122401.17441-3-liaoyuanhong@vivo.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 7b4a6e8b7508..bab2d4dce5b3 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -306,7 +306,7 @@ static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) } if (!ch->uses_otg_pins) - return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true; + return ch->dr_mode != USB_DR_MODE_HOST; if (ch->phy_data->no_adp_ctrl) return !!(readl(ch->base + USB2_LINECTRL1) & USB2_LINECTRL1_USB2_IDMON); From 0c5375b06060fa40a8f8ce2e926bde125fdf6c3b Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Thu, 28 Aug 2025 20:23:57 +0800 Subject: [PATCH 48/64] phy: rockchip: usbdp: Remove redundant ternary operators Remove redundant ternary operators to clean up the code. Signed-off-by: Liao Yuanhong Link: https://lore.kernel.org/r/20250828122401.17441-4-liaoyuanhong@vivo.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-usbdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c index 010e9d2d6fac..fba35510d88c 100644 --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c @@ -666,7 +666,7 @@ static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw, goto unlock_ret; } - udphy->flip = (orien == TYPEC_ORIENTATION_REVERSE) ? true : false; + udphy->flip = orien == TYPEC_ORIENTATION_REVERSE; rk_udphy_set_typec_default_mapping(udphy); rk_udphy_usb_bvalid_enable(udphy, true); From 616fe247bdce4e3a23e3ded4b3be951001ed8039 Mon Sep 17 00:00:00 2001 From: Prashanth K Date: Tue, 26 Aug 2025 16:22:54 +0530 Subject: [PATCH 49/64] phy: qcom: m31-eusb2: Fix the error log while enabling clock While enabling clock, we incorrectly log 'ref clk' as 'cfg ahb clk' Fix this since the devicetree bindings mentions it as ref clock. Signed-off-by: Prashanth K Link: https://lore.kernel.org/r/20250826105254.3758803-1-prashanth.k@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-m31-eusb2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c index bf32572566c4..0a0d2d9fc846 100644 --- a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c @@ -196,7 +196,7 @@ static int m31eusb2_phy_init(struct phy *uphy) ret = clk_prepare_enable(phy->clk); if (ret) { - dev_err(&uphy->dev, "failed to enable cfg ahb clock, %d\n", ret); + dev_err(&uphy->dev, "failed to enable ref clock, %d\n", ret); goto disable_repeater; } From 9bef84d30f1f724191270044a7d045bfc9d6ad97 Mon Sep 17 00:00:00 2001 From: Josua Mayer Date: Tue, 26 Aug 2025 20:32:03 +0200 Subject: [PATCH 50/64] phy: lynx-28g: check return value when calling lynx_28g_pll_get The lynx_28g_pll_get function may return NULL when called with an unsupported submode argument. This function is only called from the lynx_28g_lane_set_{10gbaser,sgmii} functions, and lynx_28g_set_mode checks available modes before setting a protocol. NXP vendor kernel based on v6.6.52 however is missing any checks and connecting a 2.5/5gbase-t ethernet phy can cause null pointer dereference [1]. Check return value at every invocation and abort in the unlikely error case. Further print a warning message the first time lynx_28g_pll_get returns null, to catch this case should it occur after future changes. [1] [ 127.019924] fsl_dpaa2_eth dpni.4 eth5: dpmac_set_protocol(2500base-x) = -ENOTSUPP [ 127.027451] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000014 [ 127.036245] Mem abort info: [ 127.039044] ESR = 0x0000000096000004 [ 127.042794] EC = 0x25: DABT (current EL), IL = 32 bits [ 127.048107] SET = 0, FnV = 0 [ 127.051161] EA = 0, S1PTW = 0 [ 127.054301] FSC = 0x04: level 0 translation fault [ 127.059179] Data abort info: [ 127.062059] ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 [ 127.067547] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 127.072596] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 127.077907] user pgtable: 4k pages, 48-bit VAs, pgdp=00000020816c9000 [ 127.084344] [0000000000000014] pgd=0000000000000000, p4d=0000000000000000 [ 127.091133] Internal error: Oops: 0000000096000004 [#1] PREEMPT SMP [ 127.097390] Modules linked in: cfg80211 rfkill fsl_jr_uio caam_jr dpaa2_caam caamkeyblob_desc crypto_engine caamhash_desc onboard_usb_hub caamalg_desc crct10dif_ce libdes caam error at24 rtc_ds1307 rtc_fsl_ftm_alarm nvmem_layerscape_sfp layerscape_edac_mod dm_mod nfnetlink ip_tables [ 127.122436] CPU: 5 PID: 96 Comm: kworker/u35:0 Not tainted 6.6.52-g3578ef896722 #10 [ 127.130083] Hardware name: SolidRun LX2162A Clearfog (DT) [ 127.135470] Workqueue: events_power_efficient phylink_resolve [ 127.141219] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 127.148170] pc : lynx_28g_set_lane_mode+0x300/0x818 [ 127.153041] lr : lynx_28g_set_lane_mode+0x2fc/0x818 [ 127.157909] sp : ffff8000806f3b80 [ 127.161212] x29: ffff8000806f3b80 x28: 0000000000000000 x27: 0000000000000000 [ 127.168340] x26: ffff29d6c11f3098 x25: 0000000000000000 x24: 0000000000000000 [ 127.175467] x23: ffff29d6c11f31f0 x22: ffff29d6c11f3080 x21: 0000000000000001 [ 127.182595] x20: ffff29d6c11f4c00 x19: 0000000000000000 x18: 0000000000000006 [ 127.189722] x17: 4f4e452d203d2029 x16: 782d657361623030 x15: 3532286c6f636f74 [ 127.196849] x14: 6f72705f7465735f x13: ffffd7a8ff991cc0 x12: 0000000000000acb [ 127.203976] x11: 0000000000000399 x10: ffffd7a8ff9e9cc0 x9 : 0000000000000000 [ 127.211104] x8 : 0000000000000000 x7 : 0000000000000000 x6 : ffff29d6c11f3080 [ 127.218231] x5 : 0000000000000000 x4 : 0000000040800030 x3 : 000000000000034c [ 127.225358] x2 : ffff29d6c11f3080 x1 : 000000000000034c x0 : 0000000000000000 [ 127.232486] Call trace: [ 127.234921] lynx_28g_set_lane_mode+0x300/0x818 [ 127.239443] lynx_28g_set_mode+0x12c/0x148 [ 127.243529] phy_set_mode_ext+0x5c/0xa8 [ 127.247356] lynx_pcs_config+0x64/0x294 [ 127.251184] phylink_major_config+0x184/0x49c [ 127.255532] phylink_resolve+0x2a0/0x5d8 [ 127.259446] process_one_work+0x138/0x248 [ 127.263448] worker_thread+0x320/0x438 [ 127.267187] kthread+0x114/0x118 [ 127.270406] ret_from_fork+0x10/0x20 [ 127.273973] Code: 2a1303e1 aa0603e0 97fffd3b aa0003e5 (b9401400) [ 127.280055] ---[ end trace 0000000000000000 ]--- Signed-off-by: Josua Mayer Link: https://lore.kernel.org/r/20250826-lynx-28g-nullptr-v1-1-e4de0098f822@solid-run.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index f7994e8983c8..c20d2636c5e9 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -188,6 +188,10 @@ static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv, return pll; } + /* no pll supports requested mode, either caller forgot to check + * lynx_28g_supports_lane_mode, or this is a bug. + */ + dev_WARN_ONCE(priv->dev, 1, "no pll for interface %s\n", phy_modes(intf)); return NULL; } @@ -276,8 +280,12 @@ static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane) lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_SGMII, PROTO_SEL_MSK); lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_10_BIT, IF_WIDTH_MSK); - /* Switch to the PLL that works with this interface type */ + /* Find the PLL that works with this interface type */ pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII); + if (unlikely(pll == NULL)) + return; + + /* Switch to the PLL that works with this interface type */ lynx_28g_lane_set_pll(lane, pll); /* Choose the portion of clock net to be used on this lane */ @@ -312,8 +320,12 @@ static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane) lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_XFI, PROTO_SEL_MSK); lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_20_BIT, IF_WIDTH_MSK); - /* Switch to the PLL that works with this interface type */ + /* Find the PLL that works with this interface type */ pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER); + if (unlikely(pll == NULL)) + return; + + /* Switch to the PLL that works with this interface type */ lynx_28g_lane_set_pll(lane, pll); /* Choose the portion of clock net to be used on this lane */ From 3d13e378d465e8ae0be1697005342055b07eaf11 Mon Sep 17 00:00:00 2001 From: Maud Spierings Date: Fri, 22 Aug 2025 11:20:05 +0200 Subject: [PATCH 51/64] dt-bindings: phy: ti,tcan104x-can: Document TI TCAN1051 TCAN1051-Q1 Automotive Fault Protected CAN Transceiver with CAN FD It is pretty much identical to the TCAN1042, add the compatible with fallback on the TCAN1042. Signed-off-by: Maud Spierings Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250822-can_phy3-v1-1-73b3ba1690ee@gocontroll.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml b/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml index 4a8c3829d85d..138923ffedfe 100644 --- a/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml +++ b/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml @@ -18,6 +18,7 @@ properties: - items: - enum: - microchip,ata6561 + - ti,tcan1051 - const: ti,tcan1042 - enum: - ti,tcan1042 From 356590cd61cf89e2420d5628e35b6e73c6b6a770 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 21 Aug 2025 16:59:57 +0100 Subject: [PATCH 52/64] phy: renesas: rcar-gen3-usb2: Fix ID check logic with VBUS valid The existing ID detection logic returned false when both IDDIG and VBUSVALID were set, which caused incorrect role determination in some cases. The condition: !(device && !vbus_valid) did not properly reflect the intended relationship between IDDIG and VBUSVALID signals. Update the logic to: return vbus_valid ? device : !device; This ensures that when VBUS is valid, the role follows the IDDIG value, and when VBUS is not valid, the role is inverted, matching the expected OTG behavior. Fixes: b725741f1c21 ("phy: renesas: rcar-gen3-usb2: Add support for RZ/T2H SoC") Signed-off-by: Lad Prabhakar Link: https://lore.kernel.org/r/20250821155957.1088337-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index bab2d4dce5b3..3f6b480e1092 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -302,7 +302,7 @@ static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) device = !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); vbus_valid = !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_VBUSVALID); - return !(device && !vbus_valid); + return vbus_valid ? device : !device; } if (!ch->uses_otg_pins) From 284fb19a3ffb1083c3ad9c00d29749d09dddb99c Mon Sep 17 00:00:00 2001 From: Devarsh Thakkar Date: Fri, 4 Jul 2025 18:29:14 +0530 Subject: [PATCH 53/64] phy: cadence: cdns-dphy: Fix PLL lock and O_CMN_READY polling PLL lockup and O_CMN_READY assertion can only happen after common state machine gets enabled by programming DPHY_CMN_SSM register, but driver was polling them before the common state machine was enabled which is incorrect. This is as per the DPHY initialization sequence as mentioned in J721E TRM [1] at section "12.7.2.4.1.2.1 Start-up Sequence Timing Diagram". It shows O_CMN_READY polling at the end after common configuration pin setup where the common configuration pin setup step enables state machine as referenced in "Table 12-1533. Common Configuration-Related Setup mentions state machine" To fix this : - Add new function callbacks for polling on PLL lock and O_CMN_READY assertion. - As state machine and clocks get enabled in power_on callback only, move the clock related programming part from configure callback to power_on callback and poll for the PLL lockup and O_CMN_READY assertion after state machine gets enabled. - The configure callback only saves the PLL configuration received from the client driver which will be applied later on in power_on callback. - Add checks to ensure configure is called before power_on and state machine is in disabled state before power_on callback is called. - Disable state machine in power_off so that client driver can re-configure the PLL by following up a power_off, configure, power_on sequence. [1]: https://www.ti.com/lit/zip/spruil1 Cc: stable@vger.kernel.org Fixes: 7a343c8bf4b5 ("phy: Add Cadence D-PHY support") Signed-off-by: Devarsh Thakkar Tested-by: Harikrishna Shenoy Reviewed-by: Tomi Valkeinen Link: https://lore.kernel.org/r/20250704125915.1224738-2-devarsht@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/cdns-dphy.c | 124 +++++++++++++++++++++++--------- 1 file changed, 92 insertions(+), 32 deletions(-) diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c index 33a42e72362e..da8de0a9d086 100644 --- a/drivers/phy/cadence/cdns-dphy.c +++ b/drivers/phy/cadence/cdns-dphy.c @@ -92,6 +92,8 @@ struct cdns_dphy_ops { void (*set_pll_cfg)(struct cdns_dphy *dphy, const struct cdns_dphy_cfg *cfg); unsigned long (*get_wakeup_time_ns)(struct cdns_dphy *dphy); + int (*wait_for_pll_lock)(struct cdns_dphy *dphy); + int (*wait_for_cmn_ready)(struct cdns_dphy *dphy); }; struct cdns_dphy { @@ -101,6 +103,8 @@ struct cdns_dphy { struct clk *pll_ref_clk; const struct cdns_dphy_ops *ops; struct phy *phy; + bool is_configured; + bool is_powered; }; /* Order of bands is important since the index is the band number. */ @@ -186,6 +190,16 @@ static unsigned long cdns_dphy_get_wakeup_time_ns(struct cdns_dphy *dphy) return dphy->ops->get_wakeup_time_ns(dphy); } +static int cdns_dphy_wait_for_pll_lock(struct cdns_dphy *dphy) +{ + return dphy->ops->wait_for_pll_lock ? dphy->ops->wait_for_pll_lock(dphy) : 0; +} + +static int cdns_dphy_wait_for_cmn_ready(struct cdns_dphy *dphy) +{ + return dphy->ops->wait_for_cmn_ready ? dphy->ops->wait_for_cmn_ready(dphy) : 0; +} + static unsigned long cdns_dphy_ref_get_wakeup_time_ns(struct cdns_dphy *dphy) { /* Default wakeup time is 800 ns (in a simulated environment). */ @@ -227,7 +241,6 @@ static unsigned long cdns_dphy_j721e_get_wakeup_time_ns(struct cdns_dphy *dphy) static void cdns_dphy_j721e_set_pll_cfg(struct cdns_dphy *dphy, const struct cdns_dphy_cfg *cfg) { - u32 status; /* * set the PWM and PLL Byteclk divider settings to recommended values @@ -244,13 +257,6 @@ static void cdns_dphy_j721e_set_pll_cfg(struct cdns_dphy *dphy, writel(DPHY_TX_J721E_WIZ_LANE_RSTB, dphy->regs + DPHY_TX_J721E_WIZ_RST_CTRL); - - readl_poll_timeout(dphy->regs + DPHY_TX_J721E_WIZ_PLL_CTRL, status, - (status & DPHY_TX_WIZ_PLL_LOCK), 0, POLL_TIMEOUT_US); - - readl_poll_timeout(dphy->regs + DPHY_TX_J721E_WIZ_STATUS, status, - (status & DPHY_TX_WIZ_O_CMN_READY), 0, - POLL_TIMEOUT_US); } static void cdns_dphy_j721e_set_psm_div(struct cdns_dphy *dphy, u8 div) @@ -258,6 +264,23 @@ static void cdns_dphy_j721e_set_psm_div(struct cdns_dphy *dphy, u8 div) writel(div, dphy->regs + DPHY_TX_J721E_WIZ_PSM_FREQ); } +static int cdns_dphy_j721e_wait_for_pll_lock(struct cdns_dphy *dphy) +{ + u32 status; + + return readl_poll_timeout(dphy->regs + DPHY_TX_J721E_WIZ_PLL_CTRL, status, + status & DPHY_TX_WIZ_PLL_LOCK, 0, POLL_TIMEOUT_US); +} + +static int cdns_dphy_j721e_wait_for_cmn_ready(struct cdns_dphy *dphy) +{ + u32 status; + + return readl_poll_timeout(dphy->regs + DPHY_TX_J721E_WIZ_STATUS, status, + status & DPHY_TX_WIZ_O_CMN_READY, 0, + POLL_TIMEOUT_US); +} + /* * This is the reference implementation of DPHY hooks. Specific integration of * this IP may have to re-implement some of them depending on how they decided @@ -273,6 +296,8 @@ static const struct cdns_dphy_ops j721e_dphy_ops = { .get_wakeup_time_ns = cdns_dphy_j721e_get_wakeup_time_ns, .set_pll_cfg = cdns_dphy_j721e_set_pll_cfg, .set_psm_div = cdns_dphy_j721e_set_psm_div, + .wait_for_pll_lock = cdns_dphy_j721e_wait_for_pll_lock, + .wait_for_cmn_ready = cdns_dphy_j721e_wait_for_cmn_ready, }; static int cdns_dphy_config_from_opts(struct phy *phy, @@ -328,21 +353,36 @@ static int cdns_dphy_validate(struct phy *phy, enum phy_mode mode, int submode, static int cdns_dphy_configure(struct phy *phy, union phy_configure_opts *opts) { struct cdns_dphy *dphy = phy_get_drvdata(phy); - struct cdns_dphy_cfg cfg = { 0 }; - int ret, band_ctrl; - unsigned int reg; + int ret; - ret = cdns_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg); - if (ret) - return ret; + ret = cdns_dphy_config_from_opts(phy, &opts->mipi_dphy, &dphy->cfg); + if (!ret) + dphy->is_configured = true; + + return ret; +} + +static int cdns_dphy_power_on(struct phy *phy) +{ + struct cdns_dphy *dphy = phy_get_drvdata(phy); + int ret; + u32 reg; + + if (!dphy->is_configured || dphy->is_powered) + return -EINVAL; + + clk_prepare_enable(dphy->psm_clk); + clk_prepare_enable(dphy->pll_ref_clk); /* * Configure the internal PSM clk divider so that the DPHY has a * 1MHz clk (or something close). */ ret = cdns_dphy_setup_psm(dphy); - if (ret) - return ret; + if (ret) { + dev_err(&dphy->phy->dev, "Failed to setup PSM with error %d\n", ret); + goto err_power_on; + } /* * Configure attach clk lanes to data lanes: the DPHY has 2 clk lanes @@ -357,40 +397,60 @@ static int cdns_dphy_configure(struct phy *phy, union phy_configure_opts *opts) * Configure the DPHY PLL that will be used to generate the TX byte * clk. */ - cdns_dphy_set_pll_cfg(dphy, &cfg); + cdns_dphy_set_pll_cfg(dphy, &dphy->cfg); - band_ctrl = cdns_dphy_tx_get_band_ctrl(opts->mipi_dphy.hs_clk_rate); - if (band_ctrl < 0) - return band_ctrl; + ret = cdns_dphy_tx_get_band_ctrl(dphy->cfg.hs_clk_rate); + if (ret < 0) { + dev_err(&dphy->phy->dev, "Failed to get band control value with error %d\n", ret); + goto err_power_on; + } - reg = FIELD_PREP(DPHY_BAND_CFG_LEFT_BAND, band_ctrl) | - FIELD_PREP(DPHY_BAND_CFG_RIGHT_BAND, band_ctrl); + reg = FIELD_PREP(DPHY_BAND_CFG_LEFT_BAND, ret) | + FIELD_PREP(DPHY_BAND_CFG_RIGHT_BAND, ret); writel(reg, dphy->regs + DPHY_BAND_CFG); - return 0; -} - -static int cdns_dphy_power_on(struct phy *phy) -{ - struct cdns_dphy *dphy = phy_get_drvdata(phy); - - clk_prepare_enable(dphy->psm_clk); - clk_prepare_enable(dphy->pll_ref_clk); - /* Start TX state machine. */ writel(DPHY_CMN_SSM_EN | DPHY_CMN_TX_MODE_EN, dphy->regs + DPHY_CMN_SSM); + ret = cdns_dphy_wait_for_pll_lock(dphy); + if (ret) { + dev_err(&dphy->phy->dev, "Failed to lock PLL with error %d\n", ret); + goto err_power_on; + } + + ret = cdns_dphy_wait_for_cmn_ready(dphy); + if (ret) { + dev_err(&dphy->phy->dev, "O_CMN_READY signal failed to assert with error %d\n", + ret); + goto err_power_on; + } + + dphy->is_powered = true; + return 0; + +err_power_on: + clk_disable_unprepare(dphy->pll_ref_clk); + clk_disable_unprepare(dphy->psm_clk); + + return ret; } static int cdns_dphy_power_off(struct phy *phy) { struct cdns_dphy *dphy = phy_get_drvdata(phy); + u32 reg; clk_disable_unprepare(dphy->pll_ref_clk); clk_disable_unprepare(dphy->psm_clk); + /* Stop TX state machine. */ + reg = readl(dphy->regs + DPHY_CMN_SSM); + writel(reg & ~DPHY_CMN_SSM_EN, dphy->regs + DPHY_CMN_SSM); + + dphy->is_powered = false; + return 0; } From 2c27aaee934a1b5229152fe33a14f1fdf50da143 Mon Sep 17 00:00:00 2001 From: Devarsh Thakkar Date: Fri, 4 Jul 2025 18:29:15 +0530 Subject: [PATCH 54/64] phy: cadence: cdns-dphy: Update calibration wait time for startup state machine Do read-modify-write so that we re-use the characterized reset value as specified in TRM [1] to program calibration wait time which defines number of cycles to wait for after startup state machine is in bandgap enable state. This fixes PLL lock timeout error faced while using RPi DSI Panel on TI's AM62L and J721E SoC since earlier calibration wait time was getting overwritten to zero value thus failing the PLL to lockup and causing timeout. [1] AM62P TRM (Section 14.8.6.3.2.1.1 DPHY_TX_DPHYTX_CMN0_CMN_DIG_TBIT2): Link: https://www.ti.com/lit/pdf/spruj83 Cc: stable@vger.kernel.org Fixes: 7a343c8bf4b5 ("phy: Add Cadence D-PHY support") Signed-off-by: Devarsh Thakkar Tested-by: Harikrishna Shenoy Reviewed-by: Tomi Valkeinen Link: https://lore.kernel.org/r/20250704125915.1224738-3-devarsht@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/cdns-dphy.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c index da8de0a9d086..24a25606996c 100644 --- a/drivers/phy/cadence/cdns-dphy.c +++ b/drivers/phy/cadence/cdns-dphy.c @@ -30,6 +30,7 @@ #define DPHY_CMN_SSM DPHY_PMA_CMN(0x20) #define DPHY_CMN_SSM_EN BIT(0) +#define DPHY_CMN_SSM_CAL_WAIT_TIME GENMASK(8, 1) #define DPHY_CMN_TX_MODE_EN BIT(9) #define DPHY_CMN_PWM DPHY_PMA_CMN(0x40) @@ -410,7 +411,8 @@ static int cdns_dphy_power_on(struct phy *phy) writel(reg, dphy->regs + DPHY_BAND_CFG); /* Start TX state machine. */ - writel(DPHY_CMN_SSM_EN | DPHY_CMN_TX_MODE_EN, + reg = readl(dphy->regs + DPHY_CMN_SSM); + writel((reg & DPHY_CMN_SSM_CAL_WAIT_TIME) | DPHY_CMN_SSM_EN | DPHY_CMN_TX_MODE_EN, dphy->regs + DPHY_CMN_SSM); ret = cdns_dphy_wait_for_pll_lock(dphy); From cdb2511bf3925ce095c31e1647c12086d34f9cc2 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Tue, 8 Jul 2025 14:30:36 +0800 Subject: [PATCH 55/64] dt-bindings: phy: Add Sophgo CV1800 USB phy The USB phy of Sophgo CV18XX series SoC needs to sense a pin called "VBUS_DET" to get the right operation mode. If this pin is not connected, it only supports setting the mode manually. Add USB phy bindings for Sophgo CV18XX/SG200X series SoC. Signed-off-by: Inochi Amaoto Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250708063038.497473-2-inochiama@gmail.com Signed-off-by: Vinod Koul --- .../bindings/phy/sophgo,cv1800b-usb2-phy.yaml | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/sophgo,cv1800b-usb2-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/sophgo,cv1800b-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/sophgo,cv1800b-usb2-phy.yaml new file mode 100644 index 000000000000..2ff8f85d0282 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/sophgo,cv1800b-usb2-phy.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/sophgo,cv1800b-usb2-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sophgo CV18XX/SG200X USB 2.0 PHY + +maintainers: + - Inochi Amaoto + +properties: + compatible: + const: sophgo,cv1800b-usb2-phy + + reg: + maxItems: 1 + + "#phy-cells": + const: 0 + + clocks: + items: + - description: PHY app clock + - description: PHY stb clock + - description: PHY lpm clock + + clock-names: + items: + - const: app + - const: stb + - const: lpm + + resets: + maxItems: 1 + +required: + - compatible + - "#phy-cells" + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + phy@48 { + compatible = "sophgo,cv1800b-usb2-phy"; + reg = <0x48 0x4>; + #phy-cells = <0>; + clocks = <&clk 93>, <&clk 94>, <&clk 95>; + clock-names = "app", "stb", "lpm"; + resets = <&rst 58>; + }; From f0c6d776f74d1d8bda94f6f042b2919bcd615280 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Tue, 8 Jul 2025 14:30:37 +0800 Subject: [PATCH 56/64] phy: sophgo: Add USB 2.0 PHY driver for Sophgo CV18XX/SG200X Add USB 2.0 PHY driver for Sophgo CV18XX/SG200X. Currently this driver does not support OTG mode as lack of document. Signed-off-by: Inochi Amaoto Tested-by: Alexander Sverdlin Link: https://lore.kernel.org/r/20250708063038.497473-3-inochiama@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/Kconfig | 1 + drivers/phy/Makefile | 1 + drivers/phy/sophgo/Kconfig | 19 +++ drivers/phy/sophgo/Makefile | 2 + drivers/phy/sophgo/phy-cv1800-usb2.c | 170 +++++++++++++++++++++++++++ 5 files changed, 193 insertions(+) create mode 100644 drivers/phy/sophgo/Kconfig create mode 100644 drivers/phy/sophgo/Makefile create mode 100644 drivers/phy/sophgo/phy-cv1800-usb2.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 58c911e1b2d2..678dd0452f0a 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -122,6 +122,7 @@ source "drivers/phy/renesas/Kconfig" source "drivers/phy/rockchip/Kconfig" source "drivers/phy/samsung/Kconfig" source "drivers/phy/socionext/Kconfig" +source "drivers/phy/sophgo/Kconfig" source "drivers/phy/st/Kconfig" source "drivers/phy/starfive/Kconfig" source "drivers/phy/sunplus/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index c670a8dac468..bfb27fb5a494 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -35,6 +35,7 @@ obj-y += allwinner/ \ rockchip/ \ samsung/ \ socionext/ \ + sophgo/ \ st/ \ starfive/ \ sunplus/ \ diff --git a/drivers/phy/sophgo/Kconfig b/drivers/phy/sophgo/Kconfig new file mode 100644 index 000000000000..2c943bbe1f81 --- /dev/null +++ b/drivers/phy/sophgo/Kconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Phy drivers for Sophgo platforms +# + +if ARCH_SOPHGO || COMPILE_TEST + +config PHY_SOPHGO_CV1800_USB2 + tristate "Sophgo CV18XX/SG200X USB 2.0 PHY support" + depends on MFD_SYSCON + depends on USB_SUPPORT + select GENERIC_PHY + help + Enable this to support the USB 2.0 PHY used with + the DWC2 USB controller in Sophgo CV18XX/SG200X + series SoC. + If unsure, say N. + +endif # ARCH_SOPHGO || COMPILE_TEST diff --git a/drivers/phy/sophgo/Makefile b/drivers/phy/sophgo/Makefile new file mode 100644 index 000000000000..318060661759 --- /dev/null +++ b/drivers/phy/sophgo/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PHY_SOPHGO_CV1800_USB2) += phy-cv1800-usb2.o diff --git a/drivers/phy/sophgo/phy-cv1800-usb2.c b/drivers/phy/sophgo/phy-cv1800-usb2.c new file mode 100644 index 000000000000..64f8e37b4b52 --- /dev/null +++ b/drivers/phy/sophgo/phy-cv1800-usb2.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Inochi Amaoto + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_USB_PHY_CTRL 0x048 + +#define PHY_VBUS_POWER_EN BIT(0) +#define PHY_VBUS_POWER BIT(1) +#define PHY_ID_OVERWRITE_EN BIT(6) +#define PHY_ID_OVERWRITE_MODE BIT(7) +#define PHY_ID_OVERWRITE_MODE_HOST FIELD_PREP(BIT(7), 0) +#define PHY_ID_OVERWRITE_MODE_DEVICE FIELD_PREP(BIT(7), 1) + +#define PHY_APP_CLK_RATE 125000000 +#define PHY_LPM_CLK_RATE 12000000 +#define PHY_STB_CLK_RATE 333334 + +struct cv1800_usb_phy { + struct phy *phy; + struct regmap *syscon; + spinlock_t lock; + struct clk *usb_app_clk; + struct clk *usb_lpm_clk; + struct clk *usb_stb_clk; + bool support_otg; +}; + +static int cv1800_usb_phy_set_mode(struct phy *_phy, + enum phy_mode mode, int submode) +{ + struct cv1800_usb_phy *phy = phy_get_drvdata(_phy); + unsigned int regval = 0; + int ret; + + dev_info(&phy->phy->dev, "set mode %d", (int)mode); + + switch (mode) { + case PHY_MODE_USB_DEVICE: + regval = PHY_ID_OVERWRITE_EN | PHY_ID_OVERWRITE_MODE_DEVICE; + regmap_clear_bits(phy->syscon, REG_USB_PHY_CTRL, PHY_VBUS_POWER); + break; + case PHY_MODE_USB_HOST: + regval = PHY_ID_OVERWRITE_EN | PHY_ID_OVERWRITE_MODE_HOST; + regmap_set_bits(phy->syscon, REG_USB_PHY_CTRL, PHY_VBUS_POWER); + break; + case PHY_MODE_USB_OTG: + if (!phy->support_otg) + return 0; + + ret = regmap_read(phy->syscon, REG_USB_PHY_CTRL, ®val); + if (ret) + return ret; + + regval = FIELD_GET(PHY_ID_OVERWRITE_MODE, regval); + break; + default: + return -EINVAL; + } + + return regmap_update_bits(phy->syscon, REG_USB_PHY_CTRL, + PHY_ID_OVERWRITE_EN | PHY_ID_OVERWRITE_MODE, + regval); +} + +static int cv1800_usb_phy_set_clock(struct cv1800_usb_phy *phy) +{ + int ret; + + ret = clk_set_rate(phy->usb_app_clk, PHY_APP_CLK_RATE); + if (ret) + return ret; + + ret = clk_set_rate(phy->usb_lpm_clk, PHY_LPM_CLK_RATE); + if (ret) + return ret; + + return clk_set_rate(phy->usb_stb_clk, PHY_STB_CLK_RATE); +} + +static const struct phy_ops cv1800_usb_phy_ops = { + .set_mode = cv1800_usb_phy_set_mode, + .owner = THIS_MODULE, +}; + +static int cv1800_usb_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device *parent = dev->parent; + struct cv1800_usb_phy *phy; + struct phy_provider *phy_provider; + int ret; + + if (!parent) + return -ENODEV; + + phy = devm_kmalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + phy->syscon = syscon_node_to_regmap(parent->of_node); + if (IS_ERR_OR_NULL(phy->syscon)) + return -ENODEV; + + phy->support_otg = false; + + spin_lock_init(&phy->lock); + + phy->usb_app_clk = devm_clk_get_enabled(dev, "app"); + if (IS_ERR(phy->usb_app_clk)) + return dev_err_probe(dev, PTR_ERR(phy->usb_app_clk), + "Failed to get app clock\n"); + + phy->usb_lpm_clk = devm_clk_get_enabled(dev, "lpm"); + if (IS_ERR(phy->usb_lpm_clk)) + return dev_err_probe(dev, PTR_ERR(phy->usb_lpm_clk), + "Failed to get lpm clock\n"); + + phy->usb_stb_clk = devm_clk_get_enabled(dev, "stb"); + if (IS_ERR(phy->usb_stb_clk)) + return dev_err_probe(dev, PTR_ERR(phy->usb_stb_clk), + "Failed to get stb clock\n"); + + phy->phy = devm_phy_create(dev, NULL, &cv1800_usb_phy_ops); + if (IS_ERR(phy->phy)) + return dev_err_probe(dev, PTR_ERR(phy->phy), + "Failed to create phy\n"); + + ret = cv1800_usb_phy_set_clock(phy); + if (ret) + return ret; + + phy_set_drvdata(phy->phy, phy); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id cv1800_usb_phy_ids[] = { + { .compatible = "sophgo,cv1800b-usb2-phy" }, + { }, +}; +MODULE_DEVICE_TABLE(of, cv1800_usb_phy_ids); + +static struct platform_driver cv1800_usb_phy_driver = { + .probe = cv1800_usb_phy_probe, + .driver = { + .name = "cv1800-usb2-phy", + .of_match_table = cv1800_usb_phy_ids, + }, +}; +module_platform_driver(cv1800_usb_phy_driver); + +MODULE_AUTHOR("Inochi Amaoto "); +MODULE_DESCRIPTION("CV1800/SG2000 SoC USB 2.0 PHY driver"); +MODULE_LICENSE("GPL"); From d337c557581eeb008a06d66ad72152e871967fa5 Mon Sep 17 00:00:00 2001 From: Michael Dege Date: Thu, 3 Jul 2025 13:07:23 +0200 Subject: [PATCH 57/64] phy: renesas: r8a779f0-ether-serdes: add USXGMII mode The initial driver implementation was limited to SGMII and 1GBit/s. The new mode allows speeds up to 2.5GBit/s on R-Car S4-8 SOCs. Signed-off-by: Michael Dege Link: https://lore.kernel.org/r/20250703-renesas-serdes-update-v4-1-1db5629cac2b@renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/r8a779f0-ether-serdes.c | 69 +++++++++++++++++---- 1 file changed, 57 insertions(+), 12 deletions(-) diff --git a/drivers/phy/renesas/r8a779f0-ether-serdes.c b/drivers/phy/renesas/r8a779f0-ether-serdes.c index 3b2d8cef75e5..ed83c46f6d00 100644 --- a/drivers/phy/renesas/r8a779f0-ether-serdes.c +++ b/drivers/phy/renesas/r8a779f0-ether-serdes.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Renesas Ethernet SERDES device driver * - * Copyright (C) 2022 Renesas Electronics Corporation + * Copyright (C) 2022-2025 Renesas Electronics Corporation */ #include @@ -92,17 +92,18 @@ r8a779f0_eth_serdes_common_setting(struct r8a779f0_eth_serdes_channel *channel) { struct r8a779f0_eth_serdes_drv_data *dd = channel->dd; - switch (channel->phy_interface) { - case PHY_INTERFACE_MODE_SGMII: - r8a779f0_eth_serdes_write32(dd->addr, 0x0244, 0x180, 0x0097); - r8a779f0_eth_serdes_write32(dd->addr, 0x01d0, 0x180, 0x0060); - r8a779f0_eth_serdes_write32(dd->addr, 0x01d8, 0x180, 0x2200); - r8a779f0_eth_serdes_write32(dd->addr, 0x01d4, 0x180, 0x0000); - r8a779f0_eth_serdes_write32(dd->addr, 0x01e0, 0x180, 0x003d); - return 0; - default: - return -EOPNOTSUPP; - } + /* Set combination mode */ + r8a779f0_eth_serdes_write32(dd->addr, 0x0244, 0x180, 0x00d7); + r8a779f0_eth_serdes_write32(dd->addr, 0x01cc, 0x180, 0xc200); + r8a779f0_eth_serdes_write32(dd->addr, 0x01c4, 0x180, 0x0042); + r8a779f0_eth_serdes_write32(dd->addr, 0x01c8, 0x180, 0x0000); + r8a779f0_eth_serdes_write32(dd->addr, 0x01dc, 0x180, 0x002f); + r8a779f0_eth_serdes_write32(dd->addr, 0x01d0, 0x180, 0x0060); + r8a779f0_eth_serdes_write32(dd->addr, 0x01d8, 0x180, 0x2200); + r8a779f0_eth_serdes_write32(dd->addr, 0x01d4, 0x180, 0x0000); + r8a779f0_eth_serdes_write32(dd->addr, 0x01e0, 0x180, 0x003d); + + return 0; } static int @@ -155,6 +156,42 @@ r8a779f0_eth_serdes_chan_setting(struct r8a779f0_eth_serdes_channel *channel) r8a779f0_eth_serdes_write32(channel->addr, 0x0028, 0x1f80, 0x07a1); r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f80, 0x0208); break; + + case PHY_INTERFACE_MODE_USXGMII: + r8a779f0_eth_serdes_write32(channel->addr, 0x001c, 0x300, 0x0000); + r8a779f0_eth_serdes_write32(channel->addr, 0x0014, 0x380, 0x0050); + r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2200); + r8a779f0_eth_serdes_write32(channel->addr, 0x001c, 0x380, 0x0400); + r8a779f0_eth_serdes_write32(channel->addr, 0x01c0, 0x180, 0x0001); + r8a779f0_eth_serdes_write32(channel->addr, 0x0248, 0x180, 0x056a); + r8a779f0_eth_serdes_write32(channel->addr, 0x0258, 0x180, 0x0015); + r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x1100); + r8a779f0_eth_serdes_write32(channel->addr, 0x01a0, 0x180, 0x0001); + r8a779f0_eth_serdes_write32(channel->addr, 0x00d0, 0x180, 0x0001); + r8a779f0_eth_serdes_write32(channel->addr, 0x0150, 0x180, 0x0001); + r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x180, 0x0300); + r8a779f0_eth_serdes_write32(channel->addr, 0x0148, 0x180, 0x0300); + r8a779f0_eth_serdes_write32(channel->addr, 0x0174, 0x180, 0x0000); + r8a779f0_eth_serdes_write32(channel->addr, 0x0160, 0x180, 0x0004); + r8a779f0_eth_serdes_write32(channel->addr, 0x01ac, 0x180, 0x0000); + r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x0310); + r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x180, 0x0301); + ret = r8a779f0_eth_serdes_reg_wait(channel, 0x00c8, 0x180, BIT(0), 0); + if (ret) + return ret; + r8a779f0_eth_serdes_write32(channel->addr, 0x0148, 0x180, 0x0301); + ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0148, 0x180, BIT(0), 0); + if (ret) + return ret; + r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x1310); + r8a779f0_eth_serdes_write32(channel->addr, 0x00d8, 0x180, 0x1800); + r8a779f0_eth_serdes_write32(channel->addr, 0x00dc, 0x180, 0x0000); + r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2300); + ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0000, 0x380, BIT(8), 0); + if (ret) + return ret; + break; + default: return -EOPNOTSUPP; } @@ -179,6 +216,14 @@ r8a779f0_eth_serdes_chan_speed(struct r8a779f0_eth_serdes_channel *channel) return ret; r8a779f0_eth_serdes_write32(channel->addr, 0x0008, 0x1f80, 0x0000); break; + case PHY_INTERFACE_MODE_USXGMII: + r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x0120); + usleep_range(10, 20); + r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2600); + ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0000, 0x380, BIT(10), 0); + if (ret) + return ret; + break; default: return -EOPNOTSUPP; } From e4a8db93b5ec9bca1cc66b295544899e3afd5e86 Mon Sep 17 00:00:00 2001 From: Michael Dege Date: Thu, 3 Jul 2025 13:07:24 +0200 Subject: [PATCH 58/64] phy: renesas: r8a779f0-ether-serdes: add new step added to latest datasheet R-Car S4-8 datasheet Rev.1.20 describes some additional register settings at the end of the initialization. Signed-off-by: Michael Dege Link: https://lore.kernel.org/r/20250703-renesas-serdes-update-v4-2-1db5629cac2b@renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/r8a779f0-ether-serdes.c | 28 +++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/phy/renesas/r8a779f0-ether-serdes.c b/drivers/phy/renesas/r8a779f0-ether-serdes.c index ed83c46f6d00..8a6b6f366fe3 100644 --- a/drivers/phy/renesas/r8a779f0-ether-serdes.c +++ b/drivers/phy/renesas/r8a779f0-ether-serdes.c @@ -49,6 +49,13 @@ static void r8a779f0_eth_serdes_write32(void __iomem *addr, u32 offs, u32 bank, iowrite32(data, addr + offs); } +static u32 r8a779f0_eth_serdes_read32(void __iomem *addr, u32 offs, u32 bank) +{ + iowrite32(bank, addr + R8A779F0_ETH_SERDES_BANK_SELECT); + + return ioread32(addr + offs); +} + static int r8a779f0_eth_serdes_reg_wait(struct r8a779f0_eth_serdes_channel *channel, u32 offs, u32 bank, u32 mask, u32 expected) @@ -319,6 +326,7 @@ static int r8a779f0_eth_serdes_hw_init_late(struct r8a779f0_eth_serdes_channel *channel) { int ret; + u32 val; ret = r8a779f0_eth_serdes_chan_setting(channel); if (ret) @@ -332,6 +340,26 @@ static int r8a779f0_eth_serdes_hw_init_late(struct r8a779f0_eth_serdes_channel r8a779f0_eth_serdes_write32(channel->addr, 0x03d0, 0x380, 0x0000); + val = r8a779f0_eth_serdes_read32(channel->addr, 0x00c0, 0x180); + r8a779f0_eth_serdes_write32(channel->addr, 0x00c0, 0x180, val | BIT(8)); + ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0100, 0x180, BIT(0), 1); + if (ret) + return ret; + r8a779f0_eth_serdes_write32(channel->addr, 0x00c0, 0x180, val & ~BIT(8)); + ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0100, 0x180, BIT(0), 0); + if (ret) + return ret; + + val = r8a779f0_eth_serdes_read32(channel->addr, 0x0144, 0x180); + r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, val | BIT(4)); + ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0180, 0x180, BIT(0), 1); + if (ret) + return ret; + r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, val & ~BIT(4)); + ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0180, 0x180, BIT(0), 0); + if (ret) + return ret; + return r8a779f0_eth_serdes_monitor_linkup(channel); } From 43bd2c44515f8ee5c019ce6e6583f5640387a41b Mon Sep 17 00:00:00 2001 From: Harikrishna Shenoy Date: Thu, 7 Aug 2025 10:50:02 +0530 Subject: [PATCH 59/64] phy: cadence: cdns-dphy: Enable lower resolutions in dphy Enable support for data lane rates between 80-160 Mbps cdns dphy as mentioned in TRM [0] by setting the pll_opdiv field to 16. This change enables lower resolutions like 640x480 at 60Hz. [0]: https://www.ti.com/lit/zip/spruil1 (Table 12-552. DPHY_TX_PLL_CTRL Register Field Descriptions) Reviewed-by: Udit Kumar Reviewed-by: Devarsh Thakkar Signed-off-by: Harikrishna Shenoy Link: https://lore.kernel.org/r/20250807052002.717807-1-h-shenoy@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/cdns-dphy.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c index 24a25606996c..d5b0e516b93c 100644 --- a/drivers/phy/cadence/cdns-dphy.c +++ b/drivers/phy/cadence/cdns-dphy.c @@ -136,7 +136,7 @@ static int cdns_dphy_get_pll_cfg(struct cdns_dphy *dphy, dlane_bps = opts->hs_clk_rate; - if (dlane_bps > 2500000000UL || dlane_bps < 160000000UL) + if (dlane_bps > 2500000000UL || dlane_bps < 80000000UL) return -EINVAL; else if (dlane_bps >= 1250000000) cfg->pll_opdiv = 1; @@ -146,6 +146,8 @@ static int cdns_dphy_get_pll_cfg(struct cdns_dphy *dphy, cfg->pll_opdiv = 4; else if (dlane_bps >= 160000000) cfg->pll_opdiv = 8; + else if (dlane_bps >= 80000000) + cfg->pll_opdiv = 16; cfg->pll_fbdiv = DIV_ROUND_UP_ULL(dlane_bps * 2 * cfg->pll_opdiv * cfg->pll_ipdiv, From c254815b02673cc77a84103c4c0d6197bd90c0ef Mon Sep 17 00:00:00 2001 From: Michael Riesch Date: Wed, 3 Sep 2025 19:04:50 +0200 Subject: [PATCH 60/64] dt-bindings: phy: rockchip-inno-csi-dphy: make power-domains non-required There are variants of the Rockchip Innosilicon CSI DPHY (e.g., the RK3568 variant) that are powered on by default as they are part of the ALIVE power domain. Remove 'power-domains' from the required properties in order to avoid false positives. Fixes: 22c8e0a69b7f ("dt-bindings: phy: add compatible for rk356x to rockchip-inno-csi-dphy") Cc: stable@kernel.org Reviewed-by: Krzysztof Kozlowski Signed-off-by: Michael Riesch Link: https://lore.kernel.org/r/20250616-rk3588-csi-dphy-v4-2-a4f340a7f0cf@collabora.com Signed-off-by: Vinod Koul --- .../bindings/phy/rockchip-inno-csi-dphy.yaml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml b/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml index 5ac994b3c0aa..b304bc5a08c4 100644 --- a/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml +++ b/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml @@ -57,11 +57,24 @@ required: - clocks - clock-names - '#phy-cells' - - power-domains - resets - reset-names - rockchip,grf +allOf: + - if: + properties: + compatible: + contains: + enum: + - rockchip,px30-csi-dphy + - rockchip,rk1808-csi-dphy + - rockchip,rk3326-csi-dphy + - rockchip,rk3368-csi-dphy + then: + required: + - power-domains + additionalProperties: false examples: From 5072b8e98eef4685a5a9a8bae56072cb65a2ef69 Mon Sep 17 00:00:00 2001 From: Michael Riesch Date: Wed, 3 Sep 2025 19:04:51 +0200 Subject: [PATCH 61/64] dt-bindings: phy: rockchip-inno-csi-dphy: add rk3588 variant The Rockchip RK3588 variant of the CSI-2 DPHY features two reset lines. Add the variant and allow for the additional reset. While at it, fix the description of the first reset in order to avoid confusion. Signed-off-by: Michael Riesch Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250616-rk3588-csi-dphy-v4-3-a4f340a7f0cf@collabora.com Signed-off-by: Vinod Koul --- .../bindings/phy/rockchip-inno-csi-dphy.yaml | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml b/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml index b304bc5a08c4..03950b3cad08 100644 --- a/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml +++ b/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml @@ -21,6 +21,7 @@ properties: - rockchip,rk3326-csi-dphy - rockchip,rk3368-csi-dphy - rockchip,rk3568-csi-dphy + - rockchip,rk3588-csi-dphy reg: maxItems: 1 @@ -40,11 +41,15 @@ properties: resets: items: - - description: exclusive PHY reset line + - description: APB reset line + - description: PHY reset line + minItems: 1 reset-names: items: - const: apb + - const: phy + minItems: 1 rockchip,grf: $ref: /schemas/types.yaml#/definitions/phandle @@ -74,6 +79,30 @@ allOf: then: required: - power-domains + - if: + properties: + compatible: + contains: + enum: + - rockchip,px30-csi-dphy + - rockchip,rk1808-csi-dphy + - rockchip,rk3326-csi-dphy + - rockchip,rk3368-csi-dphy + - rockchip,rk3568-csi-dphy + then: + properties: + resets: + maxItems: 1 + + reset-names: + maxItems: 1 + else: + properties: + resets: + minItems: 2 + + reset-names: + minItems: 2 additionalProperties: false @@ -91,3 +120,22 @@ examples: reset-names = "apb"; rockchip,grf = <&grf>; }; + - | + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + phy@fedc0000 { + compatible = "rockchip,rk3588-csi-dphy"; + reg = <0x0 0xfedc0000 0x0 0x8000>; + clocks = <&cru PCLK_CSIPHY0>; + clock-names = "pclk"; + #phy-cells = <0>; + resets = <&cru SRST_P_CSIPHY0>, <&cru SRST_CSIPHY0>; + reset-names = "apb", "phy"; + rockchip,grf = <&csidphy0_grf>; + }; + }; From 8c7c19466c854fa86b82d2148eaa9bf0e6531423 Mon Sep 17 00:00:00 2001 From: Michael Riesch Date: Wed, 3 Sep 2025 19:04:52 +0200 Subject: [PATCH 62/64] phy: rockchip: phy-rockchip-inno-csidphy: allow writes to grf register 0 The driver for the Rockchip MIPI CSI-2 DPHY uses GRF register offset value 0 to sort out undefined registers. However, the RK3588 CSIDPHY GRF this offset is perfectly fine (in fact, register 0 is the only one in this register file). Introduce a boolean variable to indicate valid registers and allow writes to register 0. Reviewed-by: Neil Armstrong Signed-off-by: Michael Riesch Link: https://lore.kernel.org/r/20250616-rk3588-csi-dphy-v4-4-a4f340a7f0cf@collabora.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-csidphy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c index 2ab99e1d47eb..75533d071025 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c @@ -87,10 +87,11 @@ struct dphy_reg { u32 offset; u32 mask; u32 shift; + u8 valid; }; #define PHY_REG(_offset, _width, _shift) \ - { .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, } + { .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, .valid = 1, } static const struct dphy_reg rk1808_grf_dphy_regs[] = { [GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK1808_GRF_PD_VI_CON_OFFSET, 4, 0), @@ -145,7 +146,7 @@ static inline void write_grf_reg(struct rockchip_inno_csidphy *priv, const struct dphy_drv_data *drv_data = priv->drv_data; const struct dphy_reg *reg = &drv_data->grf_regs[index]; - if (reg->offset) + if (reg->valid) regmap_write(priv->grf, reg->offset, HIWORD_UPDATE(value, reg->mask, reg->shift)); } From 260435153c90c8e90553e456ec43578834a14a71 Mon Sep 17 00:00:00 2001 From: Michael Riesch Date: Wed, 3 Sep 2025 19:04:53 +0200 Subject: [PATCH 63/64] phy: rockchip: phy-rockchip-inno-csidphy: allow for different reset lines The RK3588 MIPI CSI-2 DPHY variant requires two reset lines. Add support for different sets of reset lines to the phy-rockchip-inno-csidphy driver as preparation for the introduction of the RK3588 variant. Signed-off-by: Michael Riesch Link: https://lore.kernel.org/r/20250616-rk3588-csi-dphy-v4-5-a4f340a7f0cf@collabora.com Signed-off-by: Vinod Koul --- .../phy/rockchip/phy-rockchip-inno-csidphy.c | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c index 75533d071025..6c4ddcd7e5de 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c @@ -67,6 +67,8 @@ #define RK1808_CSIDPHY_CLK_CALIB_EN 0x168 #define RK3568_CSIDPHY_CLK_CALIB_EN 0x168 +#define RESETS_MAX 2 + /* * The higher 16-bit of this register is used for write protection * only if BIT(x + 16) set to 1 the BIT(x) can be written. @@ -127,6 +129,8 @@ struct dphy_drv_data { const struct hsfreq_range *hsfreq_ranges; int num_hsfreq_ranges; const struct dphy_reg *grf_regs; + const char *const *resets; + unsigned int resets_num; }; struct rockchip_inno_csidphy { @@ -134,7 +138,8 @@ struct rockchip_inno_csidphy { void __iomem *phy_base; struct clk *pclk; struct regmap *grf; - struct reset_control *rst; + struct reset_control_bulk_data resets[RESETS_MAX]; + unsigned int resets_num; const struct dphy_drv_data *drv_data; struct phy_configure_opts_mipi_dphy config; u8 hsfreq; @@ -174,6 +179,10 @@ static const struct hsfreq_range rk3368_mipidphy_hsfreq_ranges[] = { {1249, 0x0c}, {1349, 0x0d}, {1500, 0x0e} }; +static const char *const rk3368_reset_names[] = { + "apb" +}; + static void rockchip_inno_csidphy_ths_settle(struct rockchip_inno_csidphy *priv, int hsfreq, int offset) { @@ -344,6 +353,8 @@ static const struct dphy_drv_data rk1808_mipidphy_drv_data = { .hsfreq_ranges = rk1808_mipidphy_hsfreq_ranges, .num_hsfreq_ranges = ARRAY_SIZE(rk1808_mipidphy_hsfreq_ranges), .grf_regs = rk1808_grf_dphy_regs, + .resets = rk3368_reset_names, + .resets_num = ARRAY_SIZE(rk3368_reset_names), }; static const struct dphy_drv_data rk3326_mipidphy_drv_data = { @@ -353,6 +364,8 @@ static const struct dphy_drv_data rk3326_mipidphy_drv_data = { .hsfreq_ranges = rk3326_mipidphy_hsfreq_ranges, .num_hsfreq_ranges = ARRAY_SIZE(rk3326_mipidphy_hsfreq_ranges), .grf_regs = rk3326_grf_dphy_regs, + .resets = rk3368_reset_names, + .resets_num = ARRAY_SIZE(rk3368_reset_names), }; static const struct dphy_drv_data rk3368_mipidphy_drv_data = { @@ -362,6 +375,8 @@ static const struct dphy_drv_data rk3368_mipidphy_drv_data = { .hsfreq_ranges = rk3368_mipidphy_hsfreq_ranges, .num_hsfreq_ranges = ARRAY_SIZE(rk3368_mipidphy_hsfreq_ranges), .grf_regs = rk3368_grf_dphy_regs, + .resets = rk3368_reset_names, + .resets_num = ARRAY_SIZE(rk3368_reset_names), }; static const struct dphy_drv_data rk3568_mipidphy_drv_data = { @@ -371,6 +386,8 @@ static const struct dphy_drv_data rk3568_mipidphy_drv_data = { .hsfreq_ranges = rk1808_mipidphy_hsfreq_ranges, .num_hsfreq_ranges = ARRAY_SIZE(rk1808_mipidphy_hsfreq_ranges), .grf_regs = rk3568_grf_dphy_regs, + .resets = rk3368_reset_names, + .resets_num = ARRAY_SIZE(rk3368_reset_names), }; static const struct of_device_id rockchip_inno_csidphy_match_id[] = { @@ -404,6 +421,7 @@ static int rockchip_inno_csidphy_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct phy_provider *phy_provider; struct phy *phy; + int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -435,10 +453,18 @@ static int rockchip_inno_csidphy_probe(struct platform_device *pdev) return PTR_ERR(priv->pclk); } - priv->rst = devm_reset_control_get(dev, "apb"); - if (IS_ERR(priv->rst)) { + if (priv->drv_data->resets_num > RESETS_MAX) { + dev_err(dev, "invalid number of resets\n"); + return -EINVAL; + } + priv->resets_num = priv->drv_data->resets_num; + for (unsigned int i = 0; i < priv->resets_num; i++) + priv->resets[i].id = priv->drv_data->resets[i]; + ret = devm_reset_control_bulk_get_exclusive(dev, priv->resets_num, + priv->resets); + if (ret) { dev_err(dev, "failed to get system reset control\n"); - return PTR_ERR(priv->rst); + return ret; } phy = devm_phy_create(dev, NULL, &rockchip_inno_csidphy_ops); From bdb978979ed133c47e19099ff2a4ae51e515452b Mon Sep 17 00:00:00 2001 From: Michael Riesch Date: Wed, 3 Sep 2025 19:04:54 +0200 Subject: [PATCH 64/64] phy: rockchip: phy-rockchip-inno-csidphy: add support for rk3588 variant The Rockchip RK3588 MIPI CSI-2 DPHY can be supported using the existing phy-rockchip-inno-csidphy driver, the notable differences being - the control bits in the GRF - the additional reset line Add support for this variant. Signed-off-by: Michael Riesch Link: https://lore.kernel.org/r/20250616-rk3588-csi-dphy-v4-6-a4f340a7f0cf@collabora.com Signed-off-by: Vinod Koul --- .../phy/rockchip/phy-rockchip-inno-csidphy.c | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c index 6c4ddcd7e5de..c79fb53d8ee5 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c @@ -30,6 +30,8 @@ #define RK3568_GRF_VI_CON0 0x0340 #define RK3568_GRF_VI_CON1 0x0344 +#define RK3588_CSIDPHY_GRF_CON0 0x0000 + /* PHY */ #define CSIDPHY_CTRL_LANE_ENABLE 0x00 #define CSIDPHY_CTRL_LANE_ENABLE_CK BIT(6) @@ -117,6 +119,12 @@ static const struct dphy_reg rk3568_grf_dphy_regs[] = { [GRF_DPHY_CSIPHY_CLKLANE_EN] = PHY_REG(RK3568_GRF_VI_CON0, 1, 8), }; +static const struct dphy_reg rk3588_grf_dphy_regs[] = { + [GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3588_CSIDPHY_GRF_CON0, 4, 0), + [GRF_DPHY_CSIPHY_DATALANE_EN] = PHY_REG(RK3588_CSIDPHY_GRF_CON0, 4, 4), + [GRF_DPHY_CSIPHY_CLKLANE_EN] = PHY_REG(RK3588_CSIDPHY_GRF_CON0, 1, 8), +}; + struct hsfreq_range { u32 range_h; u8 cfg_bit; @@ -183,6 +191,11 @@ static const char *const rk3368_reset_names[] = { "apb" }; +static const char *const rk3588_reset_names[] = { + "apb", + "phy" +}; + static void rockchip_inno_csidphy_ths_settle(struct rockchip_inno_csidphy *priv, int hsfreq, int offset) { @@ -390,6 +403,17 @@ static const struct dphy_drv_data rk3568_mipidphy_drv_data = { .resets_num = ARRAY_SIZE(rk3368_reset_names), }; +static const struct dphy_drv_data rk3588_mipidphy_drv_data = { + .pwrctl_offset = -1, + .ths_settle_offset = RK3568_CSIDPHY_CLK_WR_THS_SETTLE, + .calib_offset = RK3568_CSIDPHY_CLK_CALIB_EN, + .hsfreq_ranges = rk1808_mipidphy_hsfreq_ranges, + .num_hsfreq_ranges = ARRAY_SIZE(rk1808_mipidphy_hsfreq_ranges), + .grf_regs = rk3588_grf_dphy_regs, + .resets = rk3588_reset_names, + .resets_num = ARRAY_SIZE(rk3588_reset_names), +}; + static const struct of_device_id rockchip_inno_csidphy_match_id[] = { { .compatible = "rockchip,px30-csi-dphy", @@ -411,6 +435,10 @@ static const struct of_device_id rockchip_inno_csidphy_match_id[] = { .compatible = "rockchip,rk3568-csi-dphy", .data = &rk3568_mipidphy_drv_data, }, + { + .compatible = "rockchip,rk3588-csi-dphy", + .data = &rk3588_mipidphy_drv_data, + }, {} }; MODULE_DEVICE_TABLE(of, rockchip_inno_csidphy_match_id);