From 0bd448b5467b7ead268bc3a946c1deabbda70fe0 Mon Sep 17 00:00:00 2001 From: Aditya Dabhade Date: Wed, 29 Apr 2026 01:04:59 +0530 Subject: [PATCH 01/87] phy: airoha: use C-style SPDX comment for header file checkpatch reports an improper SPDX comment style for this header: WARNING: Improper SPDX comment style for 'drivers/phy/phy-airoha-pcie-regs.h', please use '/*' instead Per Documentation/process/license-rules.rst, C header files must use the '/* SPDX-License-Identifier: ... */' form instead of the '// ....' form used in C source files. Fix it. Signed-off-by: Aditya Dabhade Link: https://patch.msgid.link/20260428193459.5865-1-aditya.dabhade066@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/phy-airoha-pcie-regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/phy-airoha-pcie-regs.h b/drivers/phy/phy-airoha-pcie-regs.h index b938a7b468fe..58572c793722 100644 --- a/drivers/phy/phy-airoha-pcie-regs.h +++ b/drivers/phy/phy-airoha-pcie-regs.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2024 AIROHA Inc * Author: Lorenzo Bianconi From f67ab4706ab72af29c331b21f431c463b00d447a Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 25 Mar 2026 11:20:39 +0000 Subject: [PATCH 02/87] phy: renesas: rcar-gen3-usb2: Simplify ID/VBUS detection logic Read USB2_ADPCTRL once in rcar_gen3_check_id() instead of issuing multiple MMIO reads, and derive both IDDIG and VBUSVALID from the same value. Drop the redundant !! operator, as assigning a masked u32 value to a bool already performs the required normalization. Simplify the logic by comparing the ID and VBUS status directly, which is equivalent to the previous conditional but easier to follow. Reported-by: Pavel Machek Closes: https://lore.kernel.org/all/acJVCOdlchLiSe5n@duo.ucw.cz/ Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260325112039.464992-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 79e820e2fe55..9a45d840efeb 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -314,13 +314,11 @@ 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; + u32 val = readl(ch->base + USB2_ADPCTRL); + bool vbus_valid = val & USB2_ADPCTRL_VBUSVALID; + bool device = val & USB2_ADPCTRL_IDDIG; - device = !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); - vbus_valid = !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_VBUSVALID); - - return vbus_valid ? device : !device; + return device == vbus_valid; } if (!ch->uses_otg_pins) From 059f1a4c9e3aa44d888c0e7cf4559403eece0438 Mon Sep 17 00:00:00 2001 From: Nora Schiffer Date: Tue, 7 Apr 2026 13:42:33 +0200 Subject: [PATCH 03/87] dt-bindings: phy: ti: phy-j721e-wiz: Add ti,j722s-wiz-10g compatible The J722S WIZ is mostly identical to the AM64's, but additionally supports SGMII. The AM64 compatible ti,am64-wiz-10g is used as a fallback. Signed-off-by: Nora Schiffer Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/1ef8adf850f2fd41b6c4e3c89e4f4e6e0f469a0e.1775559102.git.nora.schiffer@ew.tq-group.com Signed-off-by: Vinod Koul --- .../bindings/phy/ti,phy-j721e-wiz.yaml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml index 3f16ff14484d..0653252c18d8 100644 --- a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml +++ b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml @@ -12,13 +12,18 @@ maintainers: properties: compatible: - enum: - - ti,j721e-wiz-16g - - ti,j721e-wiz-10g - - ti,j721s2-wiz-10g - - ti,am64-wiz-10g - - ti,j7200-wiz-10g - - ti,j784s4-wiz-10g + oneOf: + - enum: + - ti,j721e-wiz-16g + - ti,j721e-wiz-10g + - ti,j721s2-wiz-10g + - ti,am64-wiz-10g + - ti,j7200-wiz-10g + - ti,j784s4-wiz-10g + - items: + - enum: + - ti,j722s-wiz-10g + - const: ti,am64-wiz-10g power-domains: maxItems: 1 From 567b3c62a7eb51db4cb562b416ec220132d524c9 Mon Sep 17 00:00:00 2001 From: Nora Schiffer Date: Tue, 7 Apr 2026 13:42:34 +0200 Subject: [PATCH 04/87] dt-bindings: phy: ti: phy-gmii-sel: Add ti,j722s-phy-gmii-sel compatible The J722S gmii-sel is mostly identical to the AM64's, but additionally supports SGMII. The AM64 compatible ti,am654-phy-gmii-sel is used as a fallback. Signed-off-by: Nora Schiffer Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/b67c8b0bc9cc918667e9329d79f617d033d025d5.1775559102.git.nora.schiffer@ew.tq-group.com Signed-off-by: Vinod Koul --- .../bindings/phy/ti,phy-gmii-sel.yaml | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml b/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml index be41b4547ec6..60b644a4c639 100644 --- a/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml +++ b/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml @@ -47,15 +47,20 @@ description: | properties: compatible: - enum: - - ti,am3352-phy-gmii-sel - - ti,dra7xx-phy-gmii-sel - - ti,am43xx-phy-gmii-sel - - ti,dm814-phy-gmii-sel - - ti,am654-phy-gmii-sel - - ti,j7200-cpsw5g-phy-gmii-sel - - ti,j721e-cpsw9g-phy-gmii-sel - - ti,j784s4-cpsw9g-phy-gmii-sel + oneOf: + - enum: + - ti,am3352-phy-gmii-sel + - ti,dra7xx-phy-gmii-sel + - ti,am43xx-phy-gmii-sel + - ti,dm814-phy-gmii-sel + - ti,am654-phy-gmii-sel + - ti,j7200-cpsw5g-phy-gmii-sel + - ti,j721e-cpsw9g-phy-gmii-sel + - ti,j784s4-cpsw9g-phy-gmii-sel + - items: + - enum: + - ti,j722s-phy-gmii-sel + - const: ti,am654-phy-gmii-sel reg: maxItems: 1 From 61849b7afb579630fc45dbeaf5449b42b33cc70e Mon Sep 17 00:00:00 2001 From: Nora Schiffer Date: Tue, 7 Apr 2026 13:42:35 +0200 Subject: [PATCH 05/87] phy: ti: phy-j721e-wiz: add support for J722S SoC family The J722S WIZ is mostly identical to the AM64's, but additionally supports SGMII. Signed-off-by: Nora Schiffer Link: https://patch.msgid.link/85e9f67f8673dc7039ab87c34cfc9e4de1c7447c.1775559102.git.nora.schiffer@ew.tq-group.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-j721e-wiz.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 6b584706b913..7531a8a04912 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -331,6 +331,7 @@ enum wiz_type { J721E_WIZ_16G, J721E_WIZ_10G, /* Also for J7200 SR1.0 */ AM64_WIZ_10G, + J722S_WIZ_10G, J7200_WIZ_10G, /* J7200 SR2.0 */ J784S4_WIZ_10G, J721S2_WIZ_10G, @@ -1020,6 +1021,7 @@ static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node) switch (wiz->type) { case AM64_WIZ_10G: + case J722S_WIZ_10G: case J7200_WIZ_10G: case J784S4_WIZ_10G: case J721S2_WIZ_10G: @@ -1089,6 +1091,7 @@ static void wiz_clock_init(struct wiz *wiz) switch (wiz->type) { case AM64_WIZ_10G: + case J722S_WIZ_10G: case J7200_WIZ_10G: switch (rate) { case REF_CLK_100MHZ: @@ -1158,6 +1161,7 @@ static int wiz_clock_probe(struct wiz *wiz, struct device_node *node) switch (wiz->type) { case AM64_WIZ_10G: + case J722S_WIZ_10G: case J7200_WIZ_10G: case J784S4_WIZ_10G: case J721S2_WIZ_10G: @@ -1246,6 +1250,14 @@ static int wiz_phy_fullrt_div(struct wiz *wiz, int lane) if (wiz->lane_phy_type[lane] == PHY_TYPE_SGMII) return regmap_field_write(wiz->p0_fullrt_div[lane], 0x2); break; + + case J722S_WIZ_10G: + if (wiz->lane_phy_type[lane] == PHY_TYPE_PCIE) + return regmap_field_write(wiz->p0_fullrt_div[lane], 0x1); + if (wiz->lane_phy_type[lane] == PHY_TYPE_SGMII) + return regmap_field_write(wiz->p0_fullrt_div[lane], 0x2); + break; + default: return 0; } @@ -1350,6 +1362,15 @@ static struct wiz_data am64_10g_data = { .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G, }; +static struct wiz_data j722s_10g_data = { + .type = J722S_WIZ_10G, + .pll0_refclk_mux_sel = &pll0_refclk_mux_sel, + .pll1_refclk_mux_sel = &pll1_refclk_mux_sel, + .refclk_dig_sel = &refclk_dig_sel_10g, + .clk_mux_sel = clk_mux_sel_10g, + .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G, +}; + static struct wiz_data j7200_pg2_10g_data = { .type = J7200_WIZ_10G, .pll0_refclk_mux_sel = &sup_pll0_refclk_mux_sel, @@ -1389,6 +1410,9 @@ static const struct of_device_id wiz_id_table[] = { { .compatible = "ti,am64-wiz-10g", .data = &am64_10g_data, }, + { + .compatible = "ti,j722s-wiz-10g", .data = &j722s_10g_data, + }, { .compatible = "ti,j7200-wiz-10g", .data = &j7200_pg2_10g_data, }, From d39cf00e7daea64889dda9abb0b7e6da04a69d04 Mon Sep 17 00:00:00 2001 From: Nora Schiffer Date: Tue, 7 Apr 2026 13:42:36 +0200 Subject: [PATCH 06/87] phy: ti: gmii-sel: add support for J722S SoC family The J722S gmii-sel is mostly identical to the AM64's, but additionally supports SGMII. Signed-off-by: Nora Schiffer Link: https://patch.msgid.link/86488589fc055f61ee5341f9e268184f04febe71.1775559102.git.nora.schiffer@ew.tq-group.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-gmii-sel.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c index 6213c2b6005a..c2865a6b1d7f 100644 --- a/drivers/phy/ti/phy-gmii-sel.c +++ b/drivers/phy/ti/phy-gmii-sel.c @@ -251,6 +251,15 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = { .regfields = phy_gmii_sel_fields_am654, }; +static const +struct phy_gmii_sel_soc_data phy_gmii_sel_soc_j722s = { + .use_of_data = true, + .features = BIT(PHY_GMII_SEL_RGMII_ID_MODE) | + BIT(PHY_GMII_SEL_FIXED_TX_DELAY), + .regfields = phy_gmii_sel_fields_am654, + .extra_modes = BIT(PHY_INTERFACE_MODE_SGMII), +}; + static const struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = { .use_of_data = true, @@ -307,6 +316,10 @@ static const struct of_device_id phy_gmii_sel_id_table[] = { .compatible = "ti,am654-phy-gmii-sel", .data = &phy_gmii_sel_soc_am654, }, + { + .compatible = "ti,j722s-phy-gmii-sel", + .data = &phy_gmii_sel_soc_j722s, + }, { .compatible = "ti,j7200-cpsw5g-phy-gmii-sel", .data = &phy_gmii_sel_cpsw5g_soc_j7200, From ad8fdebd40fd25e86331886f4fc6951531691319 Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Thu, 5 Mar 2026 01:00:51 +0000 Subject: [PATCH 07/87] dt-bindings: phy: spacemit: k3: add USB2 PHY support Introduce a compatible string for the USB2 PHY in SpacemiT K3 SoC. The IP of USB2 PHY mostly shares the same functionalities with K1 SoC, while has some register layout changes. Acked-by: Krzysztof Kozlowski Signed-off-by: Yixun Lan Link: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git/commit/?h=usb-next&id=c05cf9d274daf72dc7e433480cf2e0e888f6bd89 [1] Link: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git/commit/?h=usb-next&id=00b4fe5be06aecd6426930de86b7cffc2330f4b8 [2] Link: https://patch.msgid.link/20260305-11-k3-usb2-phy-v4-1-15554fb933bc@kernel.org Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/spacemit,usb2-phy.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/spacemit,usb2-phy.yaml b/Documentation/devicetree/bindings/phy/spacemit,usb2-phy.yaml index 43eaca90d88c..18025e5f60d6 100644 --- a/Documentation/devicetree/bindings/phy/spacemit,usb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/spacemit,usb2-phy.yaml @@ -4,14 +4,16 @@ $id: http://devicetree.org/schemas/phy/spacemit,usb2-phy.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: SpacemiT K1 SoC USB 2.0 PHY +title: SpacemiT K1/K3 SoC USB 2.0 PHY maintainers: - Ze Huang properties: compatible: - const: spacemit,k1-usb2-phy + enum: + - spacemit,k1-usb2-phy + - spacemit,k3-usb2-phy reg: maxItems: 1 From 056ee8b37bc91e3230afa11ec1018fa898b983b8 Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Thu, 5 Mar 2026 01:00:52 +0000 Subject: [PATCH 08/87] phy: k1-usb: k3: add USB2 PHY support Add USB2 PHY support for SpacemiT K3 SoC. Register layout of handling USB disconnect operation has been changed, So introducing a platform data to distinguish the different SoCs. Reviewed-by: Yao Zi Signed-off-by: Yixun Lan Reviewed-by: Neil Armstrong Link: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git/commit/?h=usb-next&id=c05cf9d274daf72dc7e433480cf2e0e888f6bd89 [1] Link: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git/commit/?h=usb-next&id=00b4fe5be06aecd6426930de86b7cffc2330f4b8 [2] Link: https://patch.msgid.link/20260305-11-k3-usb2-phy-v4-2-15554fb933bc@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/spacemit/phy-k1-usb2.c | 34 +++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/phy/spacemit/phy-k1-usb2.c b/drivers/phy/spacemit/phy-k1-usb2.c index 9215d0b223b2..87b943d9111f 100644 --- a/drivers/phy/spacemit/phy-k1-usb2.c +++ b/drivers/phy/spacemit/phy-k1-usb2.c @@ -51,6 +51,9 @@ #define PHY_K1_HS_HOST_DISC 0x40 #define PHY_K1_HS_HOST_DISC_CLR BIT(0) +#define PHY_K3_HS_HOST_DISC 0x20 +#define PHY_K3_HS_HOST_DISC_CLR BIT(8) + #define PHY_PLL_DIV_CFG 0x98 #define PHY_FDIV_FRACT_8_15 GENMASK(7, 0) #define PHY_FDIV_FRACT_16_19 GENMASK(11, 8) @@ -145,7 +148,7 @@ static int spacemit_usb2phy_exit(struct phy *phy) return 0; } -static int spacemit_usb2phy_disconnect(struct phy *phy, int port) +static int spacemit_k1_usb2phy_disconnect(struct phy *phy, int port) { struct spacemit_usb2phy *sphy = phy_get_drvdata(phy); @@ -155,10 +158,27 @@ static int spacemit_usb2phy_disconnect(struct phy *phy, int port) return 0; } -static const struct phy_ops spacemit_usb2phy_ops = { +static int spacemit_k3_usb2phy_disconnect(struct phy *phy, int port) +{ + struct spacemit_usb2phy *sphy = phy_get_drvdata(phy); + + regmap_update_bits(sphy->regmap_base, PHY_K3_HS_HOST_DISC, + PHY_K3_HS_HOST_DISC_CLR, PHY_K3_HS_HOST_DISC_CLR); + + return 0; +} + +static const struct phy_ops spacemit_k1_usb2phy_ops = { .init = spacemit_usb2phy_init, .exit = spacemit_usb2phy_exit, - .disconnect = spacemit_usb2phy_disconnect, + .disconnect = spacemit_k1_usb2phy_disconnect, + .owner = THIS_MODULE, +}; + +static const struct phy_ops spacemit_k3_usb2phy_ops = { + .init = spacemit_usb2phy_init, + .exit = spacemit_usb2phy_exit, + .disconnect = spacemit_k3_usb2phy_disconnect, .owner = THIS_MODULE, }; @@ -167,12 +187,15 @@ static int spacemit_usb2phy_probe(struct platform_device *pdev) struct phy_provider *phy_provider; struct device *dev = &pdev->dev; struct spacemit_usb2phy *sphy; + const struct phy_ops *ops; void __iomem *base; sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL); if (!sphy) return -ENOMEM; + ops = device_get_match_data(dev); + sphy->clk = devm_clk_get_prepared(&pdev->dev, NULL); if (IS_ERR(sphy->clk)) return dev_err_probe(dev, PTR_ERR(sphy->clk), "Failed to get clock\n"); @@ -185,7 +208,7 @@ static int spacemit_usb2phy_probe(struct platform_device *pdev) if (IS_ERR(sphy->regmap_base)) return dev_err_probe(dev, PTR_ERR(sphy->regmap_base), "Failed to init regmap\n"); - sphy->phy = devm_phy_create(dev, NULL, &spacemit_usb2phy_ops); + sphy->phy = devm_phy_create(dev, NULL, ops); if (IS_ERR(sphy->phy)) return dev_err_probe(dev, PTR_ERR(sphy->phy), "Failed to create phy\n"); @@ -196,7 +219,8 @@ static int spacemit_usb2phy_probe(struct platform_device *pdev) } static const struct of_device_id spacemit_usb2phy_dt_match[] = { - { .compatible = "spacemit,k1-usb2-phy", }, + { .compatible = "spacemit,k1-usb2-phy", .data = &spacemit_k1_usb2phy_ops }, + { .compatible = "spacemit,k3-usb2-phy", .data = &spacemit_k3_usb2phy_ops }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, spacemit_usb2phy_dt_match); From 6d6ff64e01ddeb579bf0078e5b6d50c04035541e Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 4 May 2026 16:14:42 +0800 Subject: [PATCH 09/87] dt-bindings: phy: qcom,sc8280xp-qmp-ufs-phy: Document Nord QMP UFS PHY Document QMP UFS PHY on Qualcomm Nord SoC. Signed-off-by: Shawn Guo Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260504081442.825908-1-shengchao.guo@oss.qualcomm.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml index 9616c736b6d4..b2c5c9a375a3 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml @@ -31,6 +31,7 @@ properties: - items: - enum: - qcom,eliza-qmp-ufs-phy + - qcom,nord-qmp-ufs-phy - const: qcom,sm8650-qmp-ufs-phy - items: - enum: From 78a6a90a5c4ac29d06fc8119885b80f919950d00 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Mon, 4 May 2026 19:06:46 +0300 Subject: [PATCH 10/87] dt-bindings: phy: qcom,snps-eusb2: Document the Eliza Synopsys eUSB2 PHY The Synopsys eUSB2 PHY found on the Eliza SoC is fully compatible with the one found the SM8550. So document it by adding the compatible to the list that has the SM8550 one as fallback. Acked-by: Rob Herring (Arm) Reviewed-by: Konrad Dybcio Signed-off-by: Abel Vesa Link: https://patch.msgid.link/20260504-eliza-bindings-phy-eusb2-v2-1-fa3a1fd65ab1@oss.qualcomm.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/qcom,snps-eusb2-phy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-phy.yaml index 854f70af0a6c..096f6b546632 100644 --- a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-phy.yaml @@ -17,6 +17,7 @@ properties: oneOf: - items: - enum: + - qcom,eliza-snps-eusb2-phy - qcom,milos-snps-eusb2-phy - qcom,sar2130p-snps-eusb2-phy - qcom,sdx75-snps-eusb2-phy From d67a337d28a2d852ff539e983ad6790caf9c95f5 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Mon, 4 May 2026 19:03:41 +0300 Subject: [PATCH 11/87] dt-bindings: phy: qcom,sc8280xp-qmp-usb43dp-phy: Add Eliza QMP PHY Document the compatible for the USB QMP PHY found on the Qualcomm Eliza SoC. It is fully compatible with the one found on Qualcomm SM8650, so add it with the SM8650 as fallback. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Abel Vesa Link: https://patch.msgid.link/20260504-eliza-bindings-qmp-phy-v2-1-849c4de8d75f@oss.qualcomm.com Signed-off-by: Vinod Koul --- .../bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml | 4 ++++ 1 file changed, 4 insertions(+) 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 3d537b7f9985..4eff92343ce4 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml @@ -16,6 +16,10 @@ description: properties: compatible: oneOf: + - items: + - enum: + - qcom,eliza-qmp-usb3-dp-phy + - const: qcom,sm8650-qmp-usb3-dp-phy - items: - enum: - qcom,kaanapali-qmp-usb3-dp-phy From 1a75ecefa4fbedefc1600e43445de4e1e7f03b55 Mon Sep 17 00:00:00 2001 From: SriNavmani A Date: Mon, 4 May 2026 09:38:32 +0800 Subject: [PATCH 12/87] dt-bindings: phy: axiado,ax3000-emmc-phy: add Axiado eMMC PHY Axiado AX3000 SoC contains Arasan PHY which provides the interface to the HS200 eMMC host controller. Signed-off-by: SriNavmani A Reviewed-by: Rob Herring (Arm) Signed-off-by: Tzu-Hao Wei Link: https://patch.msgid.link/20260504-axiado-ax3000-add-emmc-phy-driver-support-v3-1-3ab7eb45b0c5@axiado.com Signed-off-by: Vinod Koul --- .../bindings/phy/axiado,ax3000-emmc-phy.yaml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/axiado,ax3000-emmc-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/axiado,ax3000-emmc-phy.yaml b/Documentation/devicetree/bindings/phy/axiado,ax3000-emmc-phy.yaml new file mode 100644 index 000000000000..61700b80e93f --- /dev/null +++ b/Documentation/devicetree/bindings/phy/axiado,ax3000-emmc-phy.yaml @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/axiado,ax3000-emmc-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Axiado AX3000 Arasan eMMC PHY + +maintainers: + - SriNavmani A + - Tzu-Hao Wei + - Prasad Bolisetty + +properties: + compatible: + const: axiado,ax3000-emmc-phy + + reg: + maxItems: 1 + + "#phy-cells": + const: 0 + +required: + - compatible + - reg + - "#phy-cells" + +additionalProperties: false + +examples: + - | + phy@80801c00 { + compatible = "axiado,ax3000-emmc-phy"; + reg = <0x80801c00 0x1000>; + #phy-cells = <0>; + }; From 9e7dfa4bcd4e2c3541c4ee954ea5e66edab94d3f Mon Sep 17 00:00:00 2001 From: SriNavmani A Date: Mon, 4 May 2026 09:38:33 +0800 Subject: [PATCH 13/87] phy: axiado: add Axiado eMMC PHY driver It provides the required configurations for Axiado eMMC PHY driver for HS200 mode. Signed-off-by: SriNavmani A Co-developed-by: Prasad Bolisetty Signed-off-by: Prasad Bolisetty Signed-off-by: Tzu-Hao Wei Link: https://patch.msgid.link/20260504-axiado-ax3000-add-emmc-phy-driver-support-v3-2-3ab7eb45b0c5@axiado.com Signed-off-by: Vinod Koul --- drivers/phy/Kconfig | 1 + drivers/phy/Makefile | 1 + drivers/phy/axiado/Kconfig | 11 ++ drivers/phy/axiado/Makefile | 1 + drivers/phy/axiado/phy-axiado-emmc.c | 217 +++++++++++++++++++++++++++ 5 files changed, 231 insertions(+) create mode 100644 drivers/phy/axiado/Kconfig create mode 100644 drivers/phy/axiado/Makefile create mode 100644 drivers/phy/axiado/phy-axiado-emmc.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 227b9a4c612e..872a7f02e1c4 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -136,6 +136,7 @@ config PHY_XGENE source "drivers/phy/allwinner/Kconfig" source "drivers/phy/amlogic/Kconfig" source "drivers/phy/apple/Kconfig" +source "drivers/phy/axiado/Kconfig" source "drivers/phy/broadcom/Kconfig" source "drivers/phy/cadence/Kconfig" source "drivers/phy/canaan/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index f49d83f00a3d..ae756fea473b 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_GENERIC_PHY) += allwinner/ \ amlogic/ \ apple/ \ + axiado/ \ broadcom/ \ cadence/ \ canaan/ \ diff --git a/drivers/phy/axiado/Kconfig b/drivers/phy/axiado/Kconfig new file mode 100644 index 000000000000..d159e0345345 --- /dev/null +++ b/drivers/phy/axiado/Kconfig @@ -0,0 +1,11 @@ +# +# PHY drivers for Axiado platforms +# + +config PHY_AX3000_EMMC + tristate "Axiado eMMC PHY driver" + depends on OF && (ARCH_AXIADO || COMPILE_TEST) + select GENERIC_PHY + help + Enables this to support for the AX3000 EMMC PHY driver. + If unsure, say N. diff --git a/drivers/phy/axiado/Makefile b/drivers/phy/axiado/Makefile new file mode 100644 index 000000000000..1e2b1ba01609 --- /dev/null +++ b/drivers/phy/axiado/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_PHY_AX3000_EMMC) += phy-axiado-emmc.o diff --git a/drivers/phy/axiado/phy-axiado-emmc.c b/drivers/phy/axiado/phy-axiado-emmc.c new file mode 100644 index 000000000000..e0e2174776ad --- /dev/null +++ b/drivers/phy/axiado/phy-axiado-emmc.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Axiado eMMC PHY driver + * + * Copyright (C) 2017 Arasan Chip Systems Inc. + * Copyright (C) 2022-2026 Axiado Corporation (or its affiliates). + * + * Based on Arasan Driver (sdhci-pci-arasan.c) + * sdhci-pci-arasan.c - Driver for Arasan PCI Controller with integrated phy. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Arasan eMMC 5.1 - PHY configuration registers */ +#define CAP_REG_IN_S1_MSB 0x04 +#define PHY_CTRL_1 0x38 +#define PHY_CTRL_2 0x3c +#define PHY_CTRL_3 0x40 +#define STATUS 0x50 + +#define DLL_ENBL BIT(26) +#define RTRIM_EN BIT(21) +#define PDB_ENBL BIT(23) +#define RETB_ENBL BIT(1) + +#define REN_STRB BIT(27) +#define REN_CMD_EN GENMASK(20, 12) + +/* Pull-UP Enable on CMD Line */ +#define PU_CMD_EN GENMASK(11, 3) + +/* Selection value for the optimum delay from 1-32 output tap lines */ +#define OTAP_DLY 0x02 +/* DLL charge pump current trim default [1000] */ +#define DLL_TRM_ICP 0x08 +/* Select the frequency range of DLL Operation */ +#define FRQ_SEL 0x01 + +#define OTAP_SEL_MASK GENMASK(10, 7) +#define DLL_TRM_MASK GENMASK(25, 22) +#define DLL_FRQSEL_MASK GENMASK(27, 25) + +#define OTAP_SEL(x) (FIELD_PREP(OTAP_SEL_MASK, x) | OTAPDLY_EN) +#define DLL_TRM(x) (FIELD_PREP(DLL_TRM_MASK, x) | DLL_ENBL) +#define DLL_FRQSEL(x) FIELD_PREP(DLL_FRQSEL_MASK, x) + +#define OTAPDLY_EN BIT(11) + +#define SEL_DLY_RXCLK BIT(18) +#define SEL_DLY_TXCLK BIT(19) + +#define CALDONE_MASK 0x40 +#define DLL_RDY_MASK 0x1 +#define MAX_CLK_BUF0 BIT(20) +#define MAX_CLK_BUF1 BIT(21) +#define MAX_CLK_BUF2 BIT(22) + +#define CLK_MULTIPLIER 0xc008e +#define POLL_TIMEOUT_MS 3000 +#define POLL_DELAY_US 100 + +struct axiado_emmc_phy { + void __iomem *reg_base; + struct device *dev; +}; + +static int axiado_emmc_phy_init(struct phy *phy) +{ + struct axiado_emmc_phy *ax_phy = phy_get_drvdata(phy); + struct device *dev = ax_phy->dev; + u32 val; + int ret; + + val = readl(ax_phy->reg_base + PHY_CTRL_1); + writel(val | RETB_ENBL | RTRIM_EN, ax_phy->reg_base + PHY_CTRL_1); + + val = readl(ax_phy->reg_base + PHY_CTRL_3); + writel(val | PDB_ENBL, ax_phy->reg_base + PHY_CTRL_3); + + ret = readl_poll_timeout(ax_phy->reg_base + STATUS, val, + val & CALDONE_MASK, POLL_DELAY_US, + POLL_TIMEOUT_MS * 1000); + if (ret) { + dev_err(dev, "PHY calibration timeout\n"); + return ret; + } + + val = readl(ax_phy->reg_base + PHY_CTRL_1); + writel(val | REN_CMD_EN | PU_CMD_EN, ax_phy->reg_base + PHY_CTRL_1); + + val = readl(ax_phy->reg_base + PHY_CTRL_2); + writel(val | REN_STRB, ax_phy->reg_base + PHY_CTRL_2); + + val = readl(ax_phy->reg_base + PHY_CTRL_3); + writel(val | MAX_CLK_BUF0 | MAX_CLK_BUF1 | MAX_CLK_BUF2, + ax_phy->reg_base + PHY_CTRL_3); + + writel(CLK_MULTIPLIER, ax_phy->reg_base + CAP_REG_IN_S1_MSB); + + val = readl(ax_phy->reg_base + PHY_CTRL_3); + writel(val | SEL_DLY_RXCLK | SEL_DLY_TXCLK, + ax_phy->reg_base + PHY_CTRL_3); + + return 0; +} + +static int axiado_emmc_phy_power_on(struct phy *phy) +{ + struct axiado_emmc_phy *ax_phy = phy_get_drvdata(phy); + struct device *dev = ax_phy->dev; + u32 val; + int ret; + + val = readl(ax_phy->reg_base + PHY_CTRL_1); + writel(val | RETB_ENBL, ax_phy->reg_base + PHY_CTRL_1); + + val = readl(ax_phy->reg_base + PHY_CTRL_3); + writel(val | PDB_ENBL, ax_phy->reg_base + PHY_CTRL_3); + + val = readl(ax_phy->reg_base + PHY_CTRL_2); + writel(val | OTAP_SEL(OTAP_DLY), ax_phy->reg_base + PHY_CTRL_2); + + val = readl(ax_phy->reg_base + PHY_CTRL_1); + writel(val | DLL_TRM(DLL_TRM_ICP), ax_phy->reg_base + PHY_CTRL_1); + + val = readl(ax_phy->reg_base + PHY_CTRL_3); + writel(val | DLL_FRQSEL(FRQ_SEL), ax_phy->reg_base + PHY_CTRL_3); + + ret = read_poll_timeout(readl, val, val & DLL_RDY_MASK, POLL_DELAY_US, + POLL_TIMEOUT_MS * 1000, false, + ax_phy->reg_base + STATUS); + if (ret) { + dev_err(dev, "DLL ready timeout\n"); + return ret; + } + + return 0; +} + +static int axiado_emmc_phy_power_off(struct phy *phy) +{ + struct axiado_emmc_phy *ax_phy = phy_get_drvdata(phy); + u32 val; + + val = readl(ax_phy->reg_base + PHY_CTRL_1); + val &= ~(DLL_TRM_MASK | DLL_ENBL); + writel(val, ax_phy->reg_base + PHY_CTRL_1); + + val = readl(ax_phy->reg_base + PHY_CTRL_3); + val &= ~(DLL_FRQSEL_MASK | PDB_ENBL); + writel(val, ax_phy->reg_base + PHY_CTRL_3); + + return 0; +} + +static const struct phy_ops axiado_emmc_phy_ops = { + .init = axiado_emmc_phy_init, + .power_on = axiado_emmc_phy_power_on, + .power_off = axiado_emmc_phy_power_off, + .owner = THIS_MODULE, +}; + +static const struct of_device_id axiado_emmc_phy_of_match[] = { + { .compatible = "axiado,ax3000-emmc-phy" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, axiado_emmc_phy_of_match); + +static int axiado_emmc_phy_probe(struct platform_device *pdev) +{ + struct axiado_emmc_phy *ax_phy; + struct phy_provider *phy_provider; + struct device *dev = &pdev->dev; + struct phy *generic_phy; + + if (!dev->of_node) + return -ENODEV; + + ax_phy = devm_kzalloc(dev, sizeof(*ax_phy), GFP_KERNEL); + if (!ax_phy) + return -ENOMEM; + + ax_phy->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ax_phy->reg_base)) + return PTR_ERR(ax_phy->reg_base); + + ax_phy->dev = dev; + + generic_phy = devm_phy_create(dev, dev->of_node, &axiado_emmc_phy_ops); + if (IS_ERR(generic_phy)) + return dev_err_probe(dev, PTR_ERR(generic_phy), + "failed to create PHY\n"); + + phy_set_drvdata(generic_phy, ax_phy); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static struct platform_driver axiado_emmc_phy_driver = { + .probe = axiado_emmc_phy_probe, + .driver = { + .name = "axiado-emmc-phy", + .of_match_table = axiado_emmc_phy_of_match, + }, +}; +module_platform_driver(axiado_emmc_phy_driver); + +MODULE_DESCRIPTION("AX3000 eMMC PHY Driver"); +MODULE_AUTHOR("Axiado Corporation"); +MODULE_LICENSE("GPL"); From 13ee293a904b7b7b0507aaa8c71f7be7e683800e Mon Sep 17 00:00:00 2001 From: Tzu-Hao Wei Date: Mon, 4 May 2026 09:38:34 +0800 Subject: [PATCH 14/87] MAINTAINERS: Add Axiado AX3000 eMMC PHY driver Add SriNavmani, Prasad and me as maintainers for Axiado AX3000 eMMC PHY driver Acked-by: Prasad Bolisetty Signed-off-by: Tzu-Hao Wei Link: https://patch.msgid.link/20260504-axiado-ax3000-add-emmc-phy-driver-support-v3-3-3ab7eb45b0c5@axiado.com Signed-off-by: Vinod Koul --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2fb1c75afd16..cf179372c7f0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4334,6 +4334,16 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml F: drivers/hwmon/axi-fan-control.c +AXIADO EMMC PHY DRIVER +M: SriNavmani A +M: Tzu-Hao Wei +M: Prasad Bolisetty +L: linux-phy@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/phy/axiado,ax3000-emmc-phy.yaml +F: drivers/phy/axiado/Kconfig +F: drivers/phy/axiado/phy-axiado-emmc.c + AXI SPI ENGINE M: Michael Hennerich M: Nuno Sá From 18af47764d75bf2cd6297289255fd7f83967e7cf Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Sat, 25 Apr 2026 20:03:09 -0400 Subject: [PATCH 15/87] phy: tegra: xusb: Make USB_CONN_GPIO select conditional on GPIOLIB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kconfiglint reports: K006: config PHY_TEGRA_XUSB selects USB_CONN_GPIO which depends on GPIOLIB, but PHY_TEGRA_XUSB does not depend on GPIOLIB K002: config PHY_TEGRA_XUSB selects visible symbol USB_CONN_GPIO which has dependencies USB_CONN_GPIO was introduced in commit 4602f3bff266 ("usb: common: add USB GPIO based connection detection driver") with a hard dependency on GPIOLIB, since it needs GPIO pins to detect USB cable connection state. Commit f67213cee2b3 ("phy: tegra: xusb: Add usb-role-switch support") added `select USB_CONN_GPIO` to PHY_TEGRA_XUSB to support USB role switching via GPIO-based detection. At that time, PHY_TEGRA_XUSB depended only on `ARCH_TEGRA`, and both the ARM32 and ARM64 ARCH_TEGRA Kconfig definitions select GPIOLIB, so the missing explicit GPIOLIB guard was not a functional problem — GPIOLIB is always available when ARCH_TEGRA is enabled. Later, commit 0d5c9bc7c680 ("phy: tegra: Select USB_COMMON for usb_get_maximum_speed()") added `depends on USB_SUPPORT` but still did not address the GPIOLIB gap. The select can force USB_CONN_GPIO on without its GPIOLIB dependency being satisfied if the Kconfig dependencies were ever restructured. Make the select conditional with `select USB_CONN_GPIO if GPIOLIB` to make the dependency explicit. This mirrors how other drivers handle optional GPIO-dependent selects throughout the kernel. Assisted-by: Claude:claude-opus-4-6 kconfiglint Signed-off-by: Sasha Levin Link: https://patch.msgid.link/20260426000309.54959-1-sashal@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/tegra/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/tegra/Kconfig b/drivers/phy/tegra/Kconfig index 342fb736da4b..f0734415fc94 100644 --- a/drivers/phy/tegra/Kconfig +++ b/drivers/phy/tegra/Kconfig @@ -3,7 +3,7 @@ config PHY_TEGRA_XUSB tristate "NVIDIA Tegra XUSB pad controller driver" depends on ARCH_TEGRA && USB_SUPPORT select USB_COMMON - select USB_CONN_GPIO + select USB_CONN_GPIO if GPIOLIB select USB_PHY help Choose this option if you have an NVIDIA Tegra SoC. From 52595824b0027d075470f7f08afe805844c1b079 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 14 Mar 2026 13:13:20 +0800 Subject: [PATCH 16/87] phy: qcom-qmp: Add missing QSERDES COM v2 registers A few registers that could be used by phy-qcom-qmp drivers are missing from qserdes-com-v2 header. Add them. Signed-off-by: Shawn Guo Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260314051325.198137-2-shengchao.guo@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h index 3ea1884f35dd..cb599c113189 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h @@ -34,6 +34,7 @@ #define QSERDES_V2_COM_LOCK_CMP3_MODE1 0x060 #define QSERDES_V2_COM_EP_CLOCK_DETECT_CTR 0x068 #define QSERDES_V2_COM_SYSCLK_DET_COMP_STATUS 0x06c +#define QSERDES_V2_COM_BG_TRIM 0x070 #define QSERDES_V2_COM_CLK_EP_DIV 0x074 #define QSERDES_V2_COM_CP_CTRL_MODE0 0x078 #define QSERDES_V2_COM_CP_CTRL_MODE1 0x07c @@ -47,6 +48,7 @@ #define QSERDES_V2_COM_CML_SYSCLK_SEL 0x0b0 #define QSERDES_V2_COM_RESETSM_CNTRL 0x0b4 #define QSERDES_V2_COM_RESETSM_CNTRL2 0x0b8 +#define QSERDES_V2_COM_RESCODE_DIV_NUM 0x0c4 #define QSERDES_V2_COM_LOCK_CMP_EN 0x0c8 #define QSERDES_V2_COM_LOCK_CMP_CFG 0x0cc #define QSERDES_V2_COM_DEC_START_MODE0 0x0d0 @@ -83,6 +85,7 @@ #define QSERDES_V2_COM_RESTRIM_CODE_STATUS 0x164 #define QSERDES_V2_COM_PLLCAL_CODE1_STATUS 0x168 #define QSERDES_V2_COM_PLLCAL_CODE2_STATUS 0x16c +#define QSERDES_V2_COM_BG_CTRL 0x170 #define QSERDES_V2_COM_CLK_SELECT 0x174 #define QSERDES_V2_COM_HSCLK_SEL 0x178 #define QSERDES_V2_COM_INTEGLOOP_BINCODE_STATUS 0x17c From 764f409b840ab400253215e765a72b903feb6afd Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 14 Mar 2026 13:13:21 +0800 Subject: [PATCH 17/87] phy: qcom-qmp: Use explicit QSERDES COM v2 register definitions As the code comments in the headers say, both qserdes-com and qserdes-com-v2 define QSERDES COM registers for QMP V2 PHY. Switch phy-qcom-qmp drivers to use register definitions in qserdes-com-v2 to make the QSERDES COM version explicit. Signed-off-by: Shawn Guo Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260314051325.198137-3-shengchao.guo@oss.qualcomm.com Signed-off-by: Vinod Koul --- .../phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c | 86 ++++---- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 162 +++++++-------- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 194 +++++++++--------- drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 188 ++++++++--------- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 180 ++++++++-------- 5 files changed, 405 insertions(+), 405 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c index a7c65cfe31df..24b5d66e9ecf 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c @@ -59,49 +59,49 @@ static const unsigned int pciephy_regs_layout[QPHY_LAYOUT_SIZE] = { }; static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1c), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x33), - QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x42), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x1f), - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x09), - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x1a), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x33), - QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x02), - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1f), - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x04), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x02), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0x2f), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x19), - QMP_PHY_INIT_CFG(QSERDES_COM_RESCODE_DIV_NUM, 0x15), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_EP_DIV, 0x19), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10), - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_RESCODE_DIV_NUM, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_ENABLE1, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x33), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP_EN, 0x42), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_TIMER1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_TIMER2, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORECLK_DIV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TIMER, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE0, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE0, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x33), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_BUF_ENABLE, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_EN_SEL, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE1, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE2, 0x19), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_RESCODE_DIV_NUM, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TRIM, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_EP_DIV, 0x19), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_ENABLE1, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_RESCODE_DIV_NUM, 0x40), }; static const struct qmp_phy_init_tbl msm8996_pcie_tx_tbl[] = { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index fed2fc9bb311..aa2f8da93a02 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -309,46 +309,46 @@ static const struct qmp_phy_init_tbl ipq6018_pcie_pcs_misc_tbl[] = { }; static const struct qmp_phy_init_tbl ipq8074_pcie_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x18), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0xf), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x1), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x0), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x1f), - QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x6), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0xf), - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x0), - QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x1), - QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x20), - QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0xa), - QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x20), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0xa), - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0xa), - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x3), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x0), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0xD), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xD04), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x33), - QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x2), - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1f), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0xb), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x0), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CTRL_BY_PSM, 0x1), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x1), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x1), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x2), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x0), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0x2f), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x19), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_EP_DIV, 0x19), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_ENABLE1, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TRIM, 0xf), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP_EN, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_MAP, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_TIMER1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_TIMER2, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CMN_CONFIG, 0x6), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_IVCO, 0xf), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SVS_MODE_CLK_SEL, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORE_CLK_EN, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORECLK_DIV, 0xa), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_RESETSM_CNTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TIMER, 0xa), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_EN_SEL, 0xa), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE0, 0x3), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE0, 0xD), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE0, 0xD04), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x33), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYS_CLK_CTRL, 0x2), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_BUF_ENABLE, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CP_CTRL_MODE0, 0xb), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE0, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CTRL_BY_PSM, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_EN_CENTER, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER2, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER1, 0x2), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER2, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE1, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE2, 0x19), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_EP_DIV, 0x19), }; static const struct qmp_phy_init_tbl ipq8074_pcie_tx_tbl[] = { @@ -752,47 +752,47 @@ static const struct qmp_phy_init_tbl ipq9574_gen3x2_pcie_pcs_misc_tbl[] = { }; static const struct qmp_phy_init_tbl qcs615_pcie_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x18), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0xf), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x1), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x0), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x1f), - QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x6), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0xf), - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x0), - QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x1), - QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x20), - QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0xa), - QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x20), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x9), - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x4), - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x3), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x0), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0xd), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x04), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x35), - QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x2), - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1f), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x4), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x30), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x0), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CTRL_BY_PSM, 0x1), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0xa), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x1), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x1), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x2), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x0), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0x2f), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x19), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_EP_DIV, 0x19), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_ENABLE1, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TRIM, 0xf), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP_EN, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_MAP, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_TIMER1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_TIMER2, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CMN_CONFIG, 0x6), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_IVCO, 0xf), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SVS_MODE_CLK_SEL, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORE_CLK_EN, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORECLK_DIV, 0xa), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_RESETSM_CNTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TIMER, 0x9), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_EN_SEL, 0x4), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE0, 0x3), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE0, 0xd), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x35), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYS_CLK_CTRL, 0x2), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_BUF_ENABLE, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CP_CTRL_MODE0, 0x4), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_CCTRL_MODE0, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE0, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CTRL_BY_PSM, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TIMER, 0xa), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_EN_CENTER, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER2, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER1, 0x2), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER2, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE1, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE2, 0x19), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_EP_DIV, 0x19), }; static const struct qmp_phy_init_tbl qcs615_pcie_rx_tbl[] = { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 771bc7c2ab50..48252ab0379e 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -147,52 +147,52 @@ static const struct qmp_phy_init_tbl milos_ufsphy_pcs[] = { }; static const struct qmp_phy_init_tbl msm8996_ufsphy_serdes[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x0e), - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0xd7), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), - QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x05), - QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x10), - QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x20), - QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x54), - QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05), - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x02), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xff), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE1, 0x98), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE1, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE1, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE1, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE1, 0x32), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CMN_CONFIG, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_EN_SEL, 0xd7), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYS_CLK_CTRL, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORECLK_DIV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORECLK_DIV_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_CTRL, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_RESETSM_CNTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_TIMER1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_TIMER2, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_MAP, 0x54), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE1_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE2_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE0, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE0, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE1, 0x98), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CP_CTRL_MODE1, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_CCTRL_MODE1, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE1, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE1_MODE1, 0xd6), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE1, 0x32), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE1, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE1, 0x00), }; static const struct qmp_phy_init_tbl msm8996_ufsphy_tx[] = { @@ -320,60 +320,60 @@ static const struct qmp_phy_init_tbl sc7280_ufsphy_hs_g4_rx[] = { }; static const struct qmp_phy_init_tbl sm6115_ufsphy_serdes[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x0e), - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), - QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x02), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x20), - QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x04), - QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05), - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x02), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xff), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE1, 0x98), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE1, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE1, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE1, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE1, 0x32), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_INITVAL1, 0xff), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CMN_CONFIG, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_EN_SEL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORECLK_DIV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORECLK_DIV_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_RESETSM_CNTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_TIMER1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_TIMER2, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE1_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE2_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE0, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE0, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE1, 0x98), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CP_CTRL_MODE1, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_CCTRL_MODE1, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE1, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE1_MODE1, 0xd6), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE1, 0x32), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE1, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TRIM, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_INITVAL1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_INITVAL2, 0x00), }; static const struct qmp_phy_init_tbl sm6115_ufsphy_hs_b_serdes[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x44), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_MAP, 0x44), }; static const struct qmp_phy_init_tbl sm6115_ufsphy_tx[] = { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c index b0ecd5ba2464..f43650f9a45c 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c @@ -244,40 +244,40 @@ static const struct qmp_phy_init_tbl glymur_usb3_uniphy_pcs_usb_tbl[] = { }; static const struct qmp_phy_init_tbl ipq9574_usb3_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x1a), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_EN_SEL, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TRIM, 0x0f), QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYS_CLK_CTRL, 0x06), /* PLL and Loop filter settings */ - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x68), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0xab), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0xaa), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x02), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x09), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0xa0), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xaa), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x29), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x68), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE0, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CP_CTRL_MODE0, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE0, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE0, 0x29), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TIMER, 0x0a), /* SSC settings */ - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x7d), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER1, 0x7d), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE2, 0x05), }; static const struct qmp_phy_init_tbl ipq9574_usb3_tx_tbl[] = { @@ -326,40 +326,40 @@ static const struct qmp_phy_init_tbl ipq9574_usb3_pcs_tbl[] = { }; static const struct qmp_phy_init_tbl ipq8074_usb3_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x1a), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_EN_SEL, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TRIM, 0x0f), QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYS_CLK_CTRL, 0x06), /* PLL and Loop filter settings */ - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x15), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x34), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE0, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE0, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TIMER, 0x0a), /* SSC settings */ - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0xde), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE1, 0xde), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE2, 0x07), }; static const struct qmp_phy_init_tbl ipq8074_usb3_rx_tbl[] = { @@ -401,40 +401,40 @@ static const struct qmp_phy_init_tbl ipq8074_usb3_pcs_tbl[] = { }; static const struct qmp_phy_init_tbl msm8996_usb3_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), - QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06), - QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_EN_SEL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TRIM, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYS_CLK_CTRL, 0x04), /* PLL and Loop filter settings */ - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x15), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x34), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE0, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE0, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TIMER, 0x0a), /* SSC settings */ - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0xde), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE1, 0xde), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE2, 0x07), }; static const struct qmp_phy_init_tbl msm8996_usb3_tx_tbl[] = { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index c342479a3798..67efe80a51a6 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -177,44 +177,44 @@ static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = { }; static const struct qmp_phy_init_tbl qcm2290_usb3_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), - QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), - QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL2, 0x08), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x15), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x34), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0xde), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x07), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_INITVAL, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CTRL_BY_PSM, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_EN_SEL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYS_CLK_CTRL, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_RESETSM_CNTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_RESETSM_CNTRL2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TRIM, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE0, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORECLK_DIV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE0, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE1, 0xde), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SSC_STEP_SIZE2, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_INITVAL, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CTRL_BY_PSM, 0x01), }; static const struct qmp_phy_init_tbl qcm2290_usb3_tx_tbl[] = { @@ -291,63 +291,63 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = { }; static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x37), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x0e), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_CTRL, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x40), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x08), - QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x05), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_EN_SEL, 0x37), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYS_CLK_CTRL, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_ENABLE1, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_CTRL, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_BUF_ENABLE, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TIMER, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORECLK_DIV, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CORE_CLK_EN, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_CMN_CONFIG, 0x02), }; static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_rbr[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x2c), - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x69), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xbf), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x21), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x2c), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x69), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE0, 0xbf), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE0, 0x21), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x00), }; static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x24), - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x69), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x3f), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x38), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x69), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE0, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE0, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x00), }; static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr2[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x20), - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x8c), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x7f), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x70), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x8c), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START3_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP1_MODE0, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP2_MODE0, 0x70), + QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x00), }; static const struct qmp_phy_init_tbl qmp_v2_dp_tx_tbl[] = { @@ -906,9 +906,9 @@ static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp) writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - writel(0x20, qmp->dp_serdes + QSERDES_COM_RESETSM_CNTRL); + writel(0x20, qmp->dp_serdes + QSERDES_V2_COM_RESETSM_CNTRL); - if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_C_READY_STATUS, + if (readl_poll_timeout(qmp->dp_serdes + QSERDES_V2_COM_C_READY_STATUS, status, ((status & BIT(0)) > 0), 500, @@ -917,7 +917,7 @@ static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp) return -ETIMEDOUT; } - if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_CMN_STATUS, + if (readl_poll_timeout(qmp->dp_serdes + QSERDES_V2_COM_CMN_STATUS, status, ((status & BIT(0)) > 0), 500, @@ -926,7 +926,7 @@ static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp) return -ETIMEDOUT; } - if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_CMN_STATUS, + if (readl_poll_timeout(qmp->dp_serdes + QSERDES_V2_COM_CMN_STATUS, status, ((status & BIT(1)) > 0), 500, From 9dfdd6e7bebd63eeef0ba57493adee91c34ae338 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 14 Mar 2026 13:13:22 +0800 Subject: [PATCH 18/87] phy: qcom-qmp-usbc: Use register definitions in qserdes-txrx-v3 The register definitions in header qserdes-txrx-v2 and qserdes-txrx-v3 are actually identical. Considering that QSERDES TX/RX v2 is already defined by header qserdes-txrx, qserdes-txrx-v2 is really just a duplication of qserdes-txrx-v3 for QSERDES TX/RX v3. Switch qcom-qmp-usbc driver to use v3 registers. Signed-off-by: Shawn Guo Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260314051325.198137-4-shengchao.guo@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 64 ++++++++++++------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 67efe80a51a6..fb4be9531e7a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -351,20 +351,20 @@ static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr2[] = { }; static const struct qmp_phy_init_tbl qmp_v2_dp_tx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V2_TX_TRANSCEIVER_BIAS_EN, 0x1a), - QMP_PHY_INIT_CFG(QSERDES_V2_TX_VMODE_CTRL1, 0x40), - QMP_PHY_INIT_CFG(QSERDES_V2_TX_PRE_STALL_LDO_BOOST_EN, 0x30), - QMP_PHY_INIT_CFG(QSERDES_V2_TX_INTERFACE_SELECT, 0x3d), - QMP_PHY_INIT_CFG(QSERDES_V2_TX_CLKBUF_ENABLE, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_V2_TX_RESET_TSYNC_EN, 0x03), - QMP_PHY_INIT_CFG(QSERDES_V2_TX_TRAN_DRVR_EMP_EN, 0x03), - QMP_PHY_INIT_CFG(QSERDES_V2_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_INTERFACE_MODE, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_EMP_POST1_LVL, 0x2b), - QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_DRV_LVL, 0x2f), - QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_BAND, 0x4), - QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET_TX, 0x12), - QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET_RX, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_TRANSCEIVER_BIAS_EN, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_VMODE_CTRL1, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_PRE_STALL_LDO_BOOST_EN, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_INTERFACE_SELECT, 0x3d), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_CLKBUF_ENABLE, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RESET_TSYNC_EN, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_TRAN_DRVR_EMP_EN, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_TX_INTERFACE_MODE, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_TX_EMP_POST1_LVL, 0x2b), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_TX_DRV_LVL, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_TX_BAND, 0x4), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x12), }; struct qmp_usbc_offsets { @@ -809,10 +809,10 @@ static int qmp_v2_configure_dp_swing(struct qmp_usbc *qmp) if (voltage_swing_cfg == 0xff && pre_emphasis_cfg == 0xff) return -EINVAL; - writel(voltage_swing_cfg, tx + QSERDES_V2_TX_TX_DRV_LVL); - writel(pre_emphasis_cfg, tx + QSERDES_V2_TX_TX_EMP_POST1_LVL); - writel(voltage_swing_cfg, tx2 + QSERDES_V2_TX_TX_DRV_LVL); - writel(pre_emphasis_cfg, tx2 + QSERDES_V2_TX_TX_EMP_POST1_LVL); + writel(voltage_swing_cfg, tx + QSERDES_V3_TX_TX_DRV_LVL); + writel(pre_emphasis_cfg, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL); + writel(voltage_swing_cfg, tx2 + QSERDES_V3_TX_TX_DRV_LVL); + writel(pre_emphasis_cfg, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL); return 0; } @@ -871,17 +871,17 @@ static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp) void __iomem *tx2 = qmp->dp_tx2; /* program default setting first */ - writel(0x2a, tx + QSERDES_V2_TX_TX_DRV_LVL); - writel(0x20, tx + QSERDES_V2_TX_TX_EMP_POST1_LVL); - writel(0x2a, tx2 + QSERDES_V2_TX_TX_DRV_LVL); - writel(0x20, tx2 + QSERDES_V2_TX_TX_EMP_POST1_LVL); + writel(0x2a, tx + QSERDES_V3_TX_TX_DRV_LVL); + writel(0x20, tx + QSERDES_V3_TX_TX_EMP_POST1_LVL); + writel(0x2a, tx2 + QSERDES_V3_TX_TX_DRV_LVL); + writel(0x20, tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL); if (dp_opts->link_rate >= 2700) { - writel(0xc4, tx + QSERDES_V2_TX_LANE_MODE_1); - writel(0xc4, tx2 + QSERDES_V2_TX_LANE_MODE_1); + writel(0xc4, tx + QSERDES_V3_TX_LANE_MODE_1); + writel(0xc4, tx2 + QSERDES_V3_TX_LANE_MODE_1); } else { - writel(0xc6, tx + QSERDES_V2_TX_LANE_MODE_1); - writel(0xc6, tx2 + QSERDES_V2_TX_LANE_MODE_1); + writel(0xc6, tx + QSERDES_V3_TX_LANE_MODE_1); + writel(0xc6, tx2 + QSERDES_V3_TX_LANE_MODE_1); } qmp_v2_configure_dp_swing(qmp); @@ -955,12 +955,12 @@ static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp) return -ETIMEDOUT; } - writel(0x3f, qmp->dp_tx + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); - writel(0x10, qmp->dp_tx + QSERDES_V2_TX_HIGHZ_DRVR_EN); - writel(0x0a, qmp->dp_tx + QSERDES_V2_TX_TX_POL_INV); - writel(0x3f, qmp->dp_tx2 + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); - writel(0x10, qmp->dp_tx2 + QSERDES_V2_TX_HIGHZ_DRVR_EN); - writel(0x0a, qmp->dp_tx2 + QSERDES_V2_TX_TX_POL_INV); + writel(0x3f, qmp->dp_tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN); + writel(0x10, qmp->dp_tx + QSERDES_V3_TX_HIGHZ_DRVR_EN); + writel(0x0a, qmp->dp_tx + QSERDES_V3_TX_TX_POL_INV); + writel(0x3f, qmp->dp_tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN); + writel(0x10, qmp->dp_tx2 + QSERDES_V3_TX_HIGHZ_DRVR_EN); + writel(0x0a, qmp->dp_tx2 + QSERDES_V3_TX_TX_POL_INV); writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); From c834f0a69051e5db52172262dadf8f7b5ff58bd0 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 14 Mar 2026 13:13:23 +0800 Subject: [PATCH 19/87] phy: qcom-qmp-usbc: Rename QCS615 DP PHY variables and functions Commit 81791c45c8e0 ("phy: qcom: qmp-usbc: Add QCS615 USB/DP PHY config and DP mode support") chose to name QCS615 DP PHY variables/functions with qmp_v2 prefix, by assuming that QMP PHY registers are versioned as a whole. However, the reality is that the registers are versioned in sub-modules like QSERDES COM and QSERDES TXRX respectively, e.g. QCS615 DP PHY has registers of QSERDES COM v2 and QSERDES TXRX v3. Thus it may cause confusion that qmp_v2_xxx table and functions access QSERDES TXRX v3 registers. Rename QCS615 DP PHY variables and functions to be prefixed by qcs615 instead of qmp_v2. This better aligns with how the driver names USB3 PHY variables for QCM2290 etc. Signed-off-by: Shawn Guo Link: https://patch.msgid.link/20260314051325.198137-5-shengchao.guo@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 66 ++++++++++++------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index fb4be9531e7a..d4b55e55dd77 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -290,7 +290,7 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88), }; -static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl[] = { +static const struct qmp_phy_init_tbl qcs615_dp_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V2_COM_SVS_MODE_CLK_SEL, 0x01), QMP_PHY_INIT_CFG(QSERDES_V2_COM_SYSCLK_EN_SEL, 0x37), QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x00), @@ -317,7 +317,7 @@ static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V2_COM_CMN_CONFIG, 0x02), }; -static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_rbr[] = { +static const struct qmp_phy_init_tbl qcs615_dp_serdes_tbl_rbr[] = { QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x2c), QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x69), QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x00), @@ -328,7 +328,7 @@ static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_rbr[] = { QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x00), }; -static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr[] = { +static const struct qmp_phy_init_tbl qcs615_dp_serdes_tbl_hbr[] = { QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x24), QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x69), QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x00), @@ -339,7 +339,7 @@ static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr[] = { QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x00), }; -static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr2[] = { +static const struct qmp_phy_init_tbl qcs615_dp_serdes_tbl_hbr2[] = { QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x20), QMP_PHY_INIT_CFG(QSERDES_V2_COM_DEC_START_MODE0, 0x8c), QMP_PHY_INIT_CFG(QSERDES_V2_COM_DIV_FRAC_START1_MODE0, 0x00), @@ -350,7 +350,7 @@ static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr2[] = { QMP_PHY_INIT_CFG(QSERDES_V2_COM_LOCK_CMP3_MODE0, 0x00), }; -static const struct qmp_phy_init_tbl qmp_v2_dp_tx_tbl[] = { +static const struct qmp_phy_init_tbl qcs615_dp_tx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V3_TX_TRANSCEIVER_BIAS_EN, 0x1a), QMP_PHY_INIT_CFG(QSERDES_V3_TX_VMODE_CTRL1, 0x40), QMP_PHY_INIT_CFG(QSERDES_V3_TX_PRE_STALL_LDO_BOOST_EN, 0x30), @@ -555,14 +555,14 @@ static const struct qmp_usbc_offsets qmp_usbc_usb3dp_offsets_qcs615 = { .dp_dp_phy = 0x1000, }; -static const u8 qmp_v2_dp_pre_emphasis_hbr2_rbr[4][4] = { +static const u8 qcs615_dp_pre_emphasis_hbr2_rbr[4][4] = { {0x00, 0x0b, 0x12, 0xff}, {0x00, 0x0a, 0x12, 0xff}, {0x00, 0x0c, 0xff, 0xff}, {0xff, 0xff, 0xff, 0xff} }; -static const u8 qmp_v2_dp_voltage_swing_hbr2_rbr[4][4] = { +static const u8 qcs615_dp_voltage_swing_hbr2_rbr[4][4] = { {0x07, 0x0f, 0x14, 0xff}, {0x11, 0x1d, 0x1f, 0xff}, {0x18, 0x1f, 0xff, 0xff}, @@ -641,10 +641,10 @@ static const struct qmp_phy_cfg qcs615_usb3phy_cfg = { .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; -static void qmp_v2_dp_aux_init(struct qmp_usbc *qmp); -static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp); -static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp); -static int qmp_v2_calibrate_dp_phy(struct qmp_usbc *qmp); +static void qcs615_qmp_dp_aux_init(struct qmp_usbc *qmp); +static void qcs615_qmp_configure_dp_tx(struct qmp_usbc *qmp); +static int qcs615_qmp_configure_dp_phy(struct qmp_usbc *qmp); +static int qcs615_qmp_calibrate_dp_phy(struct qmp_usbc *qmp); static const struct qmp_phy_cfg qcs615_usb3dp_phy_cfg = { .offsets = &qmp_usbc_usb3dp_offsets_qcs615, @@ -660,25 +660,25 @@ static const struct qmp_phy_cfg qcs615_usb3dp_phy_cfg = { .regs = qmp_v3_usb3phy_regs_layout_qcm2290, - .dp_serdes_tbl = qmp_v2_dp_serdes_tbl, - .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl), - .dp_tx_tbl = qmp_v2_dp_tx_tbl, - .dp_tx_tbl_num = ARRAY_SIZE(qmp_v2_dp_tx_tbl), + .dp_serdes_tbl = qcs615_dp_serdes_tbl, + .dp_serdes_tbl_num = ARRAY_SIZE(qcs615_dp_serdes_tbl), + .dp_tx_tbl = qcs615_dp_tx_tbl, + .dp_tx_tbl_num = ARRAY_SIZE(qcs615_dp_tx_tbl), - .serdes_tbl_rbr = qmp_v2_dp_serdes_tbl_rbr, - .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_rbr), - .serdes_tbl_hbr = qmp_v2_dp_serdes_tbl_hbr, - .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_hbr), - .serdes_tbl_hbr2 = qmp_v2_dp_serdes_tbl_hbr2, - .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_hbr2), + .serdes_tbl_rbr = qcs615_dp_serdes_tbl_rbr, + .serdes_tbl_rbr_num = ARRAY_SIZE(qcs615_dp_serdes_tbl_rbr), + .serdes_tbl_hbr = qcs615_dp_serdes_tbl_hbr, + .serdes_tbl_hbr_num = ARRAY_SIZE(qcs615_dp_serdes_tbl_hbr), + .serdes_tbl_hbr2 = qcs615_dp_serdes_tbl_hbr2, + .serdes_tbl_hbr2_num = ARRAY_SIZE(qcs615_dp_serdes_tbl_hbr2), - .swing_tbl = &qmp_v2_dp_voltage_swing_hbr2_rbr, - .pre_emphasis_tbl = &qmp_v2_dp_pre_emphasis_hbr2_rbr, + .swing_tbl = &qcs615_dp_voltage_swing_hbr2_rbr, + .pre_emphasis_tbl = &qcs615_dp_pre_emphasis_hbr2_rbr, - .dp_aux_init = qmp_v2_dp_aux_init, - .configure_dp_tx = qmp_v2_configure_dp_tx, - .configure_dp_phy = qmp_v2_configure_dp_phy, - .calibrate_dp_phy = qmp_v2_calibrate_dp_phy, + .dp_aux_init = qcs615_qmp_dp_aux_init, + .configure_dp_tx = qcs615_qmp_configure_dp_tx, + .configure_dp_phy = qcs615_qmp_configure_dp_phy, + .calibrate_dp_phy = qcs615_qmp_calibrate_dp_phy, .reset_list = usb3dpphy_reset_l, .num_resets = ARRAY_SIZE(usb3dpphy_reset_l), @@ -744,7 +744,7 @@ static int qmp_usbc_com_exit(struct phy *phy) return 0; } -static void qmp_v2_dp_aux_init(struct qmp_usbc *qmp) +static void qcs615_qmp_dp_aux_init(struct qmp_usbc *qmp) { writel(DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN | @@ -774,7 +774,7 @@ static void qmp_v2_dp_aux_init(struct qmp_usbc *qmp) qmp->dp_dp_phy + QSERDES_V2_DP_PHY_AUX_INTERRUPT_MASK); } -static int qmp_v2_configure_dp_swing(struct qmp_usbc *qmp) +static int qcs615_qmp_configure_dp_swing(struct qmp_usbc *qmp) { const struct qmp_phy_cfg *cfg = qmp->cfg; const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; @@ -864,7 +864,7 @@ static int qmp_usbc_configure_dp_clocks(struct qmp_usbc *qmp) return 0; } -static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp) +static void qcs615_qmp_configure_dp_tx(struct qmp_usbc *qmp) { const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; void __iomem *tx = qmp->dp_tx; @@ -884,10 +884,10 @@ static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp) writel(0xc6, tx2 + QSERDES_V3_TX_LANE_MODE_1); } - qmp_v2_configure_dp_swing(qmp); + qcs615_qmp_configure_dp_swing(qmp); } -static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp) +static int qcs615_qmp_configure_dp_phy(struct qmp_usbc *qmp) { u32 status; int ret; @@ -977,7 +977,7 @@ static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp) return 0; } -static int qmp_v2_calibrate_dp_phy(struct qmp_usbc *qmp) +static int qcs615_qmp_calibrate_dp_phy(struct qmp_usbc *qmp) { static const u8 cfg1_settings[] = {0x13, 0x23, 0x1d}; u8 val; From 9b1270d2b85bb7ce6bbc71232375b21d8be0b799 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 14 Mar 2026 13:13:24 +0800 Subject: [PATCH 20/87] phy: qcom-qmp: Drop unused register headers None of qcom-qmp drivers uses header qserdes-com or qserdes-txrx-v2. Drop them. Signed-off-by: Shawn Guo Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260314051325.198137-6-shengchao.guo@oss.qualcomm.com Signed-off-by: Vinod Koul --- .../phy/qualcomm/phy-qcom-qmp-qserdes-com.h | 140 ------------------ .../qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h | 68 --------- drivers/phy/qualcomm/phy-qcom-qmp.h | 2 - 3 files changed, 210 deletions(-) delete mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com.h delete mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com.h deleted file mode 100644 index 7fa5363feeb9..000000000000 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com.h +++ /dev/null @@ -1,140 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. - */ - -#ifndef QCOM_PHY_QMP_QSERDES_COM_H_ -#define QCOM_PHY_QMP_QSERDES_COM_H_ - -/* Only for QMP V2 PHY - QSERDES COM registers */ -#define QSERDES_COM_ATB_SEL1 0x000 -#define QSERDES_COM_ATB_SEL2 0x004 -#define QSERDES_COM_FREQ_UPDATE 0x008 -#define QSERDES_COM_BG_TIMER 0x00c -#define QSERDES_COM_SSC_EN_CENTER 0x010 -#define QSERDES_COM_SSC_ADJ_PER1 0x014 -#define QSERDES_COM_SSC_ADJ_PER2 0x018 -#define QSERDES_COM_SSC_PER1 0x01c -#define QSERDES_COM_SSC_PER2 0x020 -#define QSERDES_COM_SSC_STEP_SIZE1 0x024 -#define QSERDES_COM_SSC_STEP_SIZE2 0x028 -#define QSERDES_COM_POST_DIV 0x02c -#define QSERDES_COM_POST_DIV_MUX 0x030 -#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x034 -#define QSERDES_COM_CLK_ENABLE1 0x038 -#define QSERDES_COM_SYS_CLK_CTRL 0x03c -#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x040 -#define QSERDES_COM_PLL_EN 0x044 -#define QSERDES_COM_PLL_IVCO 0x048 -#define QSERDES_COM_LOCK_CMP1_MODE0 0x04c -#define QSERDES_COM_LOCK_CMP2_MODE0 0x050 -#define QSERDES_COM_LOCK_CMP3_MODE0 0x054 -#define QSERDES_COM_LOCK_CMP1_MODE1 0x058 -#define QSERDES_COM_LOCK_CMP2_MODE1 0x05c -#define QSERDES_COM_LOCK_CMP3_MODE1 0x060 -#define QSERDES_COM_LOCK_CMP1_MODE2 0x064 -#define QSERDES_COM_CMN_RSVD0 0x064 -#define QSERDES_COM_LOCK_CMP2_MODE2 0x068 -#define QSERDES_COM_EP_CLOCK_DETECT_CTRL 0x068 -#define QSERDES_COM_LOCK_CMP3_MODE2 0x06c -#define QSERDES_COM_SYSCLK_DET_COMP_STATUS 0x06c -#define QSERDES_COM_BG_TRIM 0x070 -#define QSERDES_COM_CLK_EP_DIV 0x074 -#define QSERDES_COM_CP_CTRL_MODE0 0x078 -#define QSERDES_COM_CP_CTRL_MODE1 0x07c -#define QSERDES_COM_CP_CTRL_MODE2 0x080 -#define QSERDES_COM_CMN_RSVD1 0x080 -#define QSERDES_COM_PLL_RCTRL_MODE0 0x084 -#define QSERDES_COM_PLL_RCTRL_MODE1 0x088 -#define QSERDES_COM_PLL_RCTRL_MODE2 0x08c -#define QSERDES_COM_CMN_RSVD2 0x08c -#define QSERDES_COM_PLL_CCTRL_MODE0 0x090 -#define QSERDES_COM_PLL_CCTRL_MODE1 0x094 -#define QSERDES_COM_PLL_CCTRL_MODE2 0x098 -#define QSERDES_COM_CMN_RSVD3 0x098 -#define QSERDES_COM_PLL_CNTRL 0x09c -#define QSERDES_COM_PHASE_SEL_CTRL 0x0a0 -#define QSERDES_COM_PHASE_SEL_DC 0x0a4 -#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL 0x0a8 -#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM 0x0a8 -#define QSERDES_COM_SYSCLK_EN_SEL 0x0ac -#define QSERDES_COM_CML_SYSCLK_SEL 0x0b0 -#define QSERDES_COM_RESETSM_CNTRL 0x0b4 -#define QSERDES_COM_RESETSM_CNTRL2 0x0b8 -#define QSERDES_COM_RESTRIM_CTRL 0x0bc -#define QSERDES_COM_RESTRIM_CTRL2 0x0c0 -#define QSERDES_COM_RESCODE_DIV_NUM 0x0c4 -#define QSERDES_COM_LOCK_CMP_EN 0x0c8 -#define QSERDES_COM_LOCK_CMP_CFG 0x0cc -#define QSERDES_COM_DEC_START_MODE0 0x0d0 -#define QSERDES_COM_DEC_START_MODE1 0x0d4 -#define QSERDES_COM_DEC_START_MODE2 0x0d8 -#define QSERDES_COM_VCOCAL_DEADMAN_CTRL 0x0d8 -#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x0dc -#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x0e0 -#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x0e4 -#define QSERDES_COM_DIV_FRAC_START1_MODE1 0x0e8 -#define QSERDES_COM_DIV_FRAC_START2_MODE1 0x0ec -#define QSERDES_COM_DIV_FRAC_START3_MODE1 0x0f0 -#define QSERDES_COM_DIV_FRAC_START1_MODE2 0x0f4 -#define QSERDES_COM_VCO_TUNE_MINVAL1 0x0f4 -#define QSERDES_COM_DIV_FRAC_START2_MODE2 0x0f8 -#define QSERDES_COM_VCO_TUNE_MINVAL2 0x0f8 -#define QSERDES_COM_DIV_FRAC_START3_MODE2 0x0fc -#define QSERDES_COM_CMN_RSVD4 0x0fc -#define QSERDES_COM_INTEGLOOP_INITVAL 0x100 -#define QSERDES_COM_INTEGLOOP_EN 0x104 -#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x108 -#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x10c -#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 0x110 -#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 0x114 -#define QSERDES_COM_INTEGLOOP_GAIN0_MODE2 0x118 -#define QSERDES_COM_VCO_TUNE_MAXVAL1 0x118 -#define QSERDES_COM_INTEGLOOP_GAIN1_MODE2 0x11c -#define QSERDES_COM_VCO_TUNE_MAXVAL2 0x11c -#define QSERDES_COM_RES_TRIM_CONTROL2 0x120 -#define QSERDES_COM_VCO_TUNE_CTRL 0x124 -#define QSERDES_COM_VCO_TUNE_MAP 0x128 -#define QSERDES_COM_VCO_TUNE1_MODE0 0x12c -#define QSERDES_COM_VCO_TUNE2_MODE0 0x130 -#define QSERDES_COM_VCO_TUNE1_MODE1 0x134 -#define QSERDES_COM_VCO_TUNE2_MODE1 0x138 -#define QSERDES_COM_VCO_TUNE1_MODE2 0x13c -#define QSERDES_COM_VCO_TUNE_INITVAL1 0x13c -#define QSERDES_COM_VCO_TUNE2_MODE2 0x140 -#define QSERDES_COM_VCO_TUNE_INITVAL2 0x140 -#define QSERDES_COM_VCO_TUNE_TIMER1 0x144 -#define QSERDES_COM_VCO_TUNE_TIMER2 0x148 -#define QSERDES_COM_SAR 0x14c -#define QSERDES_COM_SAR_CLK 0x150 -#define QSERDES_COM_SAR_CODE_OUT_STATUS 0x154 -#define QSERDES_COM_SAR_CODE_READY_STATUS 0x158 -#define QSERDES_COM_CMN_STATUS 0x15c -#define QSERDES_COM_RESET_SM_STATUS 0x160 -#define QSERDES_COM_RESTRIM_CODE_STATUS 0x164 -#define QSERDES_COM_PLLCAL_CODE1_STATUS 0x168 -#define QSERDES_COM_PLLCAL_CODE2_STATUS 0x16c -#define QSERDES_COM_BG_CTRL 0x170 -#define QSERDES_COM_CLK_SELECT 0x174 -#define QSERDES_COM_HSCLK_SEL 0x178 -#define QSERDES_COM_INTEGLOOP_BINCODE_STATUS 0x17c -#define QSERDES_COM_PLL_ANALOG 0x180 -#define QSERDES_COM_CORECLK_DIV 0x184 -#define QSERDES_COM_SW_RESET 0x188 -#define QSERDES_COM_CORE_CLK_EN 0x18c -#define QSERDES_COM_C_READY_STATUS 0x190 -#define QSERDES_COM_CMN_CONFIG 0x194 -#define QSERDES_COM_CMN_RATE_OVERRIDE 0x198 -#define QSERDES_COM_SVS_MODE_CLK_SEL 0x19c -#define QSERDES_COM_DEBUG_BUS0 0x1a0 -#define QSERDES_COM_DEBUG_BUS1 0x1a4 -#define QSERDES_COM_DEBUG_BUS2 0x1a8 -#define QSERDES_COM_DEBUG_BUS3 0x1ac -#define QSERDES_COM_DEBUG_BUS_SEL 0x1b0 -#define QSERDES_COM_CMN_MISC1 0x1b4 -#define QSERDES_COM_CMN_MISC2 0x1b8 -#define QSERDES_COM_CORECLK_DIV_MODE1 0x1bc -#define QSERDES_COM_CORECLK_DIV_MODE2 0x1c0 -#define QSERDES_COM_CMN_RSVD5 0x1c4 - -#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h deleted file mode 100644 index 34919720b7bc..000000000000 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. - */ - -#ifndef QCOM_PHY_QMP_QSERDES_TXRX_V2_H_ -#define QCOM_PHY_QMP_QSERDES_TXRX_V2_H_ - -/* Only for QMP V2 PHY - TX registers */ -#define QSERDES_V2_TX_BIST_MODE_LANENO 0x000 -#define QSERDES_V2_TX_CLKBUF_ENABLE 0x008 -#define QSERDES_V2_TX_TX_EMP_POST1_LVL 0x00c -#define QSERDES_V2_TX_TX_DRV_LVL 0x01c -#define QSERDES_V2_TX_RESET_TSYNC_EN 0x024 -#define QSERDES_V2_TX_PRE_STALL_LDO_BOOST_EN 0x028 -#define QSERDES_V2_TX_TX_BAND 0x02c -#define QSERDES_V2_TX_SLEW_CNTL 0x030 -#define QSERDES_V2_TX_INTERFACE_SELECT 0x034 -#define QSERDES_V2_TX_RES_CODE_LANE_TX 0x03c -#define QSERDES_V2_TX_RES_CODE_LANE_RX 0x040 -#define QSERDES_V2_TX_RES_CODE_LANE_OFFSET_TX 0x044 -#define QSERDES_V2_TX_RES_CODE_LANE_OFFSET_RX 0x048 -#define QSERDES_V2_TX_DEBUG_BUS_SEL 0x058 -#define QSERDES_V2_TX_TRANSCEIVER_BIAS_EN 0x05c -#define QSERDES_V2_TX_HIGHZ_DRVR_EN 0x060 -#define QSERDES_V2_TX_TX_POL_INV 0x064 -#define QSERDES_V2_TX_PARRATE_REC_DETECT_IDLE_EN 0x068 -#define QSERDES_V2_TX_LANE_MODE_1 0x08c -#define QSERDES_V2_TX_LANE_MODE_2 0x090 -#define QSERDES_V2_TX_LANE_MODE_3 0x094 -#define QSERDES_V2_TX_RCV_DETECT_LVL_2 0x0a4 -#define QSERDES_V2_TX_TRAN_DRVR_EMP_EN 0x0c0 -#define QSERDES_V2_TX_TX_INTERFACE_MODE 0x0c4 -#define QSERDES_V2_TX_VMODE_CTRL1 0x0f0 - -/* Only for QMP V2 PHY - RX registers */ -#define QSERDES_V2_RX_UCDR_FO_GAIN 0x008 -#define QSERDES_V2_RX_UCDR_SO_GAIN_HALF 0x00c -#define QSERDES_V2_RX_UCDR_SO_GAIN 0x014 -#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN_HALF 0x024 -#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN_QUARTER 0x028 -#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN 0x02c -#define QSERDES_V2_RX_UCDR_FASTLOCK_FO_GAIN 0x030 -#define QSERDES_V2_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034 -#define QSERDES_V2_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c -#define QSERDES_V2_RX_UCDR_FASTLOCK_COUNT_HIGH 0x040 -#define QSERDES_V2_RX_UCDR_PI_CONTROLS 0x044 -#define QSERDES_V2_RX_RX_TERM_BW 0x07c -#define QSERDES_V2_RX_VGA_CAL_CNTRL1 0x0bc -#define QSERDES_V2_RX_VGA_CAL_CNTRL2 0x0c0 -#define QSERDES_V2_RX_RX_EQ_GAIN2_LSB 0x0c8 -#define QSERDES_V2_RX_RX_EQ_GAIN2_MSB 0x0cc -#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL1 0x0d0 -#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d4 -#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL3 0x0d8 -#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL4 0x0dc -#define QSERDES_V2_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x0f8 -#define QSERDES_V2_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x0fc -#define QSERDES_V2_RX_SIGDET_ENABLES 0x100 -#define QSERDES_V2_RX_SIGDET_CNTRL 0x104 -#define QSERDES_V2_RX_SIGDET_LVL 0x108 -#define QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL 0x10c -#define QSERDES_V2_RX_RX_BAND 0x110 -#define QSERDES_V2_RX_RX_INTERFACE_MODE 0x11c -#define QSERDES_V2_RX_RX_MODE_00 0x164 -#define QSERDES_V2_RX_RX_MODE_01 0x168 - -#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index a873bdd7bffe..19e91f44e84e 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -6,11 +6,9 @@ #ifndef QCOM_PHY_QMP_H_ #define QCOM_PHY_QMP_H_ -#include "phy-qcom-qmp-qserdes-com.h" #include "phy-qcom-qmp-qserdes-txrx.h" #include "phy-qcom-qmp-qserdes-com-v2.h" -#include "phy-qcom-qmp-qserdes-txrx-v2.h" #include "phy-qcom-qmp-qserdes-com-v3.h" #include "phy-qcom-qmp-qserdes-txrx-v3.h" From c7cd4798fafa84581502094d0be282072851c9b7 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 14 Mar 2026 13:13:25 +0800 Subject: [PATCH 21/87] phy: qcom-qmp: Make QSERDES TXRX v2 registers explicit Rename QSERDES TXRX v2 registers and the header to make version explicit. Signed-off-by: Shawn Guo Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260314051325.198137-7-shengchao.guo@oss.qualcomm.com Signed-off-by: Vinod Koul --- .../phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c | 24 +- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 50 ++--- .../qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h | 205 ++++++++++++++++++ .../phy/qualcomm/phy-qcom-qmp-qserdes-txrx.h | 205 ------------------ drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 60 ++--- drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 74 +++---- drivers/phy/qualcomm/phy-qcom-qmp.h | 3 +- 7 files changed, 310 insertions(+), 311 deletions(-) create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h delete mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx.h diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c index 24b5d66e9ecf..37e96493b722 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c @@ -105,21 +105,21 @@ static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = { }; static const struct qmp_phy_init_tbl msm8996_pcie_tx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), - QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_LANE_MODE, 0x06), }; static const struct qmp_phy_init_tbl msm8996_pcie_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_ENABLES, 0x1c), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x01), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x00), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0xdb), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_BAND, 0x18), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN, 0x04), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN_HALF, 0x04), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x14), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x19), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_ENABLES, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL3, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL4, 0xdb), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_BAND, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SO_GAIN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SO_GAIN_HALF, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_LVL, 0x19), }; static const struct qmp_phy_init_tbl msm8996_pcie_pcs_tbl[] = { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index aa2f8da93a02..75afbd15aaf4 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -352,22 +352,22 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_serdes_tbl[] = { }; static const struct qmp_phy_init_tbl ipq8074_pcie_tx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), - QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x6), - QMP_PHY_INIT_CFG(QSERDES_TX_RES_CODE_LANE_OFFSET, 0x2), - QMP_PHY_INIT_CFG(QSERDES_TX_RCV_DETECT_LVL_2, 0x12), - QMP_PHY_INIT_CFG(QSERDES_TX_TX_EMP_POST1_LVL, 0x36), - QMP_PHY_INIT_CFG(QSERDES_TX_SLEW_CNTL, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_LANE_MODE, 0x6), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET, 0x2), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_EMP_POST1_LVL, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_SLEW_CNTL, 0x0a), }; static const struct qmp_phy_init_tbl ipq8074_pcie_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_ENABLES, 0x1c), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x14), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x1), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x0), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0xdb), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN, 0x4), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_ENABLES, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL3, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL4, 0xdb), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SO_GAIN, 0x4), }; static const struct qmp_phy_init_tbl ipq8074_pcie_pcs_tbl[] = { @@ -796,21 +796,21 @@ static const struct qmp_phy_init_tbl qcs615_pcie_serdes_tbl[] = { }; static const struct qmp_phy_init_tbl qcs615_pcie_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_ENABLES, 0x1c), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x14), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x1), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x0), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0xdb), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN, 0x4), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN_HALF, 0x4), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_ENABLES, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL3, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL4, 0xdb), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SO_GAIN, 0x4), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SO_GAIN_HALF, 0x4), }; static const struct qmp_phy_init_tbl qcs615_pcie_tx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), - QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x6), - QMP_PHY_INIT_CFG(QSERDES_TX_RES_CODE_LANE_OFFSET, 0x2), - QMP_PHY_INIT_CFG(QSERDES_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_LANE_MODE, 0x6), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET, 0x2), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_RCV_DETECT_LVL_2, 0x12), }; static const struct qmp_phy_init_tbl qcs615_pcie_pcs_tbl[] = { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h new file mode 100644 index 000000000000..9ae0cf95e317 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_QSERDES_TXRX_V2_H_ +#define QCOM_PHY_QMP_QSERDES_TXRX_V2_H_ + +/* Only for QMP V2 PHY - TX registers */ +#define QSERDES_V2_TX_BIST_MODE_LANENO 0x000 +#define QSERDES_V2_TX_BIST_INVERT 0x004 +#define QSERDES_V2_TX_CLKBUF_ENABLE 0x008 +#define QSERDES_V2_TX_CMN_CONTROL_ONE 0x00c +#define QSERDES_V2_TX_CMN_CONTROL_TWO 0x010 +#define QSERDES_V2_TX_CMN_CONTROL_THREE 0x014 +#define QSERDES_V2_TX_TX_EMP_POST1_LVL 0x018 +#define QSERDES_V2_TX_TX_POST2_EMPH 0x01c +#define QSERDES_V2_TX_TX_BOOST_LVL_UP_DN 0x020 +#define QSERDES_V2_TX_HP_PD_ENABLES 0x024 +#define QSERDES_V2_TX_TX_IDLE_LVL_LARGE_AMP 0x028 +#define QSERDES_V2_TX_TX_DRV_LVL 0x02c +#define QSERDES_V2_TX_TX_DRV_LVL_OFFSET 0x030 +#define QSERDES_V2_TX_RESET_TSYNC_EN 0x034 +#define QSERDES_V2_TX_PRE_STALL_LDO_BOOST_EN 0x038 +#define QSERDES_V2_TX_TX_BAND 0x03c +#define QSERDES_V2_TX_SLEW_CNTL 0x040 +#define QSERDES_V2_TX_INTERFACE_SELECT 0x044 +#define QSERDES_V2_TX_LPB_EN 0x048 +#define QSERDES_V2_TX_RES_CODE_LANE_TX 0x04c +#define QSERDES_V2_TX_RES_CODE_LANE_RX 0x050 +#define QSERDES_V2_TX_RES_CODE_LANE_OFFSET 0x054 +#define QSERDES_V2_TX_PERL_LENGTH1 0x058 +#define QSERDES_V2_TX_PERL_LENGTH2 0x05c +#define QSERDES_V2_TX_SERDES_BYP_EN_OUT 0x060 +#define QSERDES_V2_TX_DEBUG_BUS_SEL 0x064 +#define QSERDES_V2_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN 0x068 +#define QSERDES_V2_TX_TX_POL_INV 0x06c +#define QSERDES_V2_TX_PARRATE_REC_DETECT_IDLE_EN 0x070 +#define QSERDES_V2_TX_BIST_PATTERN1 0x074 +#define QSERDES_V2_TX_BIST_PATTERN2 0x078 +#define QSERDES_V2_TX_BIST_PATTERN3 0x07c +#define QSERDES_V2_TX_BIST_PATTERN4 0x080 +#define QSERDES_V2_TX_BIST_PATTERN5 0x084 +#define QSERDES_V2_TX_BIST_PATTERN6 0x088 +#define QSERDES_V2_TX_BIST_PATTERN7 0x08c +#define QSERDES_V2_TX_BIST_PATTERN8 0x090 +#define QSERDES_V2_TX_LANE_MODE 0x094 +#define QSERDES_V2_TX_IDAC_CAL_LANE_MODE 0x098 +#define QSERDES_V2_TX_IDAC_CAL_LANE_MODE_CONFIGURATION 0x09c +#define QSERDES_V2_TX_ATB_SEL1 0x0a0 +#define QSERDES_V2_TX_ATB_SEL2 0x0a4 +#define QSERDES_V2_TX_RCV_DETECT_LVL 0x0a8 +#define QSERDES_V2_TX_RCV_DETECT_LVL_2 0x0ac +#define QSERDES_V2_TX_PRBS_SEED1 0x0b0 +#define QSERDES_V2_TX_PRBS_SEED2 0x0b4 +#define QSERDES_V2_TX_PRBS_SEED3 0x0b8 +#define QSERDES_V2_TX_PRBS_SEED4 0x0bc +#define QSERDES_V2_TX_RESET_GEN 0x0c0 +#define QSERDES_V2_TX_RESET_GEN_MUXES 0x0c4 +#define QSERDES_V2_TX_TRAN_DRVR_EMP_EN 0x0c8 +#define QSERDES_V2_TX_TX_INTERFACE_MODE 0x0cc +#define QSERDES_V2_TX_PWM_CTRL 0x0d0 +#define QSERDES_V2_TX_PWM_ENCODED_OR_DATA 0x0d4 +#define QSERDES_V2_TX_PWM_GEAR_1_DIVIDER_BAND2 0x0d8 +#define QSERDES_V2_TX_PWM_GEAR_2_DIVIDER_BAND2 0x0dc +#define QSERDES_V2_TX_PWM_GEAR_3_DIVIDER_BAND2 0x0e0 +#define QSERDES_V2_TX_PWM_GEAR_4_DIVIDER_BAND2 0x0e4 +#define QSERDES_V2_TX_PWM_GEAR_1_DIVIDER_BAND0_1 0x0e8 +#define QSERDES_V2_TX_PWM_GEAR_2_DIVIDER_BAND0_1 0x0ec +#define QSERDES_V2_TX_PWM_GEAR_3_DIVIDER_BAND0_1 0x0f0 +#define QSERDES_V2_TX_PWM_GEAR_4_DIVIDER_BAND0_1 0x0f4 +#define QSERDES_V2_TX_VMODE_CTRL1 0x0f8 +#define QSERDES_V2_TX_VMODE_CTRL2 0x0fc +#define QSERDES_V2_TX_TX_ALOG_INTF_OBSV_CNTL 0x100 +#define QSERDES_V2_TX_BIST_STATUS 0x104 +#define QSERDES_V2_TX_BIST_ERROR_COUNT1 0x108 +#define QSERDES_V2_TX_BIST_ERROR_COUNT2 0x10c +#define QSERDES_V2_TX_TX_ALOG_INTF_OBSV 0x110 + +/* Only for QMP V2 PHY - RX registers */ +#define QSERDES_V2_RX_UCDR_FO_GAIN_HALF 0x000 +#define QSERDES_V2_RX_UCDR_FO_GAIN_QUARTER 0x004 +#define QSERDES_V2_RX_UCDR_FO_GAIN_EIGHTH 0x008 +#define QSERDES_V2_RX_UCDR_FO_GAIN 0x00c +#define QSERDES_V2_RX_UCDR_SO_GAIN_HALF 0x010 +#define QSERDES_V2_RX_UCDR_SO_GAIN_QUARTER 0x014 +#define QSERDES_V2_RX_UCDR_SO_GAIN_EIGHTH 0x018 +#define QSERDES_V2_RX_UCDR_SO_GAIN 0x01c +#define QSERDES_V2_RX_UCDR_SVS_FO_GAIN_HALF 0x020 +#define QSERDES_V2_RX_UCDR_SVS_FO_GAIN_QUARTER 0x024 +#define QSERDES_V2_RX_UCDR_SVS_FO_GAIN_EIGHTH 0x028 +#define QSERDES_V2_RX_UCDR_SVS_FO_GAIN 0x02c +#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN_HALF 0x030 +#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN_QUARTER 0x034 +#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN_EIGHTH 0x038 +#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN 0x03c +#define QSERDES_V2_RX_UCDR_FASTLOCK_FO_GAIN 0x040 +#define QSERDES_V2_RX_UCDR_FD_GAIN 0x044 +#define QSERDES_V2_RX_UCDR_SO_SATURATION_AND_ENABLE 0x048 +#define QSERDES_V2_RX_UCDR_FO_TO_SO_DELAY 0x04c +#define QSERDES_V2_RX_UCDR_FASTLOCK_COUNT_LOW 0x050 +#define QSERDES_V2_RX_UCDR_FASTLOCK_COUNT_HIGH 0x054 +#define QSERDES_V2_RX_UCDR_MODULATE 0x058 +#define QSERDES_V2_RX_UCDR_PI_CONTROLS 0x05c +#define QSERDES_V2_RX_RBIST_CONTROL 0x060 +#define QSERDES_V2_RX_AUX_CONTROL 0x064 +#define QSERDES_V2_RX_AUX_DATA_TCOARSE 0x068 +#define QSERDES_V2_RX_AUX_DATA_TFINE_LSB 0x06c +#define QSERDES_V2_RX_AUX_DATA_TFINE_MSB 0x070 +#define QSERDES_V2_RX_RCLK_AUXDATA_SEL 0x074 +#define QSERDES_V2_RX_AC_JTAG_ENABLE 0x078 +#define QSERDES_V2_RX_AC_JTAG_INITP 0x07c +#define QSERDES_V2_RX_AC_JTAG_INITN 0x080 +#define QSERDES_V2_RX_AC_JTAG_LVL 0x084 +#define QSERDES_V2_RX_AC_JTAG_MODE 0x088 +#define QSERDES_V2_RX_AC_JTAG_RESET 0x08c +#define QSERDES_V2_RX_RX_TERM_BW 0x090 +#define QSERDES_V2_RX_RX_RCVR_IQ_EN 0x094 +#define QSERDES_V2_RX_RX_IDAC_I_DC_OFFSETS 0x098 +#define QSERDES_V2_RX_RX_IDAC_IBAR_DC_OFFSETS 0x09c +#define QSERDES_V2_RX_RX_IDAC_Q_DC_OFFSETS 0x0a0 +#define QSERDES_V2_RX_RX_IDAC_QBAR_DC_OFFSETS 0x0a4 +#define QSERDES_V2_RX_RX_IDAC_A_DC_OFFSETS 0x0a8 +#define QSERDES_V2_RX_RX_IDAC_ABAR_DC_OFFSETS 0x0ac +#define QSERDES_V2_RX_RX_IDAC_EN 0x0b0 +#define QSERDES_V2_RX_RX_IDAC_ENABLES 0x0b4 +#define QSERDES_V2_RX_RX_IDAC_SIGN 0x0b8 +#define QSERDES_V2_RX_RX_HIGHZ_HIGHRATE 0x0bc +#define QSERDES_V2_RX_RX_TERM_AC_BYPASS_DC_COUPLE_OFFSET 0x0c0 +#define QSERDES_V2_RX_RX_EQ_GAIN1_LSB 0x0c4 +#define QSERDES_V2_RX_RX_EQ_GAIN1_MSB 0x0c8 +#define QSERDES_V2_RX_RX_EQ_GAIN2_LSB 0x0cc +#define QSERDES_V2_RX_RX_EQ_GAIN2_MSB 0x0d0 +#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL1 0x0d4 +#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d8 +#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL3 0x0dc +#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL4 0x0e0 +#define QSERDES_V2_RX_RX_IDAC_CAL_CONFIGURATION 0x0e4 +#define QSERDES_V2_RX_RX_IDAC_TSETTLE_LOW 0x0e8 +#define QSERDES_V2_RX_RX_IDAC_TSETTLE_HIGH 0x0ec +#define QSERDES_V2_RX_RX_IDAC_ENDSAMP_LOW 0x0f0 +#define QSERDES_V2_RX_RX_IDAC_ENDSAMP_HIGH 0x0f4 +#define QSERDES_V2_RX_RX_IDAC_MIDPOINT_LOW 0x0f8 +#define QSERDES_V2_RX_RX_IDAC_MIDPOINT_HIGH 0x0fc +#define QSERDES_V2_RX_RX_EQ_OFFSET_LSB 0x100 +#define QSERDES_V2_RX_RX_EQ_OFFSET_MSB 0x104 +#define QSERDES_V2_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x108 +#define QSERDES_V2_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x10c +#define QSERDES_V2_RX_SIGDET_ENABLES 0x110 +#define QSERDES_V2_RX_SIGDET_CNTRL 0x114 +#define QSERDES_V2_RX_SIGDET_LVL 0x118 +#define QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL 0x11c +#define QSERDES_V2_RX_RX_BAND 0x120 +#define QSERDES_V2_RX_CDR_FREEZE_UP_DN 0x124 +#define QSERDES_V2_RX_CDR_RESET_OVERRIDE 0x128 +#define QSERDES_V2_RX_RX_INTERFACE_MODE 0x12c +#define QSERDES_V2_RX_JITTER_GEN_MODE 0x130 +#define QSERDES_V2_RX_BUJ_AMP 0x134 +#define QSERDES_V2_RX_SJ_AMP1 0x138 +#define QSERDES_V2_RX_SJ_AMP2 0x13c +#define QSERDES_V2_RX_SJ_PER1 0x140 +#define QSERDES_V2_RX_SJ_PER2 0x144 +#define QSERDES_V2_RX_BUJ_STEP_FREQ1 0x148 +#define QSERDES_V2_RX_BUJ_STEP_FREQ2 0x14c +#define QSERDES_V2_RX_PPM_OFFSET1 0x150 +#define QSERDES_V2_RX_PPM_OFFSET2 0x154 +#define QSERDES_V2_RX_SIGN_PPM_PERIOD1 0x158 +#define QSERDES_V2_RX_SIGN_PPM_PERIOD2 0x15c +#define QSERDES_V2_RX_SSC_CTRL 0x160 +#define QSERDES_V2_RX_SSC_COUNT1 0x164 +#define QSERDES_V2_RX_SSC_COUNT2 0x168 +#define QSERDES_V2_RX_RX_ALOG_INTF_OBSV_CNTL 0x16c +#define QSERDES_V2_RX_RX_PWM_ENABLE_AND_DATA 0x170 +#define QSERDES_V2_RX_RX_PWM_GEAR1_TIMEOUT_COUNT 0x174 +#define QSERDES_V2_RX_RX_PWM_GEAR2_TIMEOUT_COUNT 0x178 +#define QSERDES_V2_RX_RX_PWM_GEAR3_TIMEOUT_COUNT 0x17c +#define QSERDES_V2_RX_RX_PWM_GEAR4_TIMEOUT_COUNT 0x180 +#define QSERDES_V2_RX_PI_CTRL1 0x184 +#define QSERDES_V2_RX_PI_CTRL2 0x188 +#define QSERDES_V2_RX_PI_QUAD 0x18c +#define QSERDES_V2_RX_IDATA1 0x190 +#define QSERDES_V2_RX_IDATA2 0x194 +#define QSERDES_V2_RX_AUX_DATA1 0x198 +#define QSERDES_V2_RX_AUX_DATA2 0x19c +#define QSERDES_V2_RX_AC_JTAG_OUTP 0x1a0 +#define QSERDES_V2_RX_AC_JTAG_OUTN 0x1a4 +#define QSERDES_V2_RX_RX_SIGDET 0x1a8 +#define QSERDES_V2_RX_RX_VDCOFF 0x1ac +#define QSERDES_V2_RX_IDAC_CAL_ON 0x1b0 +#define QSERDES_V2_RX_IDAC_STATUS_I 0x1b4 +#define QSERDES_V2_RX_IDAC_STATUS_IBAR 0x1b8 +#define QSERDES_V2_RX_IDAC_STATUS_Q 0x1bc +#define QSERDES_V2_RX_IDAC_STATUS_QBAR 0x1c0 +#define QSERDES_V2_RX_IDAC_STATUS_A 0x1c4 +#define QSERDES_V2_RX_IDAC_STATUS_ABAR 0x1c8 +#define QSERDES_V2_RX_CALST_STATUS_I 0x1cc +#define QSERDES_V2_RX_CALST_STATUS_Q 0x1d0 +#define QSERDES_V2_RX_CALST_STATUS_A 0x1d4 +#define QSERDES_V2_RX_RX_ALOG_INTF_OBSV 0x1d8 +#define QSERDES_V2_RX_READ_EQCODE 0x1dc +#define QSERDES_V2_RX_READ_OFFSETCODE 0x1e0 +#define QSERDES_V2_RX_IA_ERROR_COUNTER_LOW 0x1e4 +#define QSERDES_V2_RX_IA_ERROR_COUNTER_HIGH 0x1e8 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx.h deleted file mode 100644 index d20694513eb4..000000000000 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx.h +++ /dev/null @@ -1,205 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. - */ - -#ifndef QCOM_PHY_QMP_QSERDES_TXRX_H_ -#define QCOM_PHY_QMP_QSERDES_TXRX_H_ - -/* Only for QMP V2 PHY - TX registers */ -#define QSERDES_TX_BIST_MODE_LANENO 0x000 -#define QSERDES_TX_BIST_INVERT 0x004 -#define QSERDES_TX_CLKBUF_ENABLE 0x008 -#define QSERDES_TX_CMN_CONTROL_ONE 0x00c -#define QSERDES_TX_CMN_CONTROL_TWO 0x010 -#define QSERDES_TX_CMN_CONTROL_THREE 0x014 -#define QSERDES_TX_TX_EMP_POST1_LVL 0x018 -#define QSERDES_TX_TX_POST2_EMPH 0x01c -#define QSERDES_TX_TX_BOOST_LVL_UP_DN 0x020 -#define QSERDES_TX_HP_PD_ENABLES 0x024 -#define QSERDES_TX_TX_IDLE_LVL_LARGE_AMP 0x028 -#define QSERDES_TX_TX_DRV_LVL 0x02c -#define QSERDES_TX_TX_DRV_LVL_OFFSET 0x030 -#define QSERDES_TX_RESET_TSYNC_EN 0x034 -#define QSERDES_TX_PRE_STALL_LDO_BOOST_EN 0x038 -#define QSERDES_TX_TX_BAND 0x03c -#define QSERDES_TX_SLEW_CNTL 0x040 -#define QSERDES_TX_INTERFACE_SELECT 0x044 -#define QSERDES_TX_LPB_EN 0x048 -#define QSERDES_TX_RES_CODE_LANE_TX 0x04c -#define QSERDES_TX_RES_CODE_LANE_RX 0x050 -#define QSERDES_TX_RES_CODE_LANE_OFFSET 0x054 -#define QSERDES_TX_PERL_LENGTH1 0x058 -#define QSERDES_TX_PERL_LENGTH2 0x05c -#define QSERDES_TX_SERDES_BYP_EN_OUT 0x060 -#define QSERDES_TX_DEBUG_BUS_SEL 0x064 -#define QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN 0x068 -#define QSERDES_TX_TX_POL_INV 0x06c -#define QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN 0x070 -#define QSERDES_TX_BIST_PATTERN1 0x074 -#define QSERDES_TX_BIST_PATTERN2 0x078 -#define QSERDES_TX_BIST_PATTERN3 0x07c -#define QSERDES_TX_BIST_PATTERN4 0x080 -#define QSERDES_TX_BIST_PATTERN5 0x084 -#define QSERDES_TX_BIST_PATTERN6 0x088 -#define QSERDES_TX_BIST_PATTERN7 0x08c -#define QSERDES_TX_BIST_PATTERN8 0x090 -#define QSERDES_TX_LANE_MODE 0x094 -#define QSERDES_TX_IDAC_CAL_LANE_MODE 0x098 -#define QSERDES_TX_IDAC_CAL_LANE_MODE_CONFIGURATION 0x09c -#define QSERDES_TX_ATB_SEL1 0x0a0 -#define QSERDES_TX_ATB_SEL2 0x0a4 -#define QSERDES_TX_RCV_DETECT_LVL 0x0a8 -#define QSERDES_TX_RCV_DETECT_LVL_2 0x0ac -#define QSERDES_TX_PRBS_SEED1 0x0b0 -#define QSERDES_TX_PRBS_SEED2 0x0b4 -#define QSERDES_TX_PRBS_SEED3 0x0b8 -#define QSERDES_TX_PRBS_SEED4 0x0bc -#define QSERDES_TX_RESET_GEN 0x0c0 -#define QSERDES_TX_RESET_GEN_MUXES 0x0c4 -#define QSERDES_TX_TRAN_DRVR_EMP_EN 0x0c8 -#define QSERDES_TX_TX_INTERFACE_MODE 0x0cc -#define QSERDES_TX_PWM_CTRL 0x0d0 -#define QSERDES_TX_PWM_ENCODED_OR_DATA 0x0d4 -#define QSERDES_TX_PWM_GEAR_1_DIVIDER_BAND2 0x0d8 -#define QSERDES_TX_PWM_GEAR_2_DIVIDER_BAND2 0x0dc -#define QSERDES_TX_PWM_GEAR_3_DIVIDER_BAND2 0x0e0 -#define QSERDES_TX_PWM_GEAR_4_DIVIDER_BAND2 0x0e4 -#define QSERDES_TX_PWM_GEAR_1_DIVIDER_BAND0_1 0x0e8 -#define QSERDES_TX_PWM_GEAR_2_DIVIDER_BAND0_1 0x0ec -#define QSERDES_TX_PWM_GEAR_3_DIVIDER_BAND0_1 0x0f0 -#define QSERDES_TX_PWM_GEAR_4_DIVIDER_BAND0_1 0x0f4 -#define QSERDES_TX_VMODE_CTRL1 0x0f8 -#define QSERDES_TX_VMODE_CTRL2 0x0fc -#define QSERDES_TX_TX_ALOG_INTF_OBSV_CNTL 0x100 -#define QSERDES_TX_BIST_STATUS 0x104 -#define QSERDES_TX_BIST_ERROR_COUNT1 0x108 -#define QSERDES_TX_BIST_ERROR_COUNT2 0x10c -#define QSERDES_TX_TX_ALOG_INTF_OBSV 0x110 - -/* Only for QMP V2 PHY - RX registers */ -#define QSERDES_RX_UCDR_FO_GAIN_HALF 0x000 -#define QSERDES_RX_UCDR_FO_GAIN_QUARTER 0x004 -#define QSERDES_RX_UCDR_FO_GAIN_EIGHTH 0x008 -#define QSERDES_RX_UCDR_FO_GAIN 0x00c -#define QSERDES_RX_UCDR_SO_GAIN_HALF 0x010 -#define QSERDES_RX_UCDR_SO_GAIN_QUARTER 0x014 -#define QSERDES_RX_UCDR_SO_GAIN_EIGHTH 0x018 -#define QSERDES_RX_UCDR_SO_GAIN 0x01c -#define QSERDES_RX_UCDR_SVS_FO_GAIN_HALF 0x020 -#define QSERDES_RX_UCDR_SVS_FO_GAIN_QUARTER 0x024 -#define QSERDES_RX_UCDR_SVS_FO_GAIN_EIGHTH 0x028 -#define QSERDES_RX_UCDR_SVS_FO_GAIN 0x02c -#define QSERDES_RX_UCDR_SVS_SO_GAIN_HALF 0x030 -#define QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER 0x034 -#define QSERDES_RX_UCDR_SVS_SO_GAIN_EIGHTH 0x038 -#define QSERDES_RX_UCDR_SVS_SO_GAIN 0x03c -#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN 0x040 -#define QSERDES_RX_UCDR_FD_GAIN 0x044 -#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE 0x048 -#define QSERDES_RX_UCDR_FO_TO_SO_DELAY 0x04c -#define QSERDES_RX_UCDR_FASTLOCK_COUNT_LOW 0x050 -#define QSERDES_RX_UCDR_FASTLOCK_COUNT_HIGH 0x054 -#define QSERDES_RX_UCDR_MODULATE 0x058 -#define QSERDES_RX_UCDR_PI_CONTROLS 0x05c -#define QSERDES_RX_RBIST_CONTROL 0x060 -#define QSERDES_RX_AUX_CONTROL 0x064 -#define QSERDES_RX_AUX_DATA_TCOARSE 0x068 -#define QSERDES_RX_AUX_DATA_TFINE_LSB 0x06c -#define QSERDES_RX_AUX_DATA_TFINE_MSB 0x070 -#define QSERDES_RX_RCLK_AUXDATA_SEL 0x074 -#define QSERDES_RX_AC_JTAG_ENABLE 0x078 -#define QSERDES_RX_AC_JTAG_INITP 0x07c -#define QSERDES_RX_AC_JTAG_INITN 0x080 -#define QSERDES_RX_AC_JTAG_LVL 0x084 -#define QSERDES_RX_AC_JTAG_MODE 0x088 -#define QSERDES_RX_AC_JTAG_RESET 0x08c -#define QSERDES_RX_RX_TERM_BW 0x090 -#define QSERDES_RX_RX_RCVR_IQ_EN 0x094 -#define QSERDES_RX_RX_IDAC_I_DC_OFFSETS 0x098 -#define QSERDES_RX_RX_IDAC_IBAR_DC_OFFSETS 0x09c -#define QSERDES_RX_RX_IDAC_Q_DC_OFFSETS 0x0a0 -#define QSERDES_RX_RX_IDAC_QBAR_DC_OFFSETS 0x0a4 -#define QSERDES_RX_RX_IDAC_A_DC_OFFSETS 0x0a8 -#define QSERDES_RX_RX_IDAC_ABAR_DC_OFFSETS 0x0ac -#define QSERDES_RX_RX_IDAC_EN 0x0b0 -#define QSERDES_RX_RX_IDAC_ENABLES 0x0b4 -#define QSERDES_RX_RX_IDAC_SIGN 0x0b8 -#define QSERDES_RX_RX_HIGHZ_HIGHRATE 0x0bc -#define QSERDES_RX_RX_TERM_AC_BYPASS_DC_COUPLE_OFFSET 0x0c0 -#define QSERDES_RX_RX_EQ_GAIN1_LSB 0x0c4 -#define QSERDES_RX_RX_EQ_GAIN1_MSB 0x0c8 -#define QSERDES_RX_RX_EQ_GAIN2_LSB 0x0cc -#define QSERDES_RX_RX_EQ_GAIN2_MSB 0x0d0 -#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1 0x0d4 -#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d8 -#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 0x0dc -#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 0x0e0 -#define QSERDES_RX_RX_IDAC_CAL_CONFIGURATION 0x0e4 -#define QSERDES_RX_RX_IDAC_TSETTLE_LOW 0x0e8 -#define QSERDES_RX_RX_IDAC_TSETTLE_HIGH 0x0ec -#define QSERDES_RX_RX_IDAC_ENDSAMP_LOW 0x0f0 -#define QSERDES_RX_RX_IDAC_ENDSAMP_HIGH 0x0f4 -#define QSERDES_RX_RX_IDAC_MIDPOINT_LOW 0x0f8 -#define QSERDES_RX_RX_IDAC_MIDPOINT_HIGH 0x0fc -#define QSERDES_RX_RX_EQ_OFFSET_LSB 0x100 -#define QSERDES_RX_RX_EQ_OFFSET_MSB 0x104 -#define QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x108 -#define QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x10c -#define QSERDES_RX_SIGDET_ENABLES 0x110 -#define QSERDES_RX_SIGDET_CNTRL 0x114 -#define QSERDES_RX_SIGDET_LVL 0x118 -#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL 0x11c -#define QSERDES_RX_RX_BAND 0x120 -#define QSERDES_RX_CDR_FREEZE_UP_DN 0x124 -#define QSERDES_RX_CDR_RESET_OVERRIDE 0x128 -#define QSERDES_RX_RX_INTERFACE_MODE 0x12c -#define QSERDES_RX_JITTER_GEN_MODE 0x130 -#define QSERDES_RX_BUJ_AMP 0x134 -#define QSERDES_RX_SJ_AMP1 0x138 -#define QSERDES_RX_SJ_AMP2 0x13c -#define QSERDES_RX_SJ_PER1 0x140 -#define QSERDES_RX_SJ_PER2 0x144 -#define QSERDES_RX_BUJ_STEP_FREQ1 0x148 -#define QSERDES_RX_BUJ_STEP_FREQ2 0x14c -#define QSERDES_RX_PPM_OFFSET1 0x150 -#define QSERDES_RX_PPM_OFFSET2 0x154 -#define QSERDES_RX_SIGN_PPM_PERIOD1 0x158 -#define QSERDES_RX_SIGN_PPM_PERIOD2 0x15c -#define QSERDES_RX_SSC_CTRL 0x160 -#define QSERDES_RX_SSC_COUNT1 0x164 -#define QSERDES_RX_SSC_COUNT2 0x168 -#define QSERDES_RX_RX_ALOG_INTF_OBSV_CNTL 0x16c -#define QSERDES_RX_RX_PWM_ENABLE_AND_DATA 0x170 -#define QSERDES_RX_RX_PWM_GEAR1_TIMEOUT_COUNT 0x174 -#define QSERDES_RX_RX_PWM_GEAR2_TIMEOUT_COUNT 0x178 -#define QSERDES_RX_RX_PWM_GEAR3_TIMEOUT_COUNT 0x17c -#define QSERDES_RX_RX_PWM_GEAR4_TIMEOUT_COUNT 0x180 -#define QSERDES_RX_PI_CTRL1 0x184 -#define QSERDES_RX_PI_CTRL2 0x188 -#define QSERDES_RX_PI_QUAD 0x18c -#define QSERDES_RX_IDATA1 0x190 -#define QSERDES_RX_IDATA2 0x194 -#define QSERDES_RX_AUX_DATA1 0x198 -#define QSERDES_RX_AUX_DATA2 0x19c -#define QSERDES_RX_AC_JTAG_OUTP 0x1a0 -#define QSERDES_RX_AC_JTAG_OUTN 0x1a4 -#define QSERDES_RX_RX_SIGDET 0x1a8 -#define QSERDES_RX_RX_VDCOFF 0x1ac -#define QSERDES_RX_IDAC_CAL_ON 0x1b0 -#define QSERDES_RX_IDAC_STATUS_I 0x1b4 -#define QSERDES_RX_IDAC_STATUS_IBAR 0x1b8 -#define QSERDES_RX_IDAC_STATUS_Q 0x1bc -#define QSERDES_RX_IDAC_STATUS_QBAR 0x1c0 -#define QSERDES_RX_IDAC_STATUS_A 0x1c4 -#define QSERDES_RX_IDAC_STATUS_ABAR 0x1c8 -#define QSERDES_RX_CALST_STATUS_I 0x1cc -#define QSERDES_RX_CALST_STATUS_Q 0x1d0 -#define QSERDES_RX_CALST_STATUS_A 0x1d4 -#define QSERDES_RX_RX_ALOG_INTF_OBSV 0x1d8 -#define QSERDES_RX_READ_EQCODE 0x1dc -#define QSERDES_RX_READ_OFFSETCODE 0x1e0 -#define QSERDES_RX_IA_ERROR_COUNTER_LOW 0x1e4 -#define QSERDES_RX_IA_ERROR_COUNTER_HIGH 0x1e8 - -#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 48252ab0379e..c7fc19a2aed1 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -196,22 +196,22 @@ static const struct qmp_phy_init_tbl msm8996_ufsphy_serdes[] = { }; static const struct qmp_phy_init_tbl msm8996_ufsphy_tx[] = { - QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), - QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_LANE_MODE, 0x02), }; static const struct qmp_phy_init_tbl msm8996_ufsphy_rx[] = { - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x24), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x02), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_INTERFACE_MODE, 0x00), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x18), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_TERM_BW, 0x5b), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xff), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3f), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xff), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0E), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_LVL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_CNTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_INTERFACE_MODE, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_TERM_BW, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQ_GAIN1_LSB, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQ_GAIN1_MSB, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQ_GAIN2_LSB, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQ_GAIN2_MSB, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0E), }; static const struct qmp_phy_init_tbl sc7280_ufsphy_tx[] = { @@ -377,26 +377,26 @@ static const struct qmp_phy_init_tbl sm6115_ufsphy_hs_b_serdes[] = { }; static const struct qmp_phy_init_tbl sm6115_ufsphy_tx[] = { - QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), - QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_LANE_MODE, 0x06), }; static const struct qmp_phy_init_tbl sm6115_ufsphy_rx[] = { - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x24), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x0F), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_INTERFACE_MODE, 0x40), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1E), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_TERM_BW, 0x5B), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xFF), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3F), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xFF), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x3F), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0D), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN_HALF, 0x04), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN, 0x04), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5B), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_LVL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_CNTRL, 0x0F), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_INTERFACE_MODE, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL, 0x1E), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_TERM_BW, 0x5B), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQ_GAIN1_LSB, 0xFF), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQ_GAIN1_MSB, 0x3F), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQ_GAIN2_LSB, 0xFF), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQ_GAIN2_MSB, 0x3F), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0D), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SVS_SO_GAIN_HALF, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SVS_SO_GAIN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5B), }; static const struct qmp_phy_init_tbl sm6115_ufsphy_pcs[] = { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c index f43650f9a45c..c5507168e135 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c @@ -248,7 +248,7 @@ static const struct qmp_phy_init_tbl ipq9574_usb3_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN, 0x08), QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x30), QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TRIM, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), QMP_PHY_INIT_CFG(QSERDES_V2_COM_SVS_MODE_CLK_SEL, 0x01), QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x00), QMP_PHY_INIT_CFG(QSERDES_V2_COM_CMN_CONFIG, 0x06), @@ -281,22 +281,22 @@ static const struct qmp_phy_init_tbl ipq9574_usb3_serdes_tbl[] = { }; static const struct qmp_phy_init_tbl ipq9574_usb3_tx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), - QMP_PHY_INIT_CFG(QSERDES_TX_RCV_DETECT_LVL_2, 0x12), - QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_LANE_MODE, 0x06), }; static const struct qmp_phy_init_tbl ipq9574_usb3_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN, 0x06), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x6c), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4c), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0xb8), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x03), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x16), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_ENABLES, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SO_GAIN, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL3, 0x6c), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4c), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL4, 0xb8), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_CNTRL, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_ENABLES, 0x0c), }; static const struct qmp_phy_init_tbl ipq9574_usb3_pcs_tbl[] = { @@ -330,7 +330,7 @@ static const struct qmp_phy_init_tbl ipq8074_usb3_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN, 0x08), QMP_PHY_INIT_CFG(QSERDES_V2_COM_CLK_SELECT, 0x30), QMP_PHY_INIT_CFG(QSERDES_V2_COM_BG_TRIM, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), QMP_PHY_INIT_CFG(QSERDES_V2_COM_SVS_MODE_CLK_SEL, 0x01), QMP_PHY_INIT_CFG(QSERDES_V2_COM_HSCLK_SEL, 0x00), QMP_PHY_INIT_CFG(QSERDES_V2_COM_CMN_CONFIG, 0x06), @@ -363,15 +363,15 @@ static const struct qmp_phy_init_tbl ipq8074_usb3_serdes_tbl[] = { }; static const struct qmp_phy_init_tbl ipq8074_usb3_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN, 0x06), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4c), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0xb8), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x03), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x16), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_ENABLES, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SO_GAIN, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4c), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL4, 0xb8), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_CNTRL, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_ENABLES, 0x0), }; static const struct qmp_phy_init_tbl ipq8074_usb3_pcs_tbl[] = { @@ -438,22 +438,22 @@ static const struct qmp_phy_init_tbl msm8996_usb3_serdes_tbl[] = { }; static const struct qmp_phy_init_tbl msm8996_usb3_tx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), - QMP_PHY_INIT_CFG(QSERDES_TX_RCV_DETECT_LVL_2, 0x12), - QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_LANE_MODE, 0x06), }; static const struct qmp_phy_init_tbl msm8996_usb3_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN, 0x04), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4c), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0xbb), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), - QMP_PHY_INIT_CFG(QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x03), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x18), - QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_UCDR_SO_GAIN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4c), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL4, 0xbb), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_CNTRL, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_LVL, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL, 0x16), }; static const struct qmp_phy_init_tbl msm8996_usb3_pcs_tbl[] = { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index 19e91f44e84e..11b7e03b4fab 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -6,9 +6,8 @@ #ifndef QCOM_PHY_QMP_H_ #define QCOM_PHY_QMP_H_ -#include "phy-qcom-qmp-qserdes-txrx.h" - #include "phy-qcom-qmp-qserdes-com-v2.h" +#include "phy-qcom-qmp-qserdes-txrx-v2.h" #include "phy-qcom-qmp-qserdes-com-v3.h" #include "phy-qcom-qmp-qserdes-txrx-v3.h" From 0cc64561b03d755bba54cbd0cf05e9210ab40a13 Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Wed, 28 Jan 2026 17:18:49 +0530 Subject: [PATCH 22/87] dt-bindings: phy: qcom-edp: Add reference clock for sa8775p eDP PHY The initial sa8775p eDP PHY binding contribution missed adding support for voting on the eDP reference clock. This went unnoticed because the UFS PHY driver happened to enable the same clock. After commit 77d2fa54a945 ("scsi: ufs: qcom : Refactor phy_power_on/off calls"), the eDP reference clock is no longer kept enabled, which results in the following PHY power-on failure: phy phy-aec2a00.phy.10: phy poweron failed --> -110 To fix this, explicit voting for the eDP reference clock is required. This patch adds the eDP reference clock for sa8775p eDP PHY and updates the corresponding example node. Signed-off-by: Ritesh Kumar Reviewed-by: Bjorn Andersson Acked-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260128114853.2543416-2-quic_riteshk@quicinc.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml | 6 ++++-- Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml index e2730a2f25cf..6c827cf9692b 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml @@ -200,9 +200,11 @@ examples: <0x0aec2000 0x1c8>; clocks = <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK>, - <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>; + <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_EDP_REF_CLKREF_EN>; clock-names = "aux", - "cfg_ahb"; + "cfg_ahb", + "ref"; #clock-cells = <1>; #phy-cells = <0>; diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml index 4a1daae3d8d4..0bf8bf4f66ac 100644 --- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml @@ -74,6 +74,7 @@ allOf: compatible: enum: - qcom,glymur-dp-phy + - qcom,sa8775p-edp-phy - qcom,x1e80100-dp-phy then: properties: From a62bfbcf2db4ae6eb7a544a40b1075a81784ea41 Mon Sep 17 00:00:00 2001 From: Wesley Cheng Date: Mon, 2 Mar 2026 10:34:46 +0200 Subject: [PATCH 23/87] phy: qcom: m31-eusb2: Make USB repeater optional A repeater is not required for the PHY to function. On systems with multiple PHY instances connected to a multi-port controller, some PHYs may be unconnected. All PHYs must still probe successfully even without attached repeaters, otherwise the controller probe fails. So make it optional. Signed-off-by: Wesley Cheng [abel.vesa@oss.qualcomm.com: commit re-worded to reflect actual reason] Reviewed-by: Dmitry Baryshkov Reviewed-by: Bjorn Andersson Signed-off-by: Abel Vesa Reviewed-by: Neil Armstrong Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20260302-phy-qcom-m31-eusb2-make-repeater-optional-v2-1-dbf714c72056@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 68f1ba8fec4a..0bec8657149c 100644 --- a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c @@ -285,7 +285,7 @@ static int m31eusb2_phy_probe(struct platform_device *pdev) phy_set_drvdata(phy->phy, phy); - phy->repeater = devm_of_phy_get_by_index(dev, dev->of_node, 0); + phy->repeater = devm_phy_optional_get(dev, NULL); if (IS_ERR(phy->repeater)) return dev_err_probe(dev, PTR_ERR(phy->repeater), "failed to get repeater\n"); From 905780855a320ab3dcf0e4eaebf544cb3e7b55f8 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 21 Mar 2026 03:14:49 +0200 Subject: [PATCH 24/87] phy: lynx-28g: use timeouts when waiting for lane halt and reset There are various circumstances in which a lane halt, or a lane reset, will fail to complete. If this happens, it will hang the kernel, which only implements a busy loop with no timeout. The circumstances in which this will happen are all bugs in nature: - if we try to power off a powered off lane - if we try to power off a lane that uses a PLL locked onto the wrong refclk frequency (wrong RCW, but SoC boots anyway) Actually, unbounded loops in the kernel are a bad practice, so let's use read_poll_timeout() with a custom function that reads both LNaTRSTCTL (lane transmit control register) and LNaRRSTCTL (lane receive control register) and returns true when the request is done in both directions. The HLT_REQ bit has to clear, whereas the RST_DONE bit has to get set. Any time such an error happens, it is catastrophic and there is no point in trying to propagate it to our callers: - if lynx_28g_set_mode() -> lynx_28g_power_on() times out, we have already reconfigured the lane, but returning an error would tell the caller that we didn't - if lynx_28g_power_off() times out, again not much for the consumer to do to help get out of this situation - the phy_power_off() call is probably made from a context that the consumer can't cancel, or it is making it to return to a known state from a previous failure. So just print an error if timeouts happen and let the driver control flow continue. The entire point is just to not let the kernel freeze. Suggested-by: Josua Mayer Link: https://lore.kernel.org/lkml/d0c8bbf8-a0c5-469f-a148-de2235948c0f@solid-run.com/ Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20260321011451.1557091-2-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 72 ++++++++++++++++++------ 1 file changed, 56 insertions(+), 16 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 63427fc34e26..a9ab92e3d1a9 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -249,6 +249,12 @@ #define CR(x) ((x) * 4) +#define LYNX_28G_LANE_HALT_SLEEP_US 100 +#define LYNX_28G_LANE_HALT_TIMEOUT_US 1000000 + +#define LYNX_28G_LANE_RESET_SLEEP_US 100 +#define LYNX_28G_LANE_RESET_TIMEOUT_US 1000000 + enum lynx_28g_eq_type { EQ_TYPE_NO_EQ = 0, EQ_TYPE_2TAP = 1, @@ -600,10 +606,29 @@ static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane, } } +static bool lynx_28g_lane_halt_done(struct lynx_28g_lane *lane) +{ + u32 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL); + u32 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); + + return !(trstctl & LNaTRSTCTL_HLT_REQ) && + !(rrstctl & LNaRRSTCTL_HLT_REQ); +} + +static bool lynx_28g_lane_reset_done(struct lynx_28g_lane *lane) +{ + u32 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL); + u32 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); + + return (trstctl & LNaTRSTCTL_RST_DONE) && + (rrstctl & LNaRRSTCTL_RST_DONE); +} + static int lynx_28g_power_off(struct phy *phy) { struct lynx_28g_lane *lane = phy_get_drvdata(phy); - u32 trstctl, rrstctl; + bool done; + int err; if (!lane->powered_up) return 0; @@ -615,11 +640,14 @@ static int lynx_28g_power_off(struct phy *phy) LNaRRSTCTL_HLT_REQ); /* Wait until the halting process is complete */ - do { - trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL); - rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); - } while ((trstctl & LNaTRSTCTL_HLT_REQ) || - (rrstctl & LNaRRSTCTL_HLT_REQ)); + err = read_poll_timeout(lynx_28g_lane_halt_done, done, done, + LYNX_28G_LANE_HALT_SLEEP_US, + LYNX_28G_LANE_HALT_TIMEOUT_US, + false, lane); + if (err) { + dev_err(&phy->dev, "Lane %c halt failed: %pe\n", + 'A' + lane->id, ERR_PTR(err)); + } lane->powered_up = false; @@ -629,7 +657,8 @@ static int lynx_28g_power_off(struct phy *phy) static int lynx_28g_power_on(struct phy *phy) { struct lynx_28g_lane *lane = phy_get_drvdata(phy); - u32 trstctl, rrstctl; + bool done; + int err; if (lane->powered_up) return 0; @@ -641,11 +670,14 @@ static int lynx_28g_power_on(struct phy *phy) LNaRRSTCTL_RST_REQ); /* Wait until the reset sequence is completed */ - do { - trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL); - rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); - } while (!(trstctl & LNaTRSTCTL_RST_DONE) || - !(rrstctl & LNaRRSTCTL_RST_DONE)); + err = read_poll_timeout(lynx_28g_lane_reset_done, done, done, + LYNX_28G_LANE_RESET_SLEEP_US, + LYNX_28G_LANE_RESET_TIMEOUT_US, + false, lane); + if (err) { + dev_err(&phy->dev, "Lane %c reset failed: %pe\n", + 'A' + lane->id, ERR_PTR(err)); + } lane->powered_up = true; @@ -1065,7 +1097,7 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work) struct lynx_28g_priv *priv = work_to_lynx(work); struct lynx_28g_lane *lane; u32 rrstctl; - int i; + int err, i; for (i = 0; i < LYNX_28G_NUM_LANE; i++) { lane = &priv->lane[i]; @@ -1083,9 +1115,17 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work) if (!(rrstctl & LNaRRSTCTL_CDR_LOCK)) { lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_RST_REQ, LNaRRSTCTL_RST_REQ); - do { - rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); - } while (!(rrstctl & LNaRRSTCTL_RST_DONE)); + + err = read_poll_timeout(lynx_28g_lane_read, rrstctl, + !!(rrstctl & LNaRRSTCTL_RST_DONE), + LYNX_28G_LANE_RESET_SLEEP_US, + LYNX_28G_LANE_RESET_TIMEOUT_US, + false, lane, LNaRRSTCTL); + if (err) { + dev_warn_once(&lane->phy->dev, + "Lane %c receiver reset failed: %pe\n", + 'A' + lane->id, ERR_PTR(err)); + } } mutex_unlock(&lane->phy->mutex); From 5d38f693f16a0e9470fda530e01994f35fed8644 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 21 Mar 2026 03:14:50 +0200 Subject: [PATCH 25/87] phy: lynx-28g: truly power the lanes up or down The current procedure for power_off() and power_on() is the same as the one used for major lane reconfiguration, aka halting. But this is incorrect. One would expect that a powered off lane causes the CDR (clock and data recovery) loop of the link partner to lose lock onto its RX stream (which suggests there are no longer any bit transitions => the channel is inactive). However, it can be observed that this does not take place (the CDR lock is still there), which means that a halted lane is not powered off. Implement the procedure mentioned in the block guide for powering down a lane, and then back on. This means: - lynx_28g_power_off() currently emits a HLT_REQ and waits for it to clear. Rename it to lynx_28g_lane_halt() and keep using it for lynx_28g_set_mode(). - lynx_28g_power_on() currently emits a RST_REQ and waits for it to clear. This is the reset procedure - rename it to lynx_28g_lane_reset(), and keep using it for lynx_28g_set_mode(). The "real" lynx_28g_power_off() should emit a STP_REQ and wait for it to clear. And the "real" lynx_28g_power_on() should clear the DIS bit and then perform a lane reset. Hook these methods to the phy_ops :: power_off() and power_on() instead. As opposed to lynx_28g_power_off() which is also directly hooked to the PHY API, lynx_28g_lane_halt() isn't; just to lynx_28g_set_mode(), and the call is being made in a state where we haven't yet made any change to the lane. So it does make some limited amount of sense to code this up such that if it fails, we make an attempt to reset the lane anyway and let the consumer know that phy_set_mode_ext() failed. Sort the field definitions in LNaTRSTCTL and LNaRRSTCTL in descending order, and add new definitions for STP_REQ and DIS, previously unused. Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260321011451.1557091-3-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 103 +++++++++++++++++++---- 1 file changed, 85 insertions(+), 18 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index a9ab92e3d1a9..1e2302799f8f 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -70,9 +70,11 @@ /* Lane a Tx Reset Control Register */ #define LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20) -#define LNaTRSTCTL_HLT_REQ BIT(27) -#define LNaTRSTCTL_RST_DONE BIT(30) #define LNaTRSTCTL_RST_REQ BIT(31) +#define LNaTRSTCTL_RST_DONE BIT(30) +#define LNaTRSTCTL_HLT_REQ BIT(27) +#define LNaTRSTCTL_STP_REQ BIT(26) +#define LNaTRSTCTL_DIS BIT(24) /* Lane a Tx General Control Register */ #define LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24) @@ -98,9 +100,11 @@ /* Lane a Rx Reset Control Register */ #define LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40) -#define LNaRRSTCTL_HLT_REQ BIT(27) -#define LNaRRSTCTL_RST_DONE BIT(30) #define LNaRRSTCTL_RST_REQ BIT(31) +#define LNaRRSTCTL_RST_DONE BIT(30) +#define LNaRRSTCTL_HLT_REQ BIT(27) +#define LNaRRSTCTL_STP_REQ BIT(26) +#define LNaRRSTCTL_DIS BIT(24) #define LNaRRSTCTL_CDR_LOCK BIT(12) /* Lane a Rx General Control Register */ @@ -255,6 +259,9 @@ #define LYNX_28G_LANE_RESET_SLEEP_US 100 #define LYNX_28G_LANE_RESET_TIMEOUT_US 1000000 +#define LYNX_28G_LANE_STOP_SLEEP_US 100 +#define LYNX_28G_LANE_STOP_TIMEOUT_US 1000000 + enum lynx_28g_eq_type { EQ_TYPE_NO_EQ = 0, EQ_TYPE_2TAP = 1, @@ -615,6 +622,15 @@ static bool lynx_28g_lane_halt_done(struct lynx_28g_lane *lane) !(rrstctl & LNaRRSTCTL_HLT_REQ); } +static bool lynx_28g_lane_stop_done(struct lynx_28g_lane *lane) +{ + u32 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL); + u32 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); + + return !(trstctl & LNaTRSTCTL_STP_REQ) && + !(rrstctl & LNaRRSTCTL_STP_REQ); +} + static bool lynx_28g_lane_reset_done(struct lynx_28g_lane *lane) { u32 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL); @@ -624,15 +640,13 @@ static bool lynx_28g_lane_reset_done(struct lynx_28g_lane *lane) (rrstctl & LNaRRSTCTL_RST_DONE); } -static int lynx_28g_power_off(struct phy *phy) +/* Halting puts the lane in a mode in which it can be reconfigured */ +static int lynx_28g_lane_halt(struct phy *phy) { struct lynx_28g_lane *lane = phy_get_drvdata(phy); bool done; int err; - if (!lane->powered_up) - return 0; - /* Issue a halt request */ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_HLT_REQ, LNaTRSTCTL_HLT_REQ); @@ -649,20 +663,15 @@ static int lynx_28g_power_off(struct phy *phy) 'A' + lane->id, ERR_PTR(err)); } - lane->powered_up = false; - - return 0; + return err; } -static int lynx_28g_power_on(struct phy *phy) +static int lynx_28g_lane_reset(struct phy *phy) { struct lynx_28g_lane *lane = phy_get_drvdata(phy); bool done; int err; - if (lane->powered_up) - return 0; - /* Issue a reset request on the lane */ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_RST_REQ, LNaTRSTCTL_RST_REQ); @@ -679,6 +688,61 @@ static int lynx_28g_power_on(struct phy *phy) 'A' + lane->id, ERR_PTR(err)); } + return err; +} + +static int lynx_28g_power_off(struct phy *phy) +{ + struct lynx_28g_lane *lane = phy_get_drvdata(phy); + bool done; + int err; + + if (!lane->powered_up) + return 0; + + /* Issue a stop request */ + lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_STP_REQ, + LNaTRSTCTL_STP_REQ); + lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_STP_REQ, + LNaRRSTCTL_STP_REQ); + + /* Wait until the stop process is complete */ + err = read_poll_timeout(lynx_28g_lane_stop_done, done, done, + LYNX_28G_LANE_STOP_SLEEP_US, + LYNX_28G_LANE_STOP_TIMEOUT_US, + false, lane); + if (err) { + dev_err(&phy->dev, "Lane %c stop failed: %pe\n", + 'A' + lane->id, ERR_PTR(err)); + } + + /* Power down the RX and TX portions of the lane */ + lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_DIS, + LNaRRSTCTL_DIS); + lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_DIS, + LNaTRSTCTL_DIS); + + lane->powered_up = false; + + return 0; +} + +static int lynx_28g_power_on(struct phy *phy) +{ + struct lynx_28g_lane *lane = phy_get_drvdata(phy); + int err; + + if (lane->powered_up) + return 0; + + /* Power up the RX and TX portions of the lane */ + lynx_28g_lane_rmw(lane, LNaRRSTCTL, 0, LNaRRSTCTL_DIS); + lynx_28g_lane_rmw(lane, LNaTRSTCTL, 0, LNaTRSTCTL_DIS); + + err = lynx_28g_lane_reset(phy); + if (err) + return err; + lane->powered_up = true; return 0; @@ -992,8 +1056,11 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode) /* If the lane is powered up, put the lane into the halt state while * the reconfiguration is being done. */ - if (powered_up) - lynx_28g_power_off(phy); + if (powered_up) { + err = lynx_28g_lane_halt(phy); + if (err) + goto out; + } err = lynx_28g_lane_disable_pcvt(lane, lane->mode); if (err) @@ -1007,7 +1074,7 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode) out: if (powered_up) - lynx_28g_power_on(phy); + lynx_28g_lane_reset(phy); return err; } From 0ee5cc59c0ee679e1a3a749cfc47834041763494 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 21 Mar 2026 03:14:51 +0200 Subject: [PATCH 26/87] phy: lynx-28g: implement phy_exit() operation On Layerscape, some Lynx SerDes consumers go through the PHY framework (we call these 'managed' for the sake of this discussion; they are some Ethernet lanes), and some consumers don't go through the PHY framework (we call these 'unmanaged'; they are some unconverted Ethernet lanes, plus all SATA and PCIe controllers). A lane is initially unmanaged, and becomes managed when phy_init() is called on it. Similarly, it becomes unmanaged again when phy_exit() is called. Managed lanes are supposed to have power management through phy_power_on() and phy_power_off(). The lynx-28g SerDes driver, when it probes, probes on all lanes, but needs to be careful to keep the unmanaged lanes powered on, because those might be in use by consumers unaware that they need to call phy_init() and phy_power_on(). This also applies after phy_exit() is called - no guarantee is made about how the port may be used afterwards - may be DPDK, may be something else which is unaware of the PHY framework. Given this state table: State | Consumer calls phy_exit()? | Provider implements phy_exit()? -------+----------------------------+-------------------------------- (a) | no | no (b) | no | yes (c) | yes | no (d) | yes | yes we are currently in state (a). This has the problem that when the consumer fails to probe with -EPROBE_DEFER or is otherwise unbound, the phy->init_count remains elevated and the lane never returns to the unmanaged state (temporarily or not) as it should. Furthermore, the second and subsequent phy_init() consumer calls are never passed on to the provider driver. We solve the above problem by implementing phy_exit() in the consumer, and that moves us to state (c). But this creates the problem that a balanced set of phy_init() and phy_exit() calls from the consumer will effectively result in multiple lynx_28g_init() calls as seen by the SerDes and nothing else - as the optional phy_ops :: exit() is not implemented. But that actually doesn't work - the 28G Lynx SerDes can't power down a lane which is already powered down; that call sequence would time out and fail. So actually we want to be in state (d), where both the provider and the consumer implement phy_exit(). But we can only do that safely through intermediary state (b), where the provider implements it first. This effectively behaves just like (a), except it offers a safe migration path for the consumer to call phy_exit() as mandated by the Generic PHY API. Extra development notes: ignoring the lynx_28g_power_on() error in lynx_28g_exit() is a deliberate decision. The consumer can't deal with a teardown path that is not error-free. Ignoring the error is not silent: lynx_28g_power_on() -> lynx_28g_lane_reset() will print on failure. Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260321011451.1557091-4-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 1e2302799f8f..4ec3fb7a0d69 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -1113,8 +1113,25 @@ static int lynx_28g_init(struct phy *phy) return 0; } +static int lynx_28g_exit(struct phy *phy) +{ + struct lynx_28g_lane *lane = phy_get_drvdata(phy); + + /* The lane returns to the state where it isn't managed by the + * consumer, so we must treat is as if it isn't initialized, and + * always powered on. + */ + lane->init = false; + lane->powered_up = false; + + lynx_28g_power_on(phy); + + return 0; +} + static const struct phy_ops lynx_28g_ops = { .init = lynx_28g_init, + .exit = lynx_28g_exit, .power_on = lynx_28g_power_on, .power_off = lynx_28g_power_off, .set_mode = lynx_28g_set_mode, From 53f60930e3d20883364fc01fd46b6099acb8127a Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 19 Mar 2026 06:32:07 +0000 Subject: [PATCH 27/87] phy: renesas: phy-rzg3e-usb3: Fix malformed MODULE_AUTHOR string Fix a malformed MODULE_AUTHOR macro in the RZ/G3E USB3.0 PHY driver where the author's name and opening angle bracket were missing, leaving only the email address with a stray closing >. Correct it to the standard Name format. Reported-by: Pavel Machek Closes: https://lore.kernel.org/all/abp4KprlYyU+jMPu@duo.ucw.cz/ Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Link: https://patch.msgid.link/20260319063211.5056-1-biju.das.jz@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rzg3e-usb3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/renesas/phy-rzg3e-usb3.c b/drivers/phy/renesas/phy-rzg3e-usb3.c index 6b3453ea0004..030c600a53e6 100644 --- a/drivers/phy/renesas/phy-rzg3e-usb3.c +++ b/drivers/phy/renesas/phy-rzg3e-usb3.c @@ -256,4 +256,4 @@ module_platform_driver(rzg3e_phy_usb3_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Renesas RZ/G3E USB3.0 PHY Driver"); -MODULE_AUTHOR("biju.das.jz@bp.renesas.com>"); +MODULE_AUTHOR("Biju Das "); From b6e33443876d0ca7e93cf949455e3c1a1a0aae24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Mon, 9 Mar 2026 15:37:34 +0100 Subject: [PATCH 28/87] phy: Add driver for EyeQ5 Ethernet PHY wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EyeQ5 embeds a system-controller called OLB. It features many unrelated registers, and some of those are registers used to configure the integration of the RGMII/SGMII Cadence PHY used by MACB/GEM instances. Wrap in a neat generic PHY provider, exposing two PHYs with standard phy_init() / phy_set_mode() / phy_power_on() operations. Reviewed-by: Luca Ceresoli Signed-off-by: Théo Lebrun Reviewed-by: Vladimir Oltean Link: https://patch.msgid.link/20260309-macb-phy-v9-1-5afd87d9db43@bootlin.com Signed-off-by: Vinod Koul --- MAINTAINERS | 1 + drivers/phy/Kconfig | 13 ++ drivers/phy/Makefile | 1 + drivers/phy/phy-eyeq5-eth.c | 280 ++++++++++++++++++++++++++++++++++++ 4 files changed, 295 insertions(+) create mode 100644 drivers/phy/phy-eyeq5-eth.c diff --git a/MAINTAINERS b/MAINTAINERS index cf179372c7f0..421dd786b399 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17958,6 +17958,7 @@ F: arch/mips/boot/dts/mobileye/ F: arch/mips/configs/eyeq*_defconfig F: arch/mips/mobileye/board-epm5.its.S F: drivers/clk/clk-eyeq.c +F: drivers/phy/phy-eyeq5-eth.c F: drivers/pinctrl/pinctrl-eyeq5.c F: drivers/reset/reset-eyeq.c F: include/dt-bindings/clock/mobileye,eyeq5-clk.h diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 872a7f02e1c4..ab96ee5858c1 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -66,6 +66,19 @@ config PHY_CAN_TRANSCEIVER functional modes using gpios and sets the attribute max link rate, for CAN drivers. +config PHY_EYEQ5_ETH + tristate "Ethernet PHY Driver on EyeQ5" + depends on OF + depends on MACH_EYEQ5 || COMPILE_TEST + select AUXILIARY_BUS + select GENERIC_PHY + default MACH_EYEQ5 + help + Enable this to support the Ethernet PHY integrated on EyeQ5. + It supports both RGMII and SGMII. Registers are located in a + shared register region called OLB. If M is selected, the + module will be called phy-eyeq5-eth. + config PHY_GOOGLE_USB tristate "Google Tensor SoC USB PHY driver" select GENERIC_PHY diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index ae756fea473b..f31767745123 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o +obj-$(CONFIG_PHY_EYEQ5_ETH) += phy-eyeq5-eth.o obj-$(CONFIG_PHY_GOOGLE_USB) += phy-google-usb.o obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o diff --git a/drivers/phy/phy-eyeq5-eth.c b/drivers/phy/phy-eyeq5-eth.c new file mode 100644 index 000000000000..c03d77c360f7 --- /dev/null +++ b/drivers/phy/phy-eyeq5-eth.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EQ5_PHY_COUNT 2 + +#define EQ5_PHY0_GP 0x128 +#define EQ5_PHY1_GP 0x12c +#define EQ5_PHY0_SGMII 0x134 +#define EQ5_PHY1_SGMII 0x138 + +#define EQ5_GP_TX_SWRST_DIS BIT(0) // Tx SW reset +#define EQ5_GP_TX_M_CLKE BIT(1) // Tx M clock enable +#define EQ5_GP_SYS_SWRST_DIS BIT(2) // Sys SW reset +#define EQ5_GP_SYS_M_CLKE BIT(3) // Sys clock enable +#define EQ5_GP_SGMII_MODE BIT(4) // SGMII mode +#define EQ5_GP_RGMII_DRV GENMASK(8, 5) // RGMII drive strength + +#define EQ5_SGMII_PWR_EN BIT(0) +#define EQ5_SGMII_RST_DIS BIT(1) +#define EQ5_SGMII_PLL_EN BIT(2) +#define EQ5_SGMII_SIG_DET_SW BIT(3) +#define EQ5_SGMII_PWR_STATE BIT(4) +#define EQ5_SGMII_PLL_ACK BIT(18) +#define EQ5_SGMII_PWR_STATE_ACK GENMASK(24, 20) + +/* + * Instead of storing a phy_interface_t, we store this enum. + * + * We do not deal with RGMII timings in this generic PHY driver, + * it is all handled inside the net PHY. + */ +enum eq5_phy_submode { + EQ5_PHY_SUBMODE_SGMII, + EQ5_PHY_SUBMODE_RGMII, +}; + +struct eq5_phy_inst { + struct device *dev; + struct phy *phy; + void __iomem *gp, *sgmii; + enum eq5_phy_submode submode; + bool sgmii_support; +}; + +struct eq5_phy_private { + struct eq5_phy_inst phys[EQ5_PHY_COUNT]; +}; + +static int eq5_phy_exit(struct phy *phy) +{ + struct eq5_phy_inst *inst = phy_get_drvdata(phy); + + writel(0, inst->gp); + writel(0, inst->sgmii); + udelay(5); /* settling time */ + return 0; +} + +static int eq5_phy_init(struct phy *phy) +{ + struct eq5_phy_inst *inst = phy_get_drvdata(phy); + u32 reg; + + /* + * Hardware stops listening to our instructions once it is started. + * It must be reset to reconfigure it. + */ + eq5_phy_exit(phy); + + reg = EQ5_GP_TX_SWRST_DIS | EQ5_GP_TX_M_CLKE | + EQ5_GP_SYS_SWRST_DIS | EQ5_GP_SYS_M_CLKE | + FIELD_PREP(EQ5_GP_RGMII_DRV, 0x9); + writel(reg, inst->gp); + + return 0; +} + +static int eq5_phy_power_on(struct phy *phy) +{ + struct eq5_phy_inst *inst = phy_get_drvdata(phy); + u32 reg; + + if (inst->submode == EQ5_PHY_SUBMODE_SGMII) { + writel(readl(inst->gp) | EQ5_GP_SGMII_MODE, inst->gp); + + reg = EQ5_SGMII_PWR_EN | EQ5_SGMII_RST_DIS | EQ5_SGMII_PLL_EN; + writel(reg, inst->sgmii); + + if (readl_poll_timeout(inst->sgmii, reg, + reg & EQ5_SGMII_PLL_ACK, 1, 100)) { + dev_err(inst->dev, "PLL timeout\n"); + return -ETIMEDOUT; + } + + reg = readl(inst->sgmii); + reg |= EQ5_SGMII_PWR_STATE | EQ5_SGMII_SIG_DET_SW; + writel(reg, inst->sgmii); + } else { + writel(readl(inst->gp) & ~EQ5_GP_SGMII_MODE, inst->gp); + writel(0, inst->sgmii); + } + + return 0; +} + +static int eq5_phy_power_off(struct phy *phy) +{ + struct eq5_phy_inst *inst = phy_get_drvdata(phy); + + writel(readl(inst->gp) & ~EQ5_GP_SGMII_MODE, inst->gp); + writel(0, inst->sgmii); + + return 0; +} + +static int eq5_phy_validate(struct phy *phy, enum phy_mode mode, int submode, + union phy_configure_opts *opts) +{ + struct eq5_phy_inst *inst = phy_get_drvdata(phy); + + if (mode != PHY_MODE_ETHERNET) + return -EINVAL; + + if (phy_interface_mode_is_rgmii(submode)) + return 0; + + if (inst->sgmii_support && submode == PHY_INTERFACE_MODE_SGMII) + return 0; + + return -EINVAL; +} + +static int eq5_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct eq5_phy_inst *inst = phy_get_drvdata(phy); + enum eq5_phy_submode target_submode; + int ret; + + ret = eq5_phy_validate(phy, mode, submode, NULL); + if (ret) + return ret; + + if (submode == PHY_INTERFACE_MODE_SGMII) + target_submode = EQ5_PHY_SUBMODE_SGMII; + else + target_submode = EQ5_PHY_SUBMODE_RGMII; + + if (target_submode == inst->submode) + return 0; + + inst->submode = target_submode; + + if (phy->power_count) { + eq5_phy_init(phy); + return eq5_phy_power_on(phy); + } + + return 0; +} + +static const struct phy_ops eq5_phy_ops = { + .init = eq5_phy_init, + .exit = eq5_phy_exit, + .power_on = eq5_phy_power_on, + .power_off = eq5_phy_power_off, + .set_mode = eq5_phy_set_mode, + .validate = eq5_phy_validate, +}; + +static struct phy *eq5_phy_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct eq5_phy_private *priv = dev_get_drvdata(dev); + + if (args->args_count != 1 || args->args[0] >= EQ5_PHY_COUNT) + return ERR_PTR(-EINVAL); + + return priv->phys[args->args[0]].phy; +} + +static int eq5_phy_probe_phy(struct device *dev, struct eq5_phy_private *priv, + unsigned int index, void __iomem *base, + unsigned int gp, unsigned int sgmii, + bool sgmii_support) +{ + struct eq5_phy_inst *inst = &priv->phys[index]; + struct phy *phy; + + phy = devm_phy_create(dev, dev->of_node, &eq5_phy_ops); + if (IS_ERR(phy)) + return dev_err_probe(dev, PTR_ERR(phy), + "failed to create PHY %u\n", index); + + inst->dev = dev; + inst->phy = phy; + inst->gp = base + gp; + inst->sgmii = base + sgmii; + inst->sgmii_support = sgmii_support; + phy_set_drvdata(phy, inst); + + /* + * Init inst->submode based on probe hardware state, allowing + * consumers to power us on without first setting the mode. + */ + if (sgmii_support && (readl(inst->gp) & EQ5_GP_SGMII_MODE)) + inst->submode = EQ5_PHY_SUBMODE_SGMII; + else + inst->submode = EQ5_PHY_SUBMODE_RGMII; + + return 0; +} + +static int eq5_phy_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct device *dev = &adev->dev; + struct phy_provider *provider; + struct eq5_phy_private *priv; + void __iomem *base; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + + base = (void __iomem *)dev_get_platdata(dev); + + ret = eq5_phy_probe_phy(dev, priv, 0, base, EQ5_PHY0_GP, + EQ5_PHY0_SGMII, true); + if (ret) + return ret; + + ret = eq5_phy_probe_phy(dev, priv, 1, base, EQ5_PHY1_GP, + EQ5_PHY1_SGMII, false); + if (ret) + return ret; + + provider = devm_of_phy_provider_register(dev, eq5_phy_xlate); + if (IS_ERR(provider)) + return dev_err_probe(dev, PTR_ERR(provider), + "registering provider failed\n"); + + return 0; +} + +static const struct auxiliary_device_id eq5_phy_id_table[] = { + { .name = "clk_eyeq.phy" }, + {} +}; +MODULE_DEVICE_TABLE(auxiliary, eq5_phy_id_table); + +static struct auxiliary_driver eq5_phy_driver = { + .probe = eq5_phy_probe, + .id_table = eq5_phy_id_table, +}; +module_auxiliary_driver(eq5_phy_driver); + +MODULE_DESCRIPTION("EyeQ5 Ethernet PHY driver"); +MODULE_AUTHOR("Théo Lebrun "); +MODULE_LICENSE("GPL"); From cc68a1728abfcbde12d36015f244046ae74ddd44 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Fri, 6 Mar 2026 14:24:56 -0800 Subject: [PATCH 29/87] phy: miphy28lp: add COMPILE_TEST There's nothing special here to prevent compilation on non ARM hosts. Matches every other st phy driver. Signed-off-by: Rosen Penev Reviewed-by: Patrice Chotard Link: https://patch.msgid.link/20260306222457.8400-2-rosenp@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/st/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/st/Kconfig b/drivers/phy/st/Kconfig index 304614b6dabf..49206185e563 100644 --- a/drivers/phy/st/Kconfig +++ b/drivers/phy/st/Kconfig @@ -4,7 +4,7 @@ # config PHY_MIPHY28LP tristate "STMicroelectronics MIPHY28LP PHY driver for STiH407" - depends on ARCH_STI + depends on ARCH_STI || COMPILE_TEST select GENERIC_PHY help Enable this to support the miphy transceiver (for SATA/PCIE/USB3) From f3508a61c892c592e4e893a3681e568a5c671027 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Fri, 6 Mar 2026 14:24:57 -0800 Subject: [PATCH 30/87] phy: miphy28lp: kzalloc + kcalloc to single kzalloc Use flex array to simplify allocation. Allows using __counted_by for extra runtime analysis. Signed-off-by: Rosen Penev Reviewed-by: Patrice Chotard Link: https://patch.msgid.link/20260306222457.8400-3-rosenp@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/st/phy-miphy28lp.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/phy/st/phy-miphy28lp.c b/drivers/phy/st/phy-miphy28lp.c index 43cef89af55e..c576fc5569fe 100644 --- a/drivers/phy/st/phy-miphy28lp.c +++ b/drivers/phy/st/phy-miphy28lp.c @@ -224,8 +224,8 @@ struct miphy28lp_dev { struct device *dev; struct regmap *regmap; struct mutex miphy_mutex; - struct miphy28lp_phy **phys; int nphys; + struct miphy28lp_phy *phys[] __counted_by(nphys); }; enum miphy_sata_gen { SATA_GEN1, SATA_GEN2, SATA_GEN3 }; @@ -1168,16 +1168,14 @@ static int miphy28lp_probe(struct platform_device *pdev) struct phy_provider *provider; struct phy *phy; int ret, port = 0; + size_t nphys; - miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL); + nphys = of_get_child_count(np); + miphy_dev = devm_kzalloc(&pdev->dev, struct_size(miphy_dev, phys, nphys), GFP_KERNEL); if (!miphy_dev) return -ENOMEM; - miphy_dev->nphys = of_get_child_count(np); - miphy_dev->phys = devm_kcalloc(&pdev->dev, miphy_dev->nphys, - sizeof(*miphy_dev->phys), GFP_KERNEL); - if (!miphy_dev->phys) - return -ENOMEM; + miphy_dev->nphys = nphys; miphy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); if (IS_ERR(miphy_dev->regmap)) { From 057c81a17fffb17f66e5b4524d49b7caad3fe627 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 11 Feb 2026 15:49:48 +0100 Subject: [PATCH 31/87] phy: freescale: imx8qm-hsio: provide regmap names This driver uses multiple regmaps, which will causes name conflicts in debugfs like: debugfs: '5f1a0000.phy' already exists in 'regmap' Fix this by using a dedicated regmap config for each resource, each having a dedicated regmap name. Signed-off-by: Alexander Stein Reviewed-by: Neil Armstrong Reviewed-by: Frank Li Link: https://patch.msgid.link/20260211144949.1128122-1-alexander.stein@ew.tq-group.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-imx8qm-hsio.c | 23 +++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c index 279b8ac7822d..4ab45c9f53df 100644 --- a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c +++ b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c @@ -107,7 +107,22 @@ static const char * const lan2_pcieb_clks[] = {"apb_pclk2", "pclk2", "ctl1_crr", static const char * const lan2_sata_clks[] = {"pclk2", "epcs_tx", "epcs_rx", "phy1_crr", "misc_crr"}; -static const struct regmap_config regmap_config = { +static const struct regmap_config regmap_phy_config = { + .name = "phy", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static const struct regmap_config regmap_ctrl_config = { + .name = "ctrl", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static const struct regmap_config regmap_misc_config = { + .name = "misc", .reg_bits = 32, .val_bits = 32, .reg_stride = 4, @@ -562,19 +577,19 @@ static int imx_hsio_probe(struct platform_device *pdev) return PTR_ERR(priv->base); off = devm_platform_ioremap_resource_byname(pdev, "phy"); - priv->phy = devm_regmap_init_mmio(dev, off, ®map_config); + priv->phy = devm_regmap_init_mmio(dev, off, ®map_phy_config); if (IS_ERR(priv->phy)) return dev_err_probe(dev, PTR_ERR(priv->phy), "unable to find phy csr registers\n"); off = devm_platform_ioremap_resource_byname(pdev, "ctrl"); - priv->ctrl = devm_regmap_init_mmio(dev, off, ®map_config); + priv->ctrl = devm_regmap_init_mmio(dev, off, ®map_ctrl_config); if (IS_ERR(priv->ctrl)) return dev_err_probe(dev, PTR_ERR(priv->ctrl), "unable to find ctrl csr registers\n"); off = devm_platform_ioremap_resource_byname(pdev, "misc"); - priv->misc = devm_regmap_init_mmio(dev, off, ®map_config); + priv->misc = devm_regmap_init_mmio(dev, off, ®map_misc_config); if (IS_ERR(priv->misc)) return dev_err_probe(dev, PTR_ERR(priv->misc), "unable to find misc csr registers\n"); From 9cfeef97f21be61372d718f7ee430ea65536bb08 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 5 Mar 2026 11:15:28 +0100 Subject: [PATCH 32/87] phy: renesas: rzg3e-usb3: Convert to FIELD_MODIFY() Use the FIELD_MODIFY() helper instead of open-coding the same operation. Signed-off-by: Geert Uytterhoeven Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/a52020ba597e2e213b161eee21239f10e6057d9d.1772705690.git.geert+renesas@glider.be Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rzg3e-usb3.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/phy/renesas/phy-rzg3e-usb3.c b/drivers/phy/renesas/phy-rzg3e-usb3.c index 030c600a53e6..060309547ea5 100644 --- a/drivers/phy/renesas/phy-rzg3e-usb3.c +++ b/drivers/phy/renesas/phy-rzg3e-usb3.c @@ -78,13 +78,11 @@ static void rzg3e_phy_usb2test_phy_init(void __iomem *base) writel(val, base + USB3_TEST_UTMICTRL2); val = readl(base + USB3_TEST_PRMCTRL5_R); - val &= ~USB3_TEST_PRMCTRL5_R_TXPREEMPAMPTUNE0_MASK; - val |= FIELD_PREP(USB3_TEST_PRMCTRL5_R_TXPREEMPAMPTUNE0_MASK, 2); + FIELD_MODIFY(USB3_TEST_PRMCTRL5_R_TXPREEMPAMPTUNE0_MASK, &val, 2); writel(val, base + USB3_TEST_PRMCTRL5_R); val = readl(base + USB3_TEST_PRMCTRL6_R); - val &= ~USB3_TEST_PRMCTRL6_R_OTGTUNE0_MASK; - val |= FIELD_PREP(USB3_TEST_PRMCTRL6_R_OTGTUNE0_MASK, 7); + FIELD_MODIFY(USB3_TEST_PRMCTRL6_R_OTGTUNE0_MASK, &val, 7); writel(val, base + USB3_TEST_PRMCTRL6_R); val = readl(base + USB3_TEST_RESET); From 1561f12db08b1da1fe47ce9a5beff11adfd90ac8 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 11 May 2026 18:00:19 +0300 Subject: [PATCH 33/87] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation The 28G Lynx SerDes is instantiated 3 times in the NXP LX2160A SoC and twice in the NXP LX2162A. All these instances share the same register map, but the number of lanes and the protocols supported by each lane differs in a way that isn't detectable by the programming model. For example, not all lanes of all SerDes block instantiations support 25GbE. So, using a generic "fsl,lynx-28g" compatible string and expecting all SerDes instantiations to use it was a mistake that needs to be fixed. The option chosen is to encode the SoC and the SerDes instance in the compatible string, with everything else being the responsibility of the driver to derive. An alternative considered but dismissed was to add sufficient device tree properties to describe the per-lane differences (implying: supported protocols), as well as the different lane count. Any decision made for the 28G Lynx should be consistent with the decisions taken for the yet-to-be-introduced 10G Lynx SerDes (older generation for older SoCs), because of how similar they are. I've seen the alternative at play in this unmerged patch set for the 10G Lynx here, and I didn't like it: https://lore.kernel.org/linux-phy/20230413160607.4128315-3-sean.anderson@seco.com/ This is because there, we have a higher degree of variability in the PCCR register values that need to be written per protocol. This makes that approach more drawn-out and more prone to errors, compared to the compatible strings which are more succinct and obviously correct. NXP SoC reference manuals clearly document the SerDes instantiations as not identical, and refers to them as such (SerDes 1, 2, etc). The per-SoC compatible string is prepended to the "fsl,lynx-28g" generic compatible, which is left there for compatibility with old kernels. An exception would be LX2160A SerDes #3, which at the time of writing is not described in fsl-lx2160a.dtsi. As "fsl,lx2160a-serdes3" implies it is a 28G Lynx SerDes, it makes "fsl,lynx-28g" redundant so we don't accept it. Signed-off-by: Vladimir Oltean Reviewed-by: Rob Herring (Arm) Tested-by: Josua Mayer Link: https://patch.msgid.link/20260511150023.1903577-2-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/fsl,lynx-28g.yaml | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml index e96229c2f8fb..8375bca810cc 100644 --- a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml +++ b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml @@ -9,10 +9,37 @@ title: Freescale Lynx 28G SerDes PHY maintainers: - Ioana Ciornei +description: + The Lynx 28G is a multi-lane, multi-protocol SerDes (PCIe, SATA, Ethernet) + present in multiple instances on NXP LX2160A and LX2162A SoCs. All instances + share a common register map and programming model, however they differ in + supported protocols per lane in a way that is not detectable by said + programming model without prior knowledge. The distinction is made through + the compatible string. + properties: compatible: - enum: - - fsl,lynx-28g + oneOf: + - const: fsl,lynx-28g + deprecated: true + description: + Legacy compatibility string for Lynx 28G SerDes. Any assumption + regarding whether a certain lane supports a certain protocol may + be incorrect. Deprecated except when used as a fallback. Use + device-specific strings instead. + - items: + - const: fsl,lx2160a-serdes1 + - const: fsl,lynx-28g + - items: + - const: fsl,lx2160a-serdes2 + - const: fsl,lynx-28g + - items: + - const: fsl,lx2162a-serdes1 + - const: fsl,lynx-28g + - items: + - const: fsl,lx2162a-serdes2 + - const: fsl,lynx-28g + - const: fsl,lx2160a-serdes3 reg: maxItems: 1 @@ -60,7 +87,7 @@ examples: #size-cells = <2>; serdes@1ea0000 { - compatible = "fsl,lynx-28g"; + compatible = "fsl,lx2160a-serdes1", "fsl,lynx-28g"; reg = <0x0 0x1ea0000 0x0 0x1e30>; #address-cells = <1>; #size-cells = <0>; From 37056ea140242681ccf706f63ad8c7366d89f5e3 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 11 May 2026 18:00:20 +0300 Subject: [PATCH 34/87] dt-bindings: phy: lynx-28g: add constraint on LX2162A lane indices The SerDes 1 of LX2162A has fewer lanes than all other instances, and strangely, their indices are not 0-3, but 4-7. This is a best-effort constraint, since we can only impose it when using per-SoC compatible string and per-lane OF nodes. Signed-off-by: Vladimir Oltean Acked-by: Conor Dooley Tested-by: Josua Mayer Link: https://patch.msgid.link/20260511150023.1903577-3-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/fsl,lynx-28g.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml index 8375bca810cc..d73591315d4b 100644 --- a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml +++ b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml @@ -78,6 +78,21 @@ required: - reg - "#phy-cells" +allOf: + # LX2162A SerDes 1 has fewer lanes than the others + - if: + properties: + compatible: + contains: + const: fsl,lx2162a-serdes1 + then: + patternProperties: + "^phy@[0-7]$": + properties: + reg: + minimum: 4 + maximum: 7 + additionalProperties: false examples: From c9d80e861034e2f3618065dc02b1de828aed24f6 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 11 May 2026 18:00:21 +0300 Subject: [PATCH 35/87] phy: lynx-28g: require an OF node to probe The driver will gain support for variants in an upcoming change, and will use of_device_get_match_data() to deduce the running variant from the compatible string. Currently, the driver expects the schema at phy/fsl,lynx-28g.yaml, and OF-based consumers, but doesn't enforce this. And it is possible for user space to force-bind the driver to a device without OF node using the driver_override sysfs. To avoid future surprise crashes for an unsupported configuration, explicitly test for the presence of an OF node and fail probing if found. Signed-off-by: Vladimir Oltean Reviewed-by: Ioana Ciornei Tested-by: Josua Mayer Link: https://patch.msgid.link/20260511150023.1903577-4-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 4ec3fb7a0d69..6d0c395d20e5 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -1286,6 +1286,12 @@ static int lynx_28g_probe(struct platform_device *pdev) struct device_node *dn; int err; + dn = dev_of_node(dev); + if (!dn) { + dev_err(dev, "Device requires an OF node\n"); + return -EINVAL; + } + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -1301,7 +1307,6 @@ static int lynx_28g_probe(struct platform_device *pdev) lynx_28g_pll_read_configuration(priv); - dn = dev_of_node(dev); if (of_get_child_count(dn)) { struct device_node *child; From 8c57247f5d9734d617862d320bd3894eec898298 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 11 May 2026 18:00:22 +0300 Subject: [PATCH 36/87] phy: lynx-28g: probe on per-SoC and per-instance compatible strings Add driver support for probing on the new, per-instance and per-SoC bindings, which provide the main benefit that they allow rejecting unsupported protocols per lane (10GbE on SerDes 2 lanes 0-5), but they also allow avoiding the creation of PHYs for lanes that don't exist (LX2162A lanes 0-3). For old device trees with just "fsl,lynx-28g", the only things that change are: - a probe time warning/encouragement to update the device tree. This is warranted by the fact that using "fsl,lynx-28g" may already provide incorrect behaviour (undetected absent 10GbE support on LX2160A SerDes 2 lanes 0-5). But we retain bug compatibility nonetheless. - the feature set is frozen in time (e.g. no 25GbE). Since we cannot guarantee that this protocol will work on a lane, just err on the safe side and don't offer it (and require a device tree update to get it). In terms of code, the lynx_28g_supports_lane_mode() function prototype changes. It was a SerDes-global function and now becomes per lane, to reflect the specific capabilities each instance may have. The implementation goes through priv->info->lane_supports_mode(). Signed-off-by: Vladimir Oltean Reviewed-by: Ioana Ciornei Tested-by: Josua Mayer Link: https://patch.msgid.link/20260511150023.1903577-5-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 126 +++++++++++++++++++++-- 1 file changed, 116 insertions(+), 10 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 6d0c395d20e5..5eddc2723e78 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -446,9 +446,15 @@ struct lynx_28g_lane { enum lynx_lane_mode mode; }; +struct lynx_info { + bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode); + int first_lane; +}; + struct lynx_28g_priv { void __iomem *base; struct device *dev; + const struct lynx_info *info; /* Serialize concurrent access to registers shared between lanes, * like PCCn */ @@ -513,11 +519,18 @@ static enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf) } } -static bool lynx_28g_supports_lane_mode(struct lynx_28g_priv *priv, +/* A lane mode is supported if we have a PLL that can provide its required + * clock net, and if there is a protocol converter for that mode on that lane. + */ +static bool lynx_28g_supports_lane_mode(struct lynx_28g_lane *lane, enum lynx_lane_mode mode) { + struct lynx_28g_priv *priv = lane->priv; int i; + if (!priv->info->lane_supports_mode(lane->id, mode)) + return false; + for (i = 0; i < LYNX_28G_NUM_PLL; i++) { if (PLLnRSTCTL_DIS(priv->pll[i].rstctl)) continue; @@ -783,6 +796,87 @@ static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode) } } +static bool lx2160a_serdes1_lane_supports_mode(int lane, + enum lynx_lane_mode mode) +{ + return true; +} + +static bool lx2160a_serdes2_lane_supports_mode(int lane, + enum lynx_lane_mode mode) +{ + switch (mode) { + case LANE_MODE_1000BASEX_SGMII: + return true; + case LANE_MODE_USXGMII: + case LANE_MODE_10GBASER: + return lane == 6 || lane == 7; + default: + return false; + } +} + +static bool lx2160a_serdes3_lane_supports_mode(int lane, + enum lynx_lane_mode mode) +{ + /* + * Non-networking SerDes, and this driver supports only + * networking protocols + */ + return false; +} + +static bool lx2162a_serdes1_lane_supports_mode(int lane, + enum lynx_lane_mode mode) +{ + return true; +} + +static bool lx2162a_serdes2_lane_supports_mode(int lane, + enum lynx_lane_mode mode) +{ + return lx2160a_serdes2_lane_supports_mode(lane, mode); +} + +/* Feature set is not expected to grow for the deprecated compatible string */ +static bool lynx_28g_compat_lane_supports_mode(int lane, + enum lynx_lane_mode mode) +{ + switch (mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_USXGMII: + case LANE_MODE_10GBASER: + return true; + default: + return false; + } +} + +static const struct lynx_info lynx_info_compat = { + .lane_supports_mode = lynx_28g_compat_lane_supports_mode, +}; + +static const struct lynx_info lynx_info_lx2160a_serdes1 = { + .lane_supports_mode = lx2160a_serdes1_lane_supports_mode, +}; + +static const struct lynx_info lynx_info_lx2160a_serdes2 = { + .lane_supports_mode = lx2160a_serdes2_lane_supports_mode, +}; + +static const struct lynx_info lynx_info_lx2160a_serdes3 = { + .lane_supports_mode = lx2160a_serdes3_lane_supports_mode, +}; + +static const struct lynx_info lynx_info_lx2162a_serdes1 = { + .lane_supports_mode = lx2162a_serdes1_lane_supports_mode, + .first_lane = 4, +}; + +static const struct lynx_info lynx_info_lx2162a_serdes2 = { + .lane_supports_mode = lx2162a_serdes2_lane_supports_mode, +}; + static int lynx_pccr_read(struct lynx_28g_lane *lane, enum lynx_lane_mode mode, u32 *val) { @@ -1035,7 +1129,6 @@ static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane, static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct lynx_28g_lane *lane = phy_get_drvdata(phy); - struct lynx_28g_priv *priv = lane->priv; int powered_up = lane->powered_up; enum lynx_lane_mode lane_mode; int err = 0; @@ -1047,7 +1140,7 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode) return -EOPNOTSUPP; lane_mode = phy_interface_to_lane_mode(submode); - if (!lynx_28g_supports_lane_mode(priv, lane_mode)) + if (!lynx_28g_supports_lane_mode(lane, lane_mode)) return -EOPNOTSUPP; if (lane_mode == lane->mode) @@ -1083,14 +1176,13 @@ static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode, union phy_configure_opts *opts __always_unused) { struct lynx_28g_lane *lane = phy_get_drvdata(phy); - struct lynx_28g_priv *priv = lane->priv; enum lynx_lane_mode lane_mode; if (mode != PHY_MODE_ETHERNET) return -EOPNOTSUPP; lane_mode = phy_interface_to_lane_mode(submode); - if (!lynx_28g_supports_lane_mode(priv, lane_mode)) + if (!lynx_28g_supports_lane_mode(lane, lane_mode)) return -EOPNOTSUPP; return 0; @@ -1183,7 +1275,7 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work) u32 rrstctl; int err, i; - for (i = 0; i < LYNX_28G_NUM_LANE; i++) { + for (i = priv->info->first_lane; i < LYNX_28G_NUM_LANE; i++) { lane = &priv->lane[i]; if (!lane->phy) continue; @@ -1253,7 +1345,8 @@ static struct phy *lynx_28g_xlate(struct device *dev, idx = args->args[0]; - if (WARN_ON(idx >= LYNX_28G_NUM_LANE)) + if (WARN_ON(idx >= LYNX_28G_NUM_LANE || + idx < priv->info->first_lane)) return ERR_PTR(-EINVAL); return priv->lane[idx].phy; @@ -1297,10 +1390,18 @@ static int lynx_28g_probe(struct platform_device *pdev) return -ENOMEM; priv->dev = dev; + priv->info = of_device_get_match_data(dev); dev_set_drvdata(dev, priv); spin_lock_init(&priv->pcc_lock); INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check); + /* + * If we get here it means we probed on a device tree where + * "fsl,lynx-28g" wasn't the fallback, but the sole compatible string. + */ + if (priv->info == &lynx_info_compat) + dev_warn(dev, "Please update device tree to use per-device compatible strings\n"); + priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); @@ -1323,7 +1424,7 @@ static int lynx_28g_probe(struct platform_device *pdev) return -EINVAL; } - if (reg >= LYNX_28G_NUM_LANE) { + if (reg < priv->info->first_lane || reg >= LYNX_28G_NUM_LANE) { dev_err(dev, "\"reg\" property out of range for %pOF\n", child); of_node_put(child); return -EINVAL; @@ -1336,7 +1437,7 @@ static int lynx_28g_probe(struct platform_device *pdev) } } } else { - for (int i = 0; i < LYNX_28G_NUM_LANE; i++) { + for (int i = priv->info->first_lane; i < LYNX_28G_NUM_LANE; i++) { err = lynx_28g_probe_lane(priv, i, NULL); if (err) return err; @@ -1362,7 +1463,12 @@ static void lynx_28g_remove(struct platform_device *pdev) } static const struct of_device_id lynx_28g_of_match_table[] = { - { .compatible = "fsl,lynx-28g" }, + { .compatible = "fsl,lx2160a-serdes1", .data = &lynx_info_lx2160a_serdes1 }, + { .compatible = "fsl,lx2160a-serdes2", .data = &lynx_info_lx2160a_serdes2 }, + { .compatible = "fsl,lx2160a-serdes3", .data = &lynx_info_lx2160a_serdes3 }, + { .compatible = "fsl,lx2162a-serdes1", .data = &lynx_info_lx2162a_serdes1 }, + { .compatible = "fsl,lx2162a-serdes2", .data = &lynx_info_lx2162a_serdes2 }, + { .compatible = "fsl,lynx-28g", .data = &lynx_info_compat }, /* fallback, keep last */ { }, }; MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table); From 1cab8fba5073962712fae3b763417af95ccf476a Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 11 May 2026 18:00:23 +0300 Subject: [PATCH 37/87] phy: lynx-28g: add support for 25GBASER Add support for 25GBASE-R in the Lynx 28G SerDes PHY driver. This will be used by the dpaa2-mac consumer on LX2160A with: - phy_validate(phy, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_25GBASER) to detect support. - phy_set_mode_ext(phy, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_25GBASER) to reconfigure the lane for this protocol. The intended use case for dynamic protocol switching to 25GBase-R is with SFP28 modules, and protocol switching is triggered by the SFP module insertion. There also exists a 25GBase-KR use case, where the protocol switching is covered by IEEE 802.3 clause 73 auto-negotiation. However, that is not handled here; it merely needs the support added here as basic ground work. The lane frequency for 25GbE is sourced from a clock net frequency of 12.890625 GHz, as produced by PLLF or PLLS, further multiplied by the lane by 2. The clock net frequencies produced by the PLLs are treated as read-only by the driver, so the absence of a PLL provisioned for the right clock net frequency implies absence of 25GbE support, even though a lane might have the appropriate protocol converter for it. In terms of implementation, the change consists of: - determining at probe time if any PLL was preconfigured for the required clock net frequency for 25GbE - adding the default lane parameters for reconfiguring a lane to 25GbE irrespective of the original protocol - allowing this operating mode only on supported lanes, i.e. all lanes of LX2162A SerDes #1, and LX2160A SerDes lanes 0-1, 4-7. Signed-off-by: Ioana Ciornei Signed-off-by: Vladimir Oltean Tested-by: Josua Mayer Link: https://patch.msgid.link/20260511150023.1903577-6-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 90 +++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 5eddc2723e78..92bfc5f65e0b 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -57,6 +57,7 @@ #define PLLnCR1_FRATE_5G_10GVCO 0x0 #define PLLnCR1_FRATE_5G_25GVCO 0x10 #define PLLnCR1_FRATE_10G_20GVCO 0x6 +#define PLLnCR1_FRATE_12G_25GVCO 0x16 /* Per SerDes lane registers */ /* Lane a General Control Register */ @@ -64,9 +65,11 @@ #define LNaGCR0_PROTO_SEL GENMASK(7, 3) #define LNaGCR0_PROTO_SEL_SGMII 0x1 #define LNaGCR0_PROTO_SEL_XFI 0xa +#define LNaGCR0_PROTO_SEL_25G 0x1a #define LNaGCR0_IF_WIDTH GENMASK(2, 0) #define LNaGCR0_IF_WIDTH_10_BIT 0x0 #define LNaGCR0_IF_WIDTH_20_BIT 0x2 +#define LNaGCR0_IF_WIDTH_40_BIT 0x4 /* Lane a Tx Reset Control Register */ #define LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20) @@ -85,6 +88,7 @@ #define LNaTGCR0_N_RATE_FULL 0x0 #define LNaTGCR0_N_RATE_HALF 0x1 #define LNaTGCR0_N_RATE_QUARTER 0x2 +#define LNaTGCR0_N_RATE_DOUBLE 0x3 #define LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30) #define LNaTECR0_EQ_TYPE GENMASK(30, 28) @@ -116,6 +120,7 @@ #define LNaRGCR0_N_RATE_FULL 0x0 #define LNaRGCR0_N_RATE_HALF 0x1 #define LNaRGCR0_N_RATE_QUARTER 0x2 +#define LNaRGCR0_N_RATE_DOUBLE 0x3 #define LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48) #define LNaRGCR1_RX_ORD_ELECIDLE BIT(31) @@ -282,6 +287,7 @@ enum lynx_lane_mode { LANE_MODE_1000BASEX_SGMII, LANE_MODE_10GBASER, LANE_MODE_USXGMII, + LANE_MODE_25GBASER, LANE_MODE_MAX, }; @@ -420,6 +426,41 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = { .ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP | LNaTTLCR0_DATA_IN_SSC, }, + [LANE_MODE_25GBASER] = { + .proto_sel = LNaGCR0_PROTO_SEL_25G, + .if_width = LNaGCR0_IF_WIDTH_40_BIT, + .teq_type = EQ_TYPE_3TAP, + .sgn_preq = 1, + .ratio_preq = 2, + .sgn_post1q = 1, + .ratio_post1q = 7, + .amp_red = 0, + .adpt_eq = 48, + .enter_idle_flt_sel = 0, + .exit_idle_flt_sel = 0, + .data_lost_th_sel = 0, + .gk2ovd = 0, + .gk3ovd = 0, + .gk4ovd = 5, + .gk2ovd_en = 0, + .gk3ovd_en = 0, + .gk4ovd_en = 1, + .eq_offset_ovd = 0x1f, + .eq_offset_ovd_en = 0, + .eq_offset_rng_dbl = 1, + .eq_blw_sel = 1, + .eq_boost = 2, + .spare_in = 3, + .smp_autoz_d1r = 2, + .smp_autoz_eg1r = 2, + .rccr0 = LNaRCCR0_CAL_EN | + LNaRCCR0_CAL_DC3_DIS | + LNaRCCR0_CAL_DC2_DIS | + LNaRCCR0_CAL_DC1_DIS | + LNaRCCR0_CAL_DC0_DIS, + .ttlcr0 = LNaTTLCR0_DATA_IN_SSC | + FIELD_PREP_CONST(LNaTTLCR0_CDR_MIN_SMP_ON, 1), + }, }; struct lynx_pccr { @@ -499,6 +540,8 @@ static const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode) return "10GBase-R"; case LANE_MODE_USXGMII: return "USXGMII"; + case LANE_MODE_25GBASER: + return "25GBase-R"; default: return "unknown"; } @@ -514,6 +557,8 @@ static enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf) return LANE_MODE_10GBASER; case PHY_INTERFACE_MODE_USXGMII: return LANE_MODE_USXGMII; + case PHY_INTERFACE_MODE_25GBASER: + return LANE_MODE_25GBASER; default: return LANE_MODE_UNKNOWN; } @@ -601,6 +646,20 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane, break; } break; + case PLLnCR1_FRATE_12G_25GVCO: + switch (lane_mode) { + case LANE_MODE_25GBASER: + lynx_28g_lane_rmw(lane, LNaTGCR0, + FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_DOUBLE), + LNaTGCR0_N_RATE); + lynx_28g_lane_rmw(lane, LNaRGCR0, + FIELD_PREP(LNaRGCR0_N_RATE, LNaRGCR0_N_RATE_DOUBLE), + LNaRGCR0_N_RATE); + break; + default: + break; + } + break; default: break; } @@ -761,6 +820,11 @@ static int lynx_28g_power_on(struct phy *phy) return 0; } +static int lynx_28g_e25g_pcvt(int lane) +{ + return 7 - lane; +} + static int lynx_28g_get_pccr(enum lynx_lane_mode lane_mode, int lane, struct lynx_pccr *pccr) { @@ -776,6 +840,11 @@ static int lynx_28g_get_pccr(enum lynx_lane_mode lane_mode, int lane, pccr->width = 4; pccr->shift = SXGMII_CFG(lane); break; + case LANE_MODE_25GBASER: + pccr->offset = PCCD; + pccr->width = 4; + pccr->shift = E25G_CFG(lynx_28g_e25g_pcvt(lane)); + break; default: return -EOPNOTSUPP; } @@ -791,6 +860,8 @@ static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode) case LANE_MODE_USXGMII: case LANE_MODE_10GBASER: return SXGMIIaCR0(lane); + case LANE_MODE_25GBASER: + return E25GaCR0(lynx_28g_e25g_pcvt(lane)); default: return -EOPNOTSUPP; } @@ -799,7 +870,12 @@ static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode) static bool lx2160a_serdes1_lane_supports_mode(int lane, enum lynx_lane_mode mode) { - return true; + switch (mode) { + case LANE_MODE_25GBASER: + return lane != 2 && lane != 3; + default: + return true; + } } static bool lx2160a_serdes2_lane_supports_mode(int lane, @@ -1115,6 +1191,9 @@ static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane, case LANE_MODE_USXGMII: val |= PCCC_SXGMIIn_CFG; break; + case LANE_MODE_25GBASER: + val |= PCCD_E25Gn_CFG; + break; default: break; } @@ -1259,8 +1338,12 @@ static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv) __set_bit(LANE_MODE_10GBASER, pll->supported); __set_bit(LANE_MODE_USXGMII, pll->supported); break; + case PLLnCR1_FRATE_12G_25GVCO: + /* 12.890625GHz clock net */ + __set_bit(LANE_MODE_25GBASER, pll->supported); + break; default: - /* 6GHz, 12.890625GHz, 8GHz */ + /* 6GHz, 8GHz */ break; } } @@ -1327,6 +1410,9 @@ static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane) else lane->mode = LANE_MODE_USXGMII; break; + case LNaPSS_TYPE_25G: + lane->mode = LANE_MODE_25GBASER; + break; default: lane->mode = LANE_MODE_UNKNOWN; } From ebee9004cc0200b2b708ebf7ac625d35c71c049f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 14 May 2026 00:01:26 +0200 Subject: [PATCH 38/87] phy: phy-can-transceiver: Check driver match and driver data against NULL Every platform driver can be forced to match a device that doesn't match its list of device IDs because of device_match_driver_override() so platform drivers that rely on the existence of a device's driver data need to verify its presence. Accordingly, add requisite match and driver data checks against NULL to the driver where they are missing. Fixes: a4a86d273ff1 ("phy: phy-can-transceiver: Add support for generic CAN transceiver driver") Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20260513220336.369628-2-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/phy/phy-can-transceiver.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c index 2b52e47f247a..1808f903c057 100644 --- a/drivers/phy/phy-can-transceiver.c +++ b/drivers/phy/phy-can-transceiver.c @@ -162,6 +162,9 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) int err, i, num_ch = 1; match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node); + if (!match || !match->data) + return -ENODEV; + drvdata = match->data; if (drvdata->flags & CAN_TRANSCEIVER_DUAL_CH) num_ch = 2; From 23db9fd578ca3b446ceaa5c9a0157f0838f4df4e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 14 May 2026 00:01:27 +0200 Subject: [PATCH 39/87] phy: phy-can-transceiver: use device_get_match_data() Use the generic firmware node interface for retrieving device match data instead of the OF-specific one. While at it, drop unneeded argument to devm_phy_create() which extracts device node from the given device by default. Reviewed-by: Josua Mayer Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20260513220336.369628-3-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/phy/phy-can-transceiver.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c index 1808f903c057..37b706d841ff 100644 --- a/drivers/phy/phy-can-transceiver.c +++ b/drivers/phy/phy-can-transceiver.c @@ -5,9 +5,9 @@ * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com * */ -#include #include #include +#include #include #include #include @@ -152,7 +152,6 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) struct can_transceiver_phy *can_transceiver_phy; struct can_transceiver_priv *priv; const struct can_transceiver_data *drvdata; - const struct of_device_id *match; struct phy *phy; struct gpio_desc *silent_gpio; struct gpio_desc *standby_gpio; @@ -161,11 +160,10 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) u32 max_bitrate = 0; int err, i, num_ch = 1; - match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node); - if (!match || !match->data) + drvdata = device_get_match_data(dev); + if (!drvdata) return -ENODEV; - drvdata = match->data; if (drvdata->flags & CAN_TRANSCEIVER_DUAL_CH) num_ch = 2; @@ -190,7 +188,7 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) can_transceiver_phy = &priv->can_transceiver_phy[i]; can_transceiver_phy->priv = priv; - phy = devm_phy_create(dev, dev->of_node, &can_transceiver_phy_ops); + phy = devm_phy_create(dev, NULL, &can_transceiver_phy_ops); if (IS_ERR(phy)) { dev_err(dev, "failed to create can transceiver phy\n"); return PTR_ERR(phy); From 62455f6be1256084cfff8690df416f418b6f0dd2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 14 May 2026 00:01:28 +0200 Subject: [PATCH 40/87] phy: phy-can-transceiver: Move OF ID table closer to their user There is no code that uses ID table directly, except the struct device_driver at the end of the file. Hence, move table closer to its user. It's always possible to access them via a pointer. Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20260513220336.369628-4-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/phy/phy-can-transceiver.c | 58 +++++++++++++++---------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c index 37b706d841ff..5c9698f77c7d 100644 --- a/drivers/phy/phy-can-transceiver.c +++ b/drivers/phy/phy-can-transceiver.c @@ -97,35 +97,6 @@ static const struct can_transceiver_data tja1057_drvdata = { .flags = CAN_TRANSCEIVER_SILENT_PRESENT, }; -static const struct of_device_id can_transceiver_phy_ids[] = { - { - .compatible = "ti,tcan1042", - .data = &tcan1042_drvdata - }, - { - .compatible = "ti,tcan1043", - .data = &tcan1043_drvdata - }, - { - .compatible = "nxp,tja1048", - .data = &tja1048_drvdata - }, - { - .compatible = "nxp,tja1051", - .data = &tja1051_drvdata - }, - { - .compatible = "nxp,tja1057", - .data = &tja1057_drvdata - }, - { - .compatible = "nxp,tjr1443", - .data = &tcan1043_drvdata - }, - { } -}; -MODULE_DEVICE_TABLE(of, can_transceiver_phy_ids); - static struct phy *can_transceiver_phy_xlate(struct device *dev, const struct of_phandle_args *args) { @@ -232,6 +203,35 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(phy_provider); } +static const struct of_device_id can_transceiver_phy_ids[] = { + { + .compatible = "ti,tcan1042", + .data = &tcan1042_drvdata + }, + { + .compatible = "ti,tcan1043", + .data = &tcan1043_drvdata + }, + { + .compatible = "nxp,tja1048", + .data = &tja1048_drvdata + }, + { + .compatible = "nxp,tja1051", + .data = &tja1051_drvdata + }, + { + .compatible = "nxp,tja1057", + .data = &tja1057_drvdata + }, + { + .compatible = "nxp,tjr1443", + .data = &tcan1043_drvdata + }, + { } +}; +MODULE_DEVICE_TABLE(of, can_transceiver_phy_ids); + static struct platform_driver can_transceiver_phy_driver = { .probe = can_transceiver_phy_probe, .driver = { From 79a5274fb39904f8a60bdd7bf7753ee1ba700210 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 14 May 2026 00:01:29 +0200 Subject: [PATCH 41/87] phy: phy-can-transceiver: Don't check for specific errors when parsing properties Instead of checking for the specific error codes (that can be considered a layering violation to some extent) check for the property existence first and then either parse it, or apply a default value. With that, return an error when parsing of the existing property fails. Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20260513220336.369628-5-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/phy/phy-can-transceiver.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c index 5c9698f77c7d..3cebaa54f7db 100644 --- a/drivers/phy/phy-can-transceiver.c +++ b/drivers/phy/phy-can-transceiver.c @@ -128,8 +128,9 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) struct gpio_desc *standby_gpio; struct gpio_desc *enable_gpio; struct mux_state *mux_state; - u32 max_bitrate = 0; int err, i, num_ch = 1; + const char *propname; + u32 max_bitrate; drvdata = device_get_match_data(dev); if (!drvdata) @@ -151,9 +152,17 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) priv->mux_state = mux_state; - err = device_property_read_u32(dev, "max-bitrate", &max_bitrate); - if ((err != -EINVAL) && !max_bitrate) - dev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit\n"); + propname = "max-bitrate"; + if (device_property_present(dev, propname)) { + err = device_property_read_u32(dev, propname, &max_bitrate); + if (err) + return dev_err_probe(dev, err, "failed to parse %s\n", propname); + + if (max_bitrate == 0) + dev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit\n"); + } else { + max_bitrate = 0; + } for (i = 0; i < num_ch; i++) { can_transceiver_phy = &priv->can_transceiver_phy[i]; From 05c72fbff4ac18e9bbb0e4b3884dad1f833807f4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 14 May 2026 00:01:30 +0200 Subject: [PATCH 42/87] phy: phy-can-transceiver: Decouple assignment and definition in probe The code like int foo = X; ... if (bar) foo = Y; is prone to subtle mistakes and hence harder to maintain as the foo value may be changed inadvertently while code in '...' grown in lines. On top it's harder to navigate to understand the possible values of foo when branch is not taken (requires to look somewhere else in the code, far from the piece at hand). Besides that in case of taken branch the foo will be rewritten, which is not a problem per se, just an unneeded operation. Decouple assignment and definition to use if-else to address the inconveniences described above. Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20260513220336.369628-6-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/phy/phy-can-transceiver.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c index 3cebaa54f7db..30330499585b 100644 --- a/drivers/phy/phy-can-transceiver.c +++ b/drivers/phy/phy-can-transceiver.c @@ -128,8 +128,8 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) struct gpio_desc *standby_gpio; struct gpio_desc *enable_gpio; struct mux_state *mux_state; - int err, i, num_ch = 1; const char *propname; + int err, i, num_ch; u32 max_bitrate; drvdata = device_get_match_data(dev); @@ -138,6 +138,8 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) if (drvdata->flags & CAN_TRANSCEIVER_DUAL_CH) num_ch = 2; + else + num_ch = 1; priv = devm_kzalloc(dev, struct_size(priv, can_transceiver_phy, num_ch), GFP_KERNEL); if (!priv) From 52ae64602394bc9a8e7b67f5e4e70c56e31699a7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 14 May 2026 00:01:31 +0200 Subject: [PATCH 43/87] phy: phy-can-transceiver: Drop unused include This file does not use the symbols from the legacy header, so let's drop it. Reviewed-by: Josua Mayer Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20260513220336.369628-7-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/phy/phy-can-transceiver.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c index 30330499585b..75dc49e75ca0 100644 --- a/drivers/phy/phy-can-transceiver.c +++ b/drivers/phy/phy-can-transceiver.c @@ -5,12 +5,11 @@ * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com * */ +#include #include #include #include #include -#include -#include #include struct can_transceiver_data { From a896852613136e6babe6036567ab0989fb322a57 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Tue, 5 May 2026 19:04:06 +0200 Subject: [PATCH 44/87] dt-bindings: phy: rockchip,inno-usb2phy: Require GRF for RK3568/RV1108 Typically these Rockchip USB2 PHYs are fully contained within a single GRF. However, for RK3568 and RV1108 regs to control the USB2 PHY is located in a different GRF compared to the base address. Update this binding to require rockchip,usbgrf for RK3568 and RV1108 to properly reflect that the USB GRF is required to control the USB2 PHYs on these variants. Also disable use of rockchip,usbgrf for variants where it is not required. This should not introduce any breakage as the affected usb2phy nodes for RK3568 and RV1108 were added together with a rockchip,usbgrf phandle in their initial commit. Signed-off-by: Jonas Karlman Acked-by: Rob Herring (Arm) Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20260505170410.3265305-2-heiko@sntech.de Signed-off-by: Vinod Koul --- .../bindings/phy/rockchip,inno-usb2phy.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml b/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml index 58e735b5dd05..b95c9e3e44fe 100644 --- a/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml +++ b/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml @@ -145,6 +145,20 @@ anyOf: - host-port allOf: + - if: + properties: + compatible: + contains: + enum: + - rockchip,rk3568-usb2phy + - rockchip,rv1108-usb2phy + then: + required: + - rockchip,usbgrf + else: + properties: + rockchip,usbgrf: false + - if: properties: compatible: From be29cd958f5393004a24cd7b5b1da88dd90a651b Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Tue, 5 May 2026 19:04:07 +0200 Subject: [PATCH 45/87] phy: rockchip: inno-usb2: Simplify rockchip,usbgrf handling The logic to decide if usbgrf or grf should be used is more complex than it needs to be. For RK3568, RV1108 and soon RK3528 we can assign the rockchip,usbgrf regmap directly to grf instead of doing a usbgrf and grf dance. Simplify the code to only use the grf regmap and handle the logic of what regmap should be used in driver probe instead. The only expected change from this is that RK3528 can be supported because of an addition of a of_property_present() check. Signed-off-by: Jonas Karlman Signed-off-by: Heiko Stuebner Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20260505170410.3265305-3-heiko@sntech.de Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 68 +++++-------------- 1 file changed, 18 insertions(+), 50 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 8f4c08e599aa..7cec45192393 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -228,7 +228,6 @@ struct rockchip_usb2phy_port { * struct rockchip_usb2phy - usb2.0 phy driver data. * @dev: pointer to device. * @grf: General Register Files regmap. - * @usbgrf: USB General Register Files regmap. * @clks: array of phy input clocks. * @clk480m: clock struct of phy output clk. * @clk480m_hw: clock struct of phy output clk management. @@ -246,7 +245,6 @@ struct rockchip_usb2phy_port { struct rockchip_usb2phy { struct device *dev; struct regmap *grf; - struct regmap *usbgrf; struct clk_bulk_data *clks; struct clk *clk480m; struct clk_hw clk480m_hw; @@ -261,11 +259,6 @@ struct rockchip_usb2phy { struct rockchip_usb2phy_port ports[USB2PHY_NUM_PORTS]; }; -static inline struct regmap *get_reg_base(struct rockchip_usb2phy *rphy) -{ - return rphy->usbgrf == NULL ? rphy->grf : rphy->usbgrf; -} - static inline int property_enable(struct regmap *base, const struct usb2phy_reg *reg, bool en) { @@ -323,12 +316,11 @@ static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw) { struct rockchip_usb2phy *rphy = container_of(hw, struct rockchip_usb2phy, clk480m_hw); - struct regmap *base = get_reg_base(rphy); int ret; /* turn on 480m clk output if it is off */ - if (!property_enabled(base, &rphy->phy_cfg->clkout_ctl)) { - ret = property_enable(base, &rphy->phy_cfg->clkout_ctl, true); + if (!property_enabled(rphy->grf, &rphy->phy_cfg->clkout_ctl)) { + ret = property_enable(rphy->grf, &rphy->phy_cfg->clkout_ctl, true); if (ret) return ret; @@ -343,19 +335,17 @@ static void rockchip_usb2phy_clk480m_unprepare(struct clk_hw *hw) { struct rockchip_usb2phy *rphy = container_of(hw, struct rockchip_usb2phy, clk480m_hw); - struct regmap *base = get_reg_base(rphy); /* turn off 480m clk output */ - property_enable(base, &rphy->phy_cfg->clkout_ctl, false); + property_enable(rphy->grf, &rphy->phy_cfg->clkout_ctl, false); } static int rockchip_usb2phy_clk480m_prepared(struct clk_hw *hw) { struct rockchip_usb2phy *rphy = container_of(hw, struct rockchip_usb2phy, clk480m_hw); - struct regmap *base = get_reg_base(rphy); - return property_enabled(base, &rphy->phy_cfg->clkout_ctl); + return property_enabled(rphy->grf, &rphy->phy_cfg->clkout_ctl); } static unsigned long @@ -574,7 +564,6 @@ static int rockchip_usb2phy_power_on(struct phy *phy) { struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); - struct regmap *base = get_reg_base(rphy); int ret; dev_dbg(&rport->phy->dev, "port power on\n"); @@ -586,7 +575,7 @@ static int rockchip_usb2phy_power_on(struct phy *phy) if (ret) return ret; - ret = property_enable(base, &rport->port_cfg->phy_sus, false); + ret = property_enable(rphy->grf, &rport->port_cfg->phy_sus, false); if (ret) { clk_disable_unprepare(rphy->clk480m); return ret; @@ -615,7 +604,6 @@ static int rockchip_usb2phy_power_off(struct phy *phy) { struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); - struct regmap *base = get_reg_base(rphy); int ret; dev_dbg(&rport->phy->dev, "port power off\n"); @@ -623,7 +611,7 @@ static int rockchip_usb2phy_power_off(struct phy *phy) if (rport->suspended) return 0; - ret = property_enable(base, &rport->port_cfg->phy_sus, true); + ret = property_enable(rphy->grf, &rport->port_cfg->phy_sus, true); if (ret) return ret; @@ -787,28 +775,22 @@ static const char *chg_to_string(enum power_supply_type chg_type) static void rockchip_chg_enable_dcd(struct rockchip_usb2phy *rphy, bool en) { - struct regmap *base = get_reg_base(rphy); - - property_enable(base, &rphy->phy_cfg->chg_det.rdm_pdwn_en, en); - property_enable(base, &rphy->phy_cfg->chg_det.idp_src_en, en); + property_enable(rphy->grf, &rphy->phy_cfg->chg_det.rdm_pdwn_en, en); + property_enable(rphy->grf, &rphy->phy_cfg->chg_det.idp_src_en, en); } static void rockchip_chg_enable_primary_det(struct rockchip_usb2phy *rphy, bool en) { - struct regmap *base = get_reg_base(rphy); - - property_enable(base, &rphy->phy_cfg->chg_det.vdp_src_en, en); - property_enable(base, &rphy->phy_cfg->chg_det.idm_sink_en, en); + property_enable(rphy->grf, &rphy->phy_cfg->chg_det.vdp_src_en, en); + property_enable(rphy->grf, &rphy->phy_cfg->chg_det.idm_sink_en, en); } static void rockchip_chg_enable_secondary_det(struct rockchip_usb2phy *rphy, bool en) { - struct regmap *base = get_reg_base(rphy); - - property_enable(base, &rphy->phy_cfg->chg_det.vdm_src_en, en); - property_enable(base, &rphy->phy_cfg->chg_det.idp_sink_en, en); + property_enable(rphy->grf, &rphy->phy_cfg->chg_det.vdm_src_en, en); + property_enable(rphy->grf, &rphy->phy_cfg->chg_det.idp_sink_en, en); } #define CHG_DCD_POLL_TIME (100 * HZ / 1000) @@ -820,7 +802,6 @@ static void rockchip_chg_detect_work(struct work_struct *work) struct rockchip_usb2phy_port *rport = container_of(work, struct rockchip_usb2phy_port, chg_work.work); struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); - struct regmap *base = get_reg_base(rphy); bool is_dcd, tmout, vout, vbus_attach; unsigned long delay; @@ -834,7 +815,7 @@ static void rockchip_chg_detect_work(struct work_struct *work) rockchip_usb2phy_power_off(rport->phy); /* put the controller in non-driving mode */ if (!vbus_attach) - property_enable(base, &rphy->phy_cfg->chg_det.opmode, false); + property_enable(rphy->grf, &rphy->phy_cfg->chg_det.opmode, false); /* Start DCD processing stage 1 */ rockchip_chg_enable_dcd(rphy, true); rphy->chg_state = USB_CHG_STATE_WAIT_FOR_DCD; @@ -898,7 +879,7 @@ static void rockchip_chg_detect_work(struct work_struct *work) case USB_CHG_STATE_DETECTED: /* put the controller in normal mode */ if (!vbus_attach) - property_enable(base, &rphy->phy_cfg->chg_det.opmode, true); + property_enable(rphy->grf, &rphy->phy_cfg->chg_det.opmode, true); rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work); dev_dbg(&rport->phy->dev, "charger = %s\n", chg_to_string(rphy->chg_type)); @@ -1353,27 +1334,14 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) if (!rphy) return -ENOMEM; - if (!dev->parent || !dev->parent->of_node) { + if (!dev->parent || !dev->parent->of_node || + of_property_present(np, "rockchip,usbgrf")) { rphy->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,usbgrf"); - if (IS_ERR(rphy->grf)) { - dev_err(dev, "failed to locate usbgrf\n"); - return PTR_ERR(rphy->grf); - } } else { rphy->grf = syscon_node_to_regmap(dev->parent->of_node); - if (IS_ERR(rphy->grf)) - return PTR_ERR(rphy->grf); - } - - if (of_device_is_compatible(np, "rockchip,rv1108-usb2phy")) { - rphy->usbgrf = - syscon_regmap_lookup_by_phandle(dev->of_node, - "rockchip,usbgrf"); - if (IS_ERR(rphy->usbgrf)) - return PTR_ERR(rphy->usbgrf); - } else { - rphy->usbgrf = NULL; } + if (IS_ERR(rphy->grf)) + return PTR_ERR(rphy->grf); if (of_property_read_u32_index(np, "reg", 0, ®)) { dev_err(dev, "the reg property is not assigned in %pOFn node\n", np); From c430f042f4ba2c5abd592b6924f028d3bb09d4cf Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Tue, 5 May 2026 19:04:08 +0200 Subject: [PATCH 46/87] dt-bindings: phy: rockchip,inno-usb2phy: Add compatible for RK3528 The embedded USB2 PHY on RK3528 is very similar to the one in RK3568, the main difference being that it only uses two clocks instead of three. Add compatible to support the USB2 PHY in RK3528. Signed-off-by: Jonas Karlman Reviewed-by: Rob Herring (Arm) Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20260505170410.3265305-4-heiko@sntech.de Signed-off-by: Vinod Koul --- .../bindings/phy/rockchip,inno-usb2phy.yaml | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml b/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml index b95c9e3e44fe..f50fc69fbbe4 100644 --- a/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml +++ b/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml @@ -20,6 +20,7 @@ properties: - rockchip,rk3328-usb2phy - rockchip,rk3366-usb2phy - rockchip,rk3399-usb2phy + - rockchip,rk3528-usb2phy - rockchip,rk3562-usb2phy - rockchip,rk3568-usb2phy - rockchip,rk3576-usb2phy @@ -41,11 +42,15 @@ properties: maxItems: 3 clock-names: - minItems: 1 - items: + oneOf: - const: phyclk - - const: aclk - - const: aclk_slv + - items: + - const: phyclk + - const: pclk + - items: + - const: phyclk + - const: aclk + - const: aclk_slv assigned-clocks: description: @@ -65,6 +70,9 @@ properties: description: Muxed interrupt for both ports maxItems: 1 + power-domains: + maxItems: 1 + resets: maxItems: 2 @@ -150,6 +158,7 @@ allOf: compatible: contains: enum: + - rockchip,rk3528-usb2phy - rockchip,rk3568-usb2phy - rockchip,rv1108-usb2phy then: @@ -218,6 +227,19 @@ allOf: clock-names: maxItems: 1 + - if: + properties: + compatible: + contains: + enum: + - rockchip,rk3528-usb2phy + then: + properties: + clocks: + minItems: 2 + clock-names: + minItems: 2 + - if: properties: compatible: From 2775541de0580ab1cd077dfef710e6316563d567 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Tue, 5 May 2026 19:04:09 +0200 Subject: [PATCH 47/87] phy: rockchip: inno-usb2: Add clkout_ctl_phy support The 480m clk is controlled using regs in the PHY address space and not in the USB GRF address space on e.g. RK3528 and RK3506. Add a clkout_ctl_phy usb2phy_reg to handle enable/disable of the 480m clk on these SoCs. Signed-off-by: Jonas Karlman Signed-off-by: Heiko Stuebner Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20260505170410.3265305-5-heiko@sntech.de Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 7cec45192393..d8879fcd4291 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -179,6 +179,7 @@ struct rockchip_usb2phy_cfg { unsigned int num_ports; int (*phy_tuning)(struct rockchip_usb2phy *rphy); struct usb2phy_reg clkout_ctl; + struct usb2phy_reg clkout_ctl_phy; const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS]; const struct rockchip_chg_det_reg chg_det; }; @@ -228,6 +229,7 @@ struct rockchip_usb2phy_port { * struct rockchip_usb2phy - usb2.0 phy driver data. * @dev: pointer to device. * @grf: General Register Files regmap. + * @phy_base: USB PHY regmap. * @clks: array of phy input clocks. * @clk480m: clock struct of phy output clk. * @clk480m_hw: clock struct of phy output clk management. @@ -245,6 +247,7 @@ struct rockchip_usb2phy_port { struct rockchip_usb2phy { struct device *dev; struct regmap *grf; + struct regmap *phy_base; struct clk_bulk_data *clks; struct clk *clk480m; struct clk_hw clk480m_hw; @@ -312,15 +315,33 @@ static void rockchip_usb2phy_clk_bulk_disable(void *data) clk_bulk_disable_unprepare(rphy->num_clks, rphy->clks); } -static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw) +static void +rockchip_usb2phy_clk480m_clkout_ctl(struct clk_hw *hw, struct regmap **base, + const struct usb2phy_reg **clkout_ctl) { struct rockchip_usb2phy *rphy = container_of(hw, struct rockchip_usb2phy, clk480m_hw); + + if (rphy->phy_cfg->clkout_ctl_phy.enable) { + *base = rphy->phy_base; + *clkout_ctl = &rphy->phy_cfg->clkout_ctl_phy; + } else { + *base = rphy->grf; + *clkout_ctl = &rphy->phy_cfg->clkout_ctl; + } +} + +static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw) +{ + const struct usb2phy_reg *clkout_ctl; + struct regmap *base; int ret; + rockchip_usb2phy_clk480m_clkout_ctl(hw, &base, &clkout_ctl); + /* turn on 480m clk output if it is off */ - if (!property_enabled(rphy->grf, &rphy->phy_cfg->clkout_ctl)) { - ret = property_enable(rphy->grf, &rphy->phy_cfg->clkout_ctl, true); + if (!property_enabled(base, clkout_ctl)) { + ret = property_enable(base, clkout_ctl, true); if (ret) return ret; @@ -333,19 +354,23 @@ static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw) static void rockchip_usb2phy_clk480m_unprepare(struct clk_hw *hw) { - struct rockchip_usb2phy *rphy = - container_of(hw, struct rockchip_usb2phy, clk480m_hw); + const struct usb2phy_reg *clkout_ctl; + struct regmap *base; + + rockchip_usb2phy_clk480m_clkout_ctl(hw, &base, &clkout_ctl); /* turn off 480m clk output */ - property_enable(rphy->grf, &rphy->phy_cfg->clkout_ctl, false); + property_enable(base, clkout_ctl, false); } static int rockchip_usb2phy_clk480m_prepared(struct clk_hw *hw) { - struct rockchip_usb2phy *rphy = - container_of(hw, struct rockchip_usb2phy, clk480m_hw); + const struct usb2phy_reg *clkout_ctl; + struct regmap *base; - return property_enabled(rphy->grf, &rphy->phy_cfg->clkout_ctl); + rockchip_usb2phy_clk480m_clkout_ctl(hw, &base, &clkout_ctl); + + return property_enabled(base, clkout_ctl); } static unsigned long @@ -1336,9 +1361,13 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) if (!dev->parent || !dev->parent->of_node || of_property_present(np, "rockchip,usbgrf")) { + rphy->phy_base = device_node_to_regmap(np); + if (IS_ERR(rphy->phy_base)) + return PTR_ERR(rphy->phy_base); rphy->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,usbgrf"); } else { rphy->grf = syscon_node_to_regmap(dev->parent->of_node); + rphy->phy_base = rphy->grf; } if (IS_ERR(rphy->grf)) return PTR_ERR(rphy->grf); From 864b3617df827865a95a06f06f09a8d57a795b91 Mon Sep 17 00:00:00 2001 From: Jianwei Zheng Date: Tue, 5 May 2026 19:04:10 +0200 Subject: [PATCH 48/87] phy: rockchip: inno-usb2: Add support for RK3528 The RK3528 has a single USB2PHY with a otg and host port. Add support for the RK3528 variant of USB2PHY. PHY tuning for RK3528: - Turn off differential receiver in suspend mode to save power consumption. - Set HS eye-height to 400mV instead of default 450mV. - Choose the Tx fs/ls data as linestate from TX driver for otg port which uses dwc3 controller to improve fs/ls devices compatibility with long cables. Undocumented magic-values are based on the linux-stan-6.1-rkr5 tag of the vendor-kernel. Signed-off-by: Jianwei Zheng Signed-off-by: Jonas Karlman Signed-off-by: Heiko Stuebner Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20260505170410.3265305-6-heiko@sntech.de Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index d8879fcd4291..133cfd6624e8 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -1511,6 +1511,38 @@ static int rk3128_usb2phy_tuning(struct rockchip_usb2phy *rphy) BIT(2) << BIT_WRITEABLE_SHIFT | 0); } +static int rk3528_usb2phy_tuning(struct rockchip_usb2phy *rphy) +{ + int ret; + + /* Turn off otg port differential receiver in suspend mode */ + ret = regmap_write(rphy->phy_base, 0x30, BIT(18) | 0x0000); + if (ret) + return ret; + + /* Turn off host port differential receiver in suspend mode */ + ret = regmap_write(rphy->phy_base, 0x430, BIT(18) | 0x0000); + if (ret) + return ret; + + /* Set otg port HS eye height to 400mv (default is 450mv) */ + ret = regmap_write(rphy->phy_base, 0x30, GENMASK(22, 20) | 0x0000); + if (ret) + return ret; + + /* Set host port HS eye height to 400mv (default is 450mv) */ + ret = regmap_write(rphy->phy_base, 0x430, GENMASK(22, 20) | 0x0000); + if (ret) + return ret; + + /* Choose the Tx fs/ls data as linestate from TX driver for otg port */ + ret = regmap_write(rphy->phy_base, 0x94, GENMASK(22, 19) | 0x0018); + if (ret) + return ret; + + return 0; +} + static int rk3576_usb2phy_tuning(struct rockchip_usb2phy *rphy) { int ret; @@ -1924,6 +1956,57 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = { { /* sentinel */ } }; +static const struct rockchip_usb2phy_cfg rk3528_phy_cfgs[] = { + { + .reg = 0xffdf0000, + .num_ports = 2, + .phy_tuning = rk3528_usb2phy_tuning, + .clkout_ctl_phy = { 0x041c, 7, 2, 0, 0x27 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x004c, 8, 0, 0, 0x1d1 }, + .bvalid_det_en = { 0x0074, 3, 2, 0, 3 }, + .bvalid_det_st = { 0x0078, 3, 2, 0, 3 }, + .bvalid_det_clr = { 0x007c, 3, 2, 0, 3 }, + .idfall_det_en = { 0x0074, 5, 5, 0, 1 }, + .idfall_det_st = { 0x0078, 5, 5, 0, 1 }, + .idfall_det_clr = { 0x007c, 5, 5, 0, 1 }, + .idrise_det_en = { 0x0074, 4, 4, 0, 1 }, + .idrise_det_st = { 0x0078, 4, 4, 0, 1 }, + .idrise_det_clr = { 0x007c, 4, 4, 0, 1 }, + .ls_det_en = { 0x0074, 0, 0, 0, 1 }, + .ls_det_st = { 0x0078, 0, 0, 0, 1 }, + .ls_det_clr = { 0x007c, 0, 0, 0, 1 }, + .utmi_avalid = { 0x006c, 1, 1, 0, 1 }, + .utmi_bvalid = { 0x006c, 0, 0, 0, 1 }, + .utmi_id = { 0x006c, 6, 6, 0, 1 }, + .utmi_ls = { 0x006c, 5, 4, 0, 1 }, + }, + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0x005c, 8, 0, 0x1d2, 0x1d1 }, + .ls_det_en = { 0x0090, 0, 0, 0, 1 }, + .ls_det_st = { 0x0094, 0, 0, 0, 1 }, + .ls_det_clr = { 0x0098, 0, 0, 0, 1 }, + .utmi_ls = { 0x006c, 13, 12, 0, 1 }, + .utmi_hstdet = { 0x006c, 15, 15, 0, 1 }, + } + }, + .chg_det = { + .opmode = { 0x004c, 3, 0, 5, 1 }, + .cp_det = { 0x006c, 19, 19, 0, 1 }, + .dcp_det = { 0x006c, 18, 18, 0, 1 }, + .dp_det = { 0x006c, 20, 20, 0, 1 }, + .idm_sink_en = { 0x0058, 1, 1, 0, 1 }, + .idp_sink_en = { 0x0058, 0, 0, 0, 1 }, + .idp_src_en = { 0x0058, 2, 2, 0, 1 }, + .rdm_pdwn_en = { 0x0058, 3, 3, 0, 1 }, + .vdm_src_en = { 0x0058, 5, 5, 0, 1 }, + .vdp_src_en = { 0x0058, 4, 4, 0, 1 }, + }, + }, + { /* sentinel */ } +}; + static const struct rockchip_usb2phy_cfg rk3562_phy_cfgs[] = { { .reg = 0xff740000, @@ -2291,6 +2374,7 @@ static const struct of_device_id rockchip_usb2phy_dt_match[] = { { .compatible = "rockchip,rk3328-usb2phy", .data = &rk3328_phy_cfgs }, { .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs }, { .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs }, + { .compatible = "rockchip,rk3528-usb2phy", .data = &rk3528_phy_cfgs }, { .compatible = "rockchip,rk3562-usb2phy", .data = &rk3562_phy_cfgs }, { .compatible = "rockchip,rk3568-usb2phy", .data = &rk3568_phy_cfgs }, { .compatible = "rockchip,rk3576-usb2phy", .data = &rk3576_phy_cfgs }, From 2cc066dbd3a211628b40967949cff2790d0f62eb Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Sat, 25 Apr 2026 17:36:41 +0000 Subject: [PATCH 49/87] dt-bindings: phy: Document PCIe PHY in EcoNet EN751221 and EN7528 EN751221 and EN7528 SoCs have two PCIe slots, and each one has a PHY which behaves slightly differently because one slot is Gen1/Gen2 while the other is Gen1 only. Signed-off-by: Caleb James DeLisle Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260425173642.406089-2-cjd@cjdns.fr Signed-off-by: Vinod Koul --- .../phy/econet,en751221-pcie-phy.yaml | 50 +++++++++++++++++++ MAINTAINERS | 6 +++ 2 files changed, 56 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/econet,en751221-pcie-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/econet,en751221-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/econet,en751221-pcie-phy.yaml new file mode 100644 index 000000000000..987d396c1c64 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/econet,en751221-pcie-phy.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/econet,en751221-pcie-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: EcoNet PCI-Express PHY for EcoNet EN751221 and EN7528 + +maintainers: + - Caleb James DeLisle + +description: + The PCIe PHY supports physical layer functionality for PCIe Gen1 and + Gen1/Gen2 ports. On these SoCs, port 0 is a Gen1-only port while + port 1 is Gen1/Gen2 capable. + +properties: + compatible: + enum: + - econet,en751221-pcie-gen1 + - econet,en751221-pcie-gen2 + - econet,en7528-pcie-gen1 + - econet,en7528-pcie-gen2 + + reg: + maxItems: 1 + + "#phy-cells": + const: 0 + +required: + - compatible + - reg + - "#phy-cells" + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <1>; + #size-cells = <1>; + + pcie-phy@1faf2000 { + compatible = "econet,en7528-pcie-gen1"; + reg = <0x1faf2000 0x1000>; + #phy-cells = <0>; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 421dd786b399..e6e729b13de2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9153,6 +9153,12 @@ F: drivers/irqchip/irq-econet-en751221.c F: include/dt-bindings/clock/econet,en751221-scu.h F: include/dt-bindings/reset/econet,en751221-scu.h +ECONET PCIE PHY DRIVER +M: Caleb James DeLisle +L: linux-mips@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/phy/econet,en751221-pcie-phy.yaml + ECRYPT FILE SYSTEM M: Tyler Hicks L: ecryptfs@vger.kernel.org From da1af49257591190ad6521abb3198f1f40420407 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Sat, 25 Apr 2026 17:36:42 +0000 Subject: [PATCH 50/87] phy: econet: Add PCIe PHY driver for EcoNet EN751221 and EN7528 SoCs. Introduce support for EcoNet PCIe PHY controllers found in EN751221 and EN7528 SoCs, these SoCs are not identical but are similar, each having one Gen1 port, and one Gen1/Gen2 port. Co-developed-by: Ahmed Naseef Signed-off-by: Ahmed Naseef [cjd@cjdns.fr: add EN751221 support and refactor for clarity] Signed-off-by: Caleb James DeLisle Link: https://patch.msgid.link/20260425173642.406089-3-cjd@cjdns.fr Signed-off-by: Vinod Koul --- MAINTAINERS | 1 + drivers/phy/Kconfig | 12 +++ drivers/phy/Makefile | 1 + drivers/phy/phy-econet-pcie.c | 182 ++++++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+) create mode 100644 drivers/phy/phy-econet-pcie.c diff --git a/MAINTAINERS b/MAINTAINERS index e6e729b13de2..8ae7578a0532 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9158,6 +9158,7 @@ M: Caleb James DeLisle L: linux-mips@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/phy/econet,en751221-pcie-phy.yaml +F: drivers/phy/phy-econet-pcie.c ECRYPT FILE SYSTEM M: Tyler Hicks diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index ab96ee5858c1..7ef342f4bbb6 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -79,6 +79,18 @@ config PHY_EYEQ5_ETH shared register region called OLB. If M is selected, the module will be called phy-eyeq5-eth. +config PHY_ECONET_PCIE + tristate "EcoNet PCIe-PHY Driver" + depends on ECONET || COMPILE_TEST + depends on OF + select GENERIC_PHY + select REGMAP_MMIO + help + Say Y here to add support for EcoNet PCIe PHY driver. + This driver create the basic PHY instance and provides initialize + callback for PCIe GEN1 and GEN2 ports. This PHY is found on + EcoNet SoCs including EN751221 and EN7528. + config PHY_GOOGLE_USB tristate "Google Tensor SoC USB PHY driver" select GENERIC_PHY diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index f31767745123..1e69ed50fb17 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o +obj-$(CONFIG_PHY_ECONET_PCIE) += phy-econet-pcie.o obj-$(CONFIG_PHY_EYEQ5_ETH) += phy-eyeq5-eth.o obj-$(CONFIG_PHY_GOOGLE_USB) += phy-google-usb.o obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o diff --git a/drivers/phy/phy-econet-pcie.c b/drivers/phy/phy-econet-pcie.c new file mode 100644 index 000000000000..96be69d1ffeb --- /dev/null +++ b/drivers/phy/phy-econet-pcie.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Author: Caleb James DeLisle + * Ahmed Naseef + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Rx detection timing for EN751221: 16*8 clock cycles */ +#define EN751221_RXDET_VAL 16 + +/* Rx detection timing when in power mode 3 */ +#define EN75_RXDET_P3_REG 0xa28 +#define EN75_RXDET_P3_MASK GENMASK(17, 9) + +/* Rx detection timing when in power mode 2 */ +#define EN75_RXDET_P2_REG 0xa2c +#define EN75_RXDET_P2_MASK GENMASK(8, 0) + +/* Rx impedance */ +#define EN75_RX_IMPEDANCE_REG 0xb2c +#define EN75_RX_IMPEDANCE_MASK GENMASK(13, 12) +enum en75_rx_impedance { + EN75_RX_IMPEDANCE_100_OHM = 0, + EN75_RX_IMPEDANCE_95_OHM = 1, + EN75_RX_IMPEDANCE_90_OHM = 2, +}; + +/* PLL Invert clock */ +#define EN75_PLL_PH_INV_REG 0x4a0 +#define EN75_PLL_PH_INV_MASK BIT(5) + +struct en75_phy_op { + u32 reg; + u32 mask; + u32 val; +}; + +struct en7528_pcie_phy { + struct regmap *regmap; + const struct en75_phy_op *data; +}; + +/* Port 0 PHY: set LCDDS_CLK_PH_INV for PLL operation */ +static const struct en75_phy_op en7528_phy_gen1[] = { + { + .reg = EN75_PLL_PH_INV_REG, + .mask = EN75_PLL_PH_INV_MASK, + .val = 1, + }, + { /* sentinel */ } +}; + +/* EN7528 Port 1 PHY: Rx impedance tuning, target R -5 Ohm */ +static const struct en75_phy_op en7528_phy_gen2[] = { + { + .reg = EN75_RX_IMPEDANCE_REG, + .mask = EN75_RX_IMPEDANCE_MASK, + .val = EN75_RX_IMPEDANCE_95_OHM, + }, + { /* sentinel */ } +}; + +/* EN751221 Port 1 PHY, set RX detect to 16*8 clock cycles */ +static const struct en75_phy_op en751221_phy_gen2[] = { + { + .reg = EN75_RXDET_P3_REG, + .mask = EN75_RXDET_P3_MASK, + .val = EN751221_RXDET_VAL, + }, + { + .reg = EN75_RXDET_P2_REG, + .mask = EN75_RXDET_P2_MASK, + .val = EN751221_RXDET_VAL, + }, + { /* sentinel */ } +}; + +static int en75_pcie_phy_init(struct phy *phy) +{ + struct en7528_pcie_phy *ephy = phy_get_drvdata(phy); + const struct en75_phy_op *data = ephy->data; + int i, ret; + u32 val; + + for (i = 0; data[i].mask || data[i].val; i++) { + if (i) + usleep_range(1000, 2000); + + val = field_prep(data[i].mask, data[i].val); + + ret = regmap_update_bits(ephy->regmap, data[i].reg, + data[i].mask, val); + if (ret) + return ret; + } + + return 0; +} + +static const struct phy_ops en75_pcie_phy_ops = { + .init = en75_pcie_phy_init, + .owner = THIS_MODULE, +}; + +static int en75_pcie_phy_probe(struct platform_device *pdev) +{ + struct regmap_config regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + }; + struct device *dev = &pdev->dev; + const struct en75_phy_op *data; + struct phy_provider *provider; + struct en7528_pcie_phy *ephy; + void __iomem *base; + struct phy *phy; + int i; + + data = of_device_get_match_data(dev); + if (!data) + return -EINVAL; + + ephy = devm_kzalloc(dev, sizeof(*ephy), GFP_KERNEL); + if (!ephy) + return -ENOMEM; + + ephy->data = data; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + /* Set max_register to highest used register */ + for (i = 0; data[i].mask || data[i].val; i++) + if (data[i].reg > regmap_config.max_register) + regmap_config.max_register = data[i].reg; + + ephy->regmap = devm_regmap_init_mmio(dev, base, ®map_config); + if (IS_ERR(ephy->regmap)) + return PTR_ERR(ephy->regmap); + + phy = devm_phy_create(dev, dev->of_node, &en75_pcie_phy_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + phy_set_drvdata(phy, ephy); + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static const struct of_device_id en75_pcie_phy_ids[] = { + { .compatible = "econet,en7528-pcie-gen1", .data = en7528_phy_gen1 }, + { .compatible = "econet,en7528-pcie-gen2", .data = en7528_phy_gen2 }, + { .compatible = "econet,en751221-pcie-gen1", .data = en7528_phy_gen1 }, + { .compatible = "econet,en751221-pcie-gen2", .data = en751221_phy_gen2 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, en75_pcie_phy_ids); + +static struct platform_driver en75_pcie_phy_driver = { + .probe = en75_pcie_phy_probe, + .driver = { + .name = "econet-pcie-phy", + .of_match_table = en75_pcie_phy_ids, + }, +}; +module_platform_driver(en75_pcie_phy_driver); + +MODULE_AUTHOR("Caleb James DeLisle "); +MODULE_DESCRIPTION("EcoNet PCIe PHY driver"); +MODULE_LICENSE("GPL"); From deb281cec3cbef5f02c6bc29fa5cd51f6d5be10f Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 15 Mar 2026 14:49:30 -0700 Subject: [PATCH 51/87] phy: qcom-usb-hs: use flexible array member Simplify allocation by removing kmalloc_array and just doing kzalloc. Signed-off-by: Rosen Penev Link: https://patch.msgid.link/20260315214930.4621-1-rosenp@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-usb-hs.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs.c b/drivers/phy/qualcomm/phy-qcom-usb-hs.c index 98a18987f1be..928a982a8a76 100644 --- a/drivers/phy/qualcomm/phy-qcom-usb-hs.c +++ b/drivers/phy/qualcomm/phy-qcom-usb-hs.c @@ -34,9 +34,9 @@ struct qcom_usb_hs_phy { struct regulator *v1p8; struct regulator *v3p3; struct reset_control *reset; - struct ulpi_seq *init_seq; struct extcon_dev *vbus_edev; struct notifier_block vbus_notify; + struct ulpi_seq init_seq[]; }; static int qcom_usb_hs_phy_set_mode(struct phy *phy, @@ -209,19 +209,16 @@ static int qcom_usb_hs_phy_probe(struct ulpi *ulpi) int size; int ret; - uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL); + size = of_property_count_u8_elems(ulpi->dev.of_node, "qcom,init-seq"); + if (size < 0) + size = 0; + + uphy = devm_kzalloc(&ulpi->dev, struct_size(uphy, init_seq, (size / 2) + 1), GFP_KERNEL); if (!uphy) return -ENOMEM; ulpi_set_drvdata(ulpi, uphy); uphy->ulpi = ulpi; - size = of_property_count_u8_elems(ulpi->dev.of_node, "qcom,init-seq"); - if (size < 0) - size = 0; - uphy->init_seq = devm_kmalloc_array(&ulpi->dev, (size / 2) + 1, - sizeof(*uphy->init_seq), GFP_KERNEL); - if (!uphy->init_seq) - return -ENOMEM; ret = of_property_read_u8_array(ulpi->dev.of_node, "qcom,init-seq", (u8 *)uphy->init_seq, size); if (ret && size) From fd6cd05ceabdf67635a4cef5145f79d1217bf11b Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 3 Mar 2026 20:34:20 -0800 Subject: [PATCH 52/87] phy: mediatek: xsphy: reduce main allocation Instead of kzalloc and kcalloc, we can use a flex array to reduce to a single allocation. Also added __counted_by() for extra possible analysis. Signed-off-by: Rosen Penev Reviewed-by: Gustavo A. R. Silva Link: https://patch.msgid.link/20260304043420.14151-1-rosenp@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-xsphy.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/phy/mediatek/phy-mtk-xsphy.c b/drivers/phy/mediatek/phy-mtk-xsphy.c index c0ddb9273cc3..cc1d66954212 100644 --- a/drivers/phy/mediatek/phy-mtk-xsphy.c +++ b/drivers/phy/mediatek/phy-mtk-xsphy.c @@ -112,10 +112,10 @@ struct xsphy_instance { struct mtk_xsphy { struct device *dev; void __iomem *glb_base; /* only shared u3 sif */ - struct xsphy_instance **phys; - int nphys; int src_ref_clk; /* MHZ, reference clock for slew rate calibrate */ int src_coef; /* coefficient for slew rate calibrate */ + int nphys; + struct xsphy_instance *phys[] __counted_by(nphys); }; static void u2_phy_slew_rate_calibrate(struct mtk_xsphy *xsphy, @@ -515,18 +515,15 @@ static int mtk_xsphy_probe(struct platform_device *pdev) struct resource *glb_res; struct mtk_xsphy *xsphy; struct resource res; + size_t nphys; int port; - xsphy = devm_kzalloc(dev, sizeof(*xsphy), GFP_KERNEL); + nphys = of_get_child_count(np); + xsphy = devm_kzalloc(dev, struct_size(xsphy, phys, nphys), GFP_KERNEL); if (!xsphy) return -ENOMEM; - xsphy->nphys = of_get_child_count(np); - xsphy->phys = devm_kcalloc(dev, xsphy->nphys, - sizeof(*xsphy->phys), GFP_KERNEL); - if (!xsphy->phys) - return -ENOMEM; - + xsphy->nphys = nphys; xsphy->dev = dev; platform_set_drvdata(pdev, xsphy); From f546912bcac6463a22c5825e27a7952f8b48c887 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Wed, 4 Mar 2026 16:06:23 -0300 Subject: [PATCH 53/87] phy: qcom: qmp-combo: Move pipe_clk on/off to common Keep the USB pipe clock working when the phy is in DP-only mode, because the dwc controller still needs it for USB 2.0 over the same Type-C port. Tested with the BenQ RD280UA monitor which has a downstream-facing port for data passthrough that's manually switchable between USB 2 and 3, corresponding to 4-lane and 2-lane DP respectively. Note: the suspend/resume callbacks were already gating the enable/disable of this clock only on init_count and not usb_init_count! Reviewed-by: Neil Armstrong Reviewed-by: Konrad Dybcio Signed-off-by: Val Packett Link: https://patch.msgid.link/20260304190827.176988-1-val@packett.cool Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 93f1aa10d400..cdcfad2e86b1 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -3691,6 +3691,13 @@ static int qmp_combo_com_init(struct qmp_combo *qmp, bool force) if (ret) goto err_assert_reset; + /* In DP-only mode, the pipe clk is still required for USB2 */ + ret = clk_prepare_enable(qmp->pipe_clk); + if (ret) { + dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret); + goto err_disable_clocks; + } + qphy_setbits(com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, SW_PWRDN); /* override hardware control for reset of qmp phy */ @@ -3749,6 +3756,8 @@ static int qmp_combo_com_init(struct qmp_combo *qmp, bool force) return 0; +err_disable_clocks: + clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); err_assert_reset: reset_control_bulk_assert(cfg->num_resets, qmp->resets); err_disable_regulators: @@ -3768,6 +3777,7 @@ static int qmp_combo_com_exit(struct qmp_combo *qmp, bool force) reset_control_bulk_assert(cfg->num_resets, qmp->resets); + clk_disable_unprepare(qmp->pipe_clk); clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); regulator_bulk_disable(cfg->num_vregs, qmp->vregs); @@ -3871,12 +3881,6 @@ static int qmp_combo_usb_power_on(struct phy *phy) qmp_configure(qmp->dev, serdes, cfg->serdes_tbl, cfg->serdes_tbl_num); - ret = clk_prepare_enable(qmp->pipe_clk); - if (ret) { - dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret); - return ret; - } - /* Tx, Rx, and PCS configurations */ qmp_configure_lane(qmp->dev, tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); qmp_configure_lane(qmp->dev, tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); @@ -3922,8 +3926,6 @@ static int qmp_combo_usb_power_off(struct phy *phy) struct qmp_combo *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; - clk_disable_unprepare(qmp->pipe_clk); - /* PHY reset */ qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); From 0b31f297557fff0941769e8257198151a0fbe8bf Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 27 Apr 2026 08:57:13 +0800 Subject: [PATCH 54/87] phy: rockchip: naneng-combphy: Consolidate SSC configuration The PCIe SSC configuration for the RK3588 and RK3576 SoCs required additional tuning which is missing. When adding these same SSC configurations for both of these two SoCs, as well as upcoming platforms, it's obvious the SSC setup code was largely duplicated across the platform-specific configuration functions. This becomes harder to maintain as more platforms are added. So extract the common SSC logic into a shared helper function, rk_combphy_common_cfg_ssc(). This cleans up the per-platform drivers and centralizes the standard configuration as possible. Reviewed-by: Neil Armstrong Reviewed-by: Heiko Stuebner Signed-off-by: Shawn Lin Link: https://patch.msgid.link/1777251433-110466-1-git-send-email-shawn.lin@rock-chips.com Signed-off-by: Vinod Koul --- .../rockchip/phy-rockchip-naneng-combphy.c | 173 ++++++++---------- 1 file changed, 73 insertions(+), 100 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index b60d6bf3f33c..2b0f152f5470 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -121,6 +121,7 @@ #define RK3568_PHYREG32_SSC_OFFSET_500PPM 1 #define RK3568_PHYREG33 0x80 +#define RK3568_PHYREG33_PLL_SSC_CTRL BIT(5) #define RK3568_PHYREG33_PLL_KVCO_MASK GENMASK(4, 2) #define RK3568_PHYREG33_PLL_KVCO_SHIFT 2 #define RK3568_PHYREG33_PLL_KVCO_VALUE 2 @@ -446,6 +447,74 @@ static int rockchip_combphy_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(phy_provider); } +static void rk_combphy_common_cfg_ssc(struct rockchip_combphy_priv *priv, unsigned long rate) +{ + struct device_node *np = priv->dev->of_node; + u32 val; + + if (!priv->enable_ssc) + return; + + /* Set SSC downward spread spectrum for PCIe and USB3 */ + if (priv->type == PHY_TYPE_PCIE || priv->type == PHY_TYPE_USB3) { + val = FIELD_PREP(RK3568_PHYREG32_SSC_MASK, RK3568_PHYREG32_SSC_DOWNWARD); + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, RK3568_PHYREG32); + } + + /* Set SSC downward spread spectrum +500ppm for SATA in 100MHz */ + if (priv->type == PHY_TYPE_SATA && rate == REF_CLOCK_100MHz) { + 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); + } + + /* Enable SSC */ + val = readl(priv->mmio + RK3568_PHYREG8); + val |= RK3568_PHYREG8_SSC_EN; + writel(val, priv->mmio + RK3568_PHYREG8); + + /* Some SoCs need tuning PCIe SSC instead of default configuration in 24MHz */ + if (!of_device_is_compatible(np, "rockchip,rk3588-naneng-combphy") && + !of_device_is_compatible(np, "rockchip,rk3576-naneng-combphy")) + return; + + /* PLL control SSC module period should be set if need tuning */ + val = readl(priv->mmio + RK3568_PHYREG33); + val |= RK3568_PHYREG33_PLL_SSC_CTRL; + writel(val, priv->mmio + RK3568_PHYREG33); + + if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_24MHz) { + /* Set PLL loop divider */ + 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 + RK3588_PHYREG27); + + /* + * Set up SU adjust signal: + * su_trim[7:0], PLL KVCO adjust bits[2:0] to min + * su_trim[15:8], PLL LPF R1 adujst bits[9:7]=3'b101 + * su_trim[23:16], CKRCV adjust + * su_trim[31:24], CKDRV adjust + */ + 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(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); + + val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, + RK3576_PHYREG33_PLL_KVCO_VALUE); + writel(val, priv->mmio + RK3568_PHYREG33); + } +} + static int rk3528_combphy_cfg(struct rockchip_combphy_priv *priv) { const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg; @@ -600,21 +669,12 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) switch (priv->type) { case PHY_TYPE_PCIE: - /* Set SSC downward spread spectrum */ - 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); 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: - /* Set SSC downward spread spectrum */ - 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, RK3568_PHYREG15_CTLE_EN, RK3568_PHYREG15_CTLE_EN, RK3568_PHYREG15); @@ -706,11 +766,7 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) } } - if (priv->enable_ssc) { - val = readl(priv->mmio + RK3568_PHYREG8); - val |= RK3568_PHYREG8_SSC_EN; - writel(val, priv->mmio + RK3568_PHYREG8); - } + rk_combphy_common_cfg_ssc(priv, rate); return 0; } @@ -755,11 +811,6 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) switch (priv->type) { case PHY_TYPE_PCIE: - /* Set SSC downward spread spectrum. */ - 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); rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_pcie, true); @@ -767,10 +818,6 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) break; case PHY_TYPE_USB3: - /* Set SSC downward spread spectrum. */ - 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 + RK3568_PHYREG15); val |= RK3568_PHYREG15_CTLE_EN; @@ -880,13 +927,6 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) 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 = 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; @@ -909,11 +949,7 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) } } - if (priv->enable_ssc) { - val = readl(priv->mmio + RK3568_PHYREG8); - val |= RK3568_PHYREG8_SSC_EN; - writel(val, priv->mmio + RK3568_PHYREG8); - } + rk_combphy_common_cfg_ssc(priv, rate); return 0; } @@ -972,10 +1008,6 @@ 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(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); rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_pcie, true); @@ -983,10 +1015,6 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) break; case PHY_TYPE_USB3: - /* Set SSC downward spread spectrum */ - 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 + RK3568_PHYREG15); val |= RK3568_PHYREG15_CTLE_EN; @@ -1110,14 +1138,6 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) 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(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, RK3576_PHYREG10_SSC_PCM_MASK, RK3576_PHYREG10_SSC_PCM_3500PPM, @@ -1156,39 +1176,7 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) } } - if (priv->enable_ssc) { - 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 + 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 + RK3588_PHYREG27); - - /* - * Set up SU adjust signal: - * su_trim[7:0], PLL KVCO adjust bits[2:0] to min - * su_trim[15:8], PLL LPF R1 adujst bits[9:7]=3'b101 - * su_trim[23:16], CKRCV adjust - * su_trim[31:24], CKDRV adjust - */ - 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(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); - - val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, - RK3576_PHYREG33_PLL_KVCO_VALUE); - writel(val, priv->mmio + RK3568_PHYREG33); - } - } + rk_combphy_common_cfg_ssc(priv, rate); return 0; } @@ -1255,10 +1243,6 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) } break; case PHY_TYPE_USB3: - /* Set SSC downward spread spectrum */ - 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 + RK3568_PHYREG15); val |= RK3568_PHYREG15_CTLE_EN; @@ -1343,13 +1327,6 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) /* Set up su_trim: */ writel(RK3568_PHYREG11_SU_TRIM_0_7, priv->mmio + RK3568_PHYREG11); - } else if (priv->type == PHY_TYPE_SATA) { - /* downward spread spectrum +500ppm */ - 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: @@ -1371,11 +1348,7 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) } } - if (priv->enable_ssc) { - val = readl(priv->mmio + RK3568_PHYREG8); - val |= RK3568_PHYREG8_SSC_EN; - writel(val, priv->mmio + RK3568_PHYREG8); - } + rk_combphy_common_cfg_ssc(priv, rate); return 0; } From a62d9440ebbce3d9f0bd6c346a7fda2a53726850 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 18 May 2026 17:20:24 +0300 Subject: [PATCH 55/87] dt-bindings: phy: add PHY bindings for the TI DS125DF111 Retimer PHY Add device tree binding for the TI DS125DF111 Retimer PHY. Signed-off-by: Ioana Ciornei Acked-by: Conor Dooley Link: https://patch.msgid.link/20260518142026.3098496-2-ioana.ciornei@nxp.com Signed-off-by: Vinod Koul --- .../bindings/phy/ti,ds125df111.yaml | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/ti,ds125df111.yaml diff --git a/Documentation/devicetree/bindings/phy/ti,ds125df111.yaml b/Documentation/devicetree/bindings/phy/ti,ds125df111.yaml new file mode 100644 index 000000000000..ca4605f1d664 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/ti,ds125df111.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/ti,ds125df111.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI DS125DF111 Retimer PHY + +description: + This binding describes the TI DS125DF111 multi-protocol Retimer PHY. + +maintainers: + - Ioana Ciornei + +properties: + compatible: + const: ti,ds125df111 + + reg: + maxItems: 1 + + "#phy-cells": + const: 1 + description: | + The phandle's argument in the PHY specifier selects one of the two + channels of the retimer + +required: + - compatible + - reg + - "#phy-cells" + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + phy@18 { + compatible = "ti,ds125df111"; + reg = <0x18>; + #phy-cells = <1>; + }; + }; From 711f64979e500799b27b33a8f030e2fd939fd07f Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 18 May 2026 17:20:25 +0300 Subject: [PATCH 56/87] phy: ti: alphabetically sort Kconfig and Makefile Sort alphabetically the entries in the Kconfig and Makefile files. Signed-off-by: Ioana Ciornei Link: https://patch.msgid.link/20260518142026.3098496-3-ioana.ciornei@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/ti/Kconfig | 124 ++++++++++++++++++++-------------------- drivers/phy/ti/Makefile | 12 ++-- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig index b40f28019131..dbe65500f20c 100644 --- a/drivers/phy/ti/Kconfig +++ b/drivers/phy/ti/Kconfig @@ -2,53 +2,6 @@ # # Phy drivers for TI platforms # -config PHY_DA8XX_USB - tristate "TI DA8xx USB PHY Driver" - depends on ARCH_DAVINCI_DA8XX || COMPILE_TEST - select GENERIC_PHY - select MFD_SYSCON - help - Enable this to support the USB PHY on DA8xx SoCs. - - This driver controls both the USB 1.1 PHY and the USB 2.0 PHY. - -config PHY_DM816X_USB - tristate "TI dm816x USB PHY driver" - depends on ARCH_OMAP2PLUS || COMPILE_TEST - depends on USB_SUPPORT - select GENERIC_PHY - select USB_PHY - help - Enable this for dm816x USB to work. - -config PHY_AM654_SERDES - tristate "TI AM654 SERDES support" - depends on OF && (ARCH_K3 || COMPILE_TEST) - depends on COMMON_CLK - select GENERIC_PHY - select MULTIPLEXER - select REGMAP_MMIO - select MUX_MMIO - help - This option enables support for TI AM654 SerDes PHY used for - PCIe. - -config PHY_J721E_WIZ - tristate "TI J721E WIZ (SERDES Wrapper) support" - depends on OF && (ARCH_K3 || COMPILE_TEST) - depends on HAS_IOMEM && OF_ADDRESS - depends on COMMON_CLK - select GENERIC_PHY - select MULTIPLEXER - select REGMAP_MMIO - select MUX_MMIO - help - This option enables support for WIZ module present in TI's J721E - SoC. WIZ is a serdes wrapper used to configure some of the input - signals to the SERDES (Sierra/Torrent). This driver configures - three clock selects (pll0, pll1, dig) and resets for each of the - lanes. - config OMAP_CONTROL_PHY tristate "OMAP CONTROL PHY Driver" depends on ARCH_OMAP2PLUS || COMPILE_TEST @@ -73,6 +26,68 @@ config OMAP_USB2 The USB OTG controller communicates with the comparator using this driver. +config PHY_AM654_SERDES + tristate "TI AM654 SERDES support" + depends on OF && (ARCH_K3 || COMPILE_TEST) + depends on COMMON_CLK + select GENERIC_PHY + select MULTIPLEXER + select REGMAP_MMIO + select MUX_MMIO + help + This option enables support for TI AM654 SerDes PHY used for + PCIe. + +config PHY_DA8XX_USB + tristate "TI DA8xx USB PHY Driver" + depends on ARCH_DAVINCI_DA8XX || COMPILE_TEST + select GENERIC_PHY + select MFD_SYSCON + help + Enable this to support the USB PHY on DA8xx SoCs. + + This driver controls both the USB 1.1 PHY and the USB 2.0 PHY. + +config PHY_DM816X_USB + tristate "TI dm816x USB PHY driver" + depends on ARCH_OMAP2PLUS || COMPILE_TEST + depends on USB_SUPPORT + select GENERIC_PHY + select USB_PHY + help + Enable this for dm816x USB to work. + +config PHY_J721E_WIZ + tristate "TI J721E WIZ (SERDES Wrapper) support" + depends on OF && (ARCH_K3 || COMPILE_TEST) + depends on HAS_IOMEM && OF_ADDRESS + depends on COMMON_CLK + select GENERIC_PHY + select MULTIPLEXER + select REGMAP_MMIO + select MUX_MMIO + help + This option enables support for WIZ module present in TI's J721E + SoC. WIZ is a serdes wrapper used to configure some of the input + signals to the SERDES (Sierra/Torrent). This driver configures + three clock selects (pll0, pll1, dig) and resets for each of the + lanes. + +config PHY_TI_GMII_SEL + tristate + select GENERIC_PHY + select REGMAP + help + This driver supports configuring of the TI CPSW Port mode depending on + the Ethernet PHY connected to the CPSW Port. + +config PHY_TUSB1210 + tristate "TI TUSB1210 ULPI PHY module" + depends on USB_ULPI_BUS + select GENERIC_PHY + help + Support for TI TUSB1210 USB ULPI PHY. + config TI_PIPE3 tristate "TI PIPE3 PHY Driver" depends on ARCH_OMAP2PLUS || COMPILE_TEST @@ -84,13 +99,6 @@ config TI_PIPE3 This driver interacts with the "OMAP Control PHY Driver" to power on/off the PHY. -config PHY_TUSB1210 - tristate "TI TUSB1210 ULPI PHY module" - depends on USB_ULPI_BUS - select GENERIC_PHY - help - Support for TI TUSB1210 USB ULPI PHY. - config TWL4030_USB tristate "TWL4030 USB Transceiver Driver" depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS @@ -103,11 +111,3 @@ config TWL4030_USB family chips (including the TWL5030 and TPS659x0 devices). This transceiver supports high and full speed devices plus, in host mode, low speed. - -config PHY_TI_GMII_SEL - tristate - select GENERIC_PHY - select REGMAP - help - This driver supports configuring of the TI CPSW Port mode depending on - the Ethernet PHY connected to the CPSW Port. diff --git a/drivers/phy/ti/Makefile b/drivers/phy/ti/Makefile index dcba2571c9bd..975fb8448ba5 100644 --- a/drivers/phy/ti/Makefile +++ b/drivers/phy/ti/Makefile @@ -1,11 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o -obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o -obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o -obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o -obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o obj-$(CONFIG_PHY_AM654_SERDES) += phy-am654-serdes.o -obj-$(CONFIG_PHY_TI_GMII_SEL) += phy-gmii-sel.o +obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o +obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o obj-$(CONFIG_PHY_J721E_WIZ) += phy-j721e-wiz.o +obj-$(CONFIG_PHY_TI_GMII_SEL) += phy-gmii-sel.o +obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o +obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o +obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o From 9bf5c16a6e63ebf2803deb32ba984a7fcf2c5ed7 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 18 May 2026 17:20:26 +0300 Subject: [PATCH 57/87] phy: ti: add PHY driver for TI DS125DF111 Dual-Channel Retimer Add a generic PHY driver for the TI DS125DF111 Multi-Protocol Dual-Channel Retimer. The driver currently supports only 10G and 1G link speeds but it can easily extended to also cover other usecases. Since the available datasheet (https://www.ti.com/lit/gpn/DS125DF111) does not name the registers, the name for the macros were determined by their usage pattern. A PHY device is created for each of the two channels present on the retimer. This allows for independent configuration of the two channels. This capability is especially important on retimers which have more than 2 channels that can be, depending on the board design, connected in multiple different ways to the SerDes lanes. Signed-off-by: Ioana Ciornei Reviewed-by: Vladimir Oltean Link: https://patch.msgid.link/20260518142026.3098496-4-ioana.ciornei@nxp.com Signed-off-by: Vinod Koul --- MAINTAINERS | 7 + drivers/phy/ti/Kconfig | 10 ++ drivers/phy/ti/Makefile | 1 + drivers/phy/ti/phy-ds125df111.c | 294 ++++++++++++++++++++++++++++++++ 4 files changed, 312 insertions(+) create mode 100644 drivers/phy/ti/phy-ds125df111.c diff --git a/MAINTAINERS b/MAINTAINERS index 8ae7578a0532..e00b43bd3444 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26684,6 +26684,13 @@ T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git F: drivers/media/platform/ti/davinci/ F: include/media/davinci/ +TI DS125DF111 RETIMER PHY DRIVER +M: Ioana Ciornei +L: linux-phy@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/phy/ti,ds125df111.yaml +F: drivers/phy/ti/phy-ds125df111.c + TI ENHANCED CAPTURE (eCAP) DRIVER M: Vignesh Raghavendra R: Julien Panis diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig index dbe65500f20c..b52c7eabe24c 100644 --- a/drivers/phy/ti/Kconfig +++ b/drivers/phy/ti/Kconfig @@ -73,6 +73,16 @@ config PHY_J721E_WIZ three clock selects (pll0, pll1, dig) and resets for each of the lanes. +config PHY_TI_DS125DF111 + tristate "TI DS125DF111 2-Channel Retimer Driver" + depends on OF && I2C + select GENERIC_PHY + help + Enable this to add support for configuration and runtime management + of the TI DS125DF111 Multi-Protocol 2-Channel Retimer. + The retimer is modeled as a Generic PHY and supports both 10G and 1G + link speeds. + config PHY_TI_GMII_SEL tristate select GENERIC_PHY diff --git a/drivers/phy/ti/Makefile b/drivers/phy/ti/Makefile index 975fb8448ba5..a002ef8764a2 100644 --- a/drivers/phy/ti/Makefile +++ b/drivers/phy/ti/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PHY_AM654_SERDES) += phy-am654-serdes.o obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o obj-$(CONFIG_PHY_J721E_WIZ) += phy-j721e-wiz.o +obj-$(CONFIG_PHY_TI_DS125DF111) += phy-ds125df111.o obj-$(CONFIG_PHY_TI_GMII_SEL) += phy-gmii-sel.o obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o diff --git a/drivers/phy/ti/phy-ds125df111.c b/drivers/phy/ti/phy-ds125df111.c new file mode 100644 index 000000000000..84ff96d7d589 --- /dev/null +++ b/drivers/phy/ti/phy-ds125df111.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright 2026 NXP */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DS125DF111_NUM_CH 2 +#define DS125DF111_NUM_VCO_GROUP_REG 5 + +#define DS125DF111_CH_SELECT 0xff +#define DS125DF111_CH_SELECT_TARGET_MASK GENMASK(3, 0) +#define DS125DF111_CH_SELECT_EN BIT(2) + +#define DS125DF111_CH_CTRL 0x00 +#define DS125DF111_CH_CTRL_RESET BIT(2) /* self clearing */ + +#define DS125DF111_CH_RST_SLEEP_US 10 +#define DS125DF111_CH_RST_TIMEOUT_US 10000 + +#define DS125DF111_VCO_GROUP_BASE 0x60 + +#define DS125DF111_RATIOS 0x2f +#define DS125DF111_RATIOS_RATE_MASK GENMASK(7, 6) +#define DS125DF111_RATIOS_SUBRATE_MASK GENMASK(5, 4) +#define DS125DF111_RATIOS_MASK GENMASK(7, 4) + +struct ds125df111_ch { + struct phy *phy; + struct ds125df111_priv *priv; + int idx; +}; + +struct ds125df111_priv { + struct ds125df111_ch ch[DS125DF111_NUM_CH]; + struct i2c_client *client; + struct mutex mutex; /* protects access to shared registers */ +}; + +enum ds125df111_mode { + FREQ_1G, + FREQ_10G, +}; + +static const struct ds125df111_config { + u8 vco_group[DS125DF111_NUM_VCO_GROUP_REG]; + u8 rate; + u8 subrate; +} ds125df111_cfg[] = { + [FREQ_1G] = { + /* VCO group #0 = 10GHz, VCO group #1 = 10GHz */ + .vco_group = {0x00, 0xB2, 0x00, 0xB2, 0xCC}, + /* By using the following combination of rate and subrate we + * select divide ratios of 1, 2, 4, 8 on both groups + */ + .rate = 0x1, + .subrate = 0x2, + }, + + [FREQ_10G] = { + /* VCO group #0 = 10.3125GHz, VCO group #1 = 10.3125GHz */ + .vco_group = {0x90, 0xB3, 0x90, 0xB3, 0xCD}, + /* By using the following combination of rate and subrate we + * select divide ratios of 1 on both groups + */ + .rate = 0x1, + .subrate = 0x3, + }, +}; + +static int ds125df111_rmw(struct ds125df111_priv *priv, u8 reg, u8 clr, u8 set) +{ + struct i2c_client *i2c = priv->client; + int err; + u8 val; + + err = i2c_smbus_read_byte_data(i2c, reg); + if (err < 0) + return err; + + val = (u8)err; + val &= ~clr; + val |= set; + + err = i2c_smbus_write_byte_data(i2c, reg, val); + if (err < 0) + return err; + + return 0; +} + +static int ds125df111_configure(struct phy *phy, + const struct ds125df111_config *cfg) +{ + struct ds125df111_ch *ch = phy_get_drvdata(phy); + struct ds125df111_priv *priv = ch->priv; + struct i2c_client *i2c = priv->client; + struct device *dev = &phy->dev; + u8 ratios_val; + int err, i; + int val; + + mutex_lock(&priv->mutex); + + /* Make sure that any subsequent read/write operation will be directed + * only to the registers of the selected channel + */ + err = ds125df111_rmw(priv, DS125DF111_CH_SELECT, + DS125DF111_CH_SELECT_TARGET_MASK, + DS125DF111_CH_SELECT_EN | ch->idx); + if (err < 0) { + dev_err(dev, "Unable to select channel: %pe\n", ERR_PTR(err)); + goto out; + } + + /* Reset channel registers and wait until the bit was cleared */ + err = ds125df111_rmw(priv, DS125DF111_CH_CTRL, 0, + DS125DF111_CH_CTRL_RESET); + if (err < 0) { + dev_err(dev, "Error resetting channel configuration: %pe\n", + ERR_PTR(err)); + goto out; + } + + err = read_poll_timeout(i2c_smbus_read_byte_data, val, + val < 0 || !(val & DS125DF111_CH_CTRL_RESET), + DS125DF111_CH_RST_SLEEP_US, + DS125DF111_CH_RST_TIMEOUT_US, false, i2c, + DS125DF111_CH_CTRL); + if (err) { + dev_err(dev, "Timed out waiting for channel reset: %pe\n", + ERR_PTR(err)); + goto out; + } + + if (val < 0) { + dev_err(dev, "Error reading reset status: %pe\n", ERR_PTR(val)); + err = val; + goto out; + } + + /* Program the VCO group frequencies */ + for (i = 0; i < DS125DF111_NUM_VCO_GROUP_REG; i++) { + err = i2c_smbus_write_byte_data(i2c, + DS125DF111_VCO_GROUP_BASE + i, + cfg->vco_group[i]); + if (err < 0) { + dev_err(dev, "Error programming VCO group: %pe\n", + ERR_PTR(err)); + goto out; + } + } + + /* Set the divide ratios for the VCO groups */ + ratios_val = FIELD_PREP(DS125DF111_RATIOS_RATE_MASK, cfg->rate) | + FIELD_PREP(DS125DF111_RATIOS_SUBRATE_MASK, cfg->subrate); + err = ds125df111_rmw(priv, DS125DF111_RATIOS, DS125DF111_RATIOS_MASK, + ratios_val); + if (err < 0) { + dev_err(dev, "Error programming the divide ratios: %pe\n", + ERR_PTR(err)); + goto out; + } + +out: + mutex_unlock(&priv->mutex); + + return err; +} + +static int ds125df111_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + const struct ds125df111_config *cfg; + + if (mode != PHY_MODE_ETHERNET) + return -EINVAL; + + switch (submode) { + case PHY_INTERFACE_MODE_10GBASER: + cfg = &ds125df111_cfg[FREQ_10G]; + break; + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_SGMII: + cfg = &ds125df111_cfg[FREQ_1G]; + break; + default: + return -EINVAL; + } + + return ds125df111_configure(phy, cfg); +} + +static int ds125df111_validate(struct phy *phy, enum phy_mode mode, int submode, + union phy_configure_opts *opts __always_unused) +{ + if (mode != PHY_MODE_ETHERNET) + return -EINVAL; + + switch (submode) { + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_SGMII: + return 0; + default: + return -EINVAL; + } +} + +static const struct phy_ops ds125df111_ops = { + .validate = ds125df111_validate, + .set_mode = ds125df111_set_mode, + .owner = THIS_MODULE, +}; + +static struct phy *ds125df111_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct ds125df111_priv *priv = dev_get_drvdata(dev); + u32 idx; + + if (args->args_count != 1) + return ERR_PTR(-EINVAL); + + idx = args->args[0]; + if (idx >= DS125DF111_NUM_CH) { + dev_err(dev, "Maximum number of channels is %d\n", + DS125DF111_NUM_CH); + return ERR_PTR(-EINVAL); + } + + return priv->ch[idx].phy; +} + +static int ds125df111_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct phy_provider *provider; + struct ds125df111_priv *priv; + int i, err; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->client = client; + err = devm_mutex_init(dev, &priv->mutex); + if (err) + return err; + + i2c_set_clientdata(client, priv); + + for (i = 0; i < DS125DF111_NUM_CH; i++) { + struct ds125df111_ch *ch = &priv->ch[i]; + struct phy *phy; + + phy = devm_phy_create(dev, NULL, &ds125df111_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + ch->idx = i; + ch->priv = priv; + ch->phy = phy; + + phy_set_drvdata(phy, ch); + } + + provider = devm_of_phy_provider_register(dev, ds125df111_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static const struct of_device_id ds125df111_dt_ids[] = { + { .compatible = "ti,ds125df111", }, + {} +}; +MODULE_DEVICE_TABLE(of, ds125df111_dt_ids); + +static struct i2c_driver ds125df111_driver = { + .driver = { + .name = "ds125df111", + .of_match_table = ds125df111_dt_ids, + }, + .probe = ds125df111_probe, +}; +module_i2c_driver(ds125df111_driver); + +MODULE_AUTHOR("Ioana Ciornei "); +MODULE_DESCRIPTION("TI DS125DF111 Retimer driver"); +MODULE_LICENSE("GPL"); From 293e19f416fa3f233a2fb013258f7abcb39ad6ed Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 19 May 2026 10:22:53 +0200 Subject: [PATCH 58/87] MAINTAINERS: Hand over phy-zynqmp to Tomi Valkeinen I volunteered to maintain the phy-zynqmp driver as part of my work on the ZynqMP DPSUB driver. Now that Tomi has taken over the DPSUB, it makes sense for him to handle the phy-zynqmp driver as well. Signed-off-by: Laurent Pinchart Acked-by: Tomi Valkeinen Acked-by: Radhey Shyam Pandey Link: https://patch.msgid.link/20260519082253.40142-1-laurent.pinchart@ideasonboard.com Signed-off-by: Vinod Koul --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index e00b43bd3444..06563ce3f459 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -29278,7 +29278,7 @@ F: Documentation/devicetree/bindings/memory-controllers/xlnx,zynqmp-ocmc-1.0.yam F: drivers/edac/zynqmp_edac.c XILINX ZYNQMP PSGTR PHY DRIVER -M: Laurent Pinchart +M: Tomi Valkeinen L: linux-kernel@vger.kernel.org S: Supported T: git https://github.com/Xilinx/linux-xlnx.git From d24d7339757aa5f3397cfdbba931ac39dfd4ba5e Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Thu, 7 May 2026 15:14:39 +0200 Subject: [PATCH 59/87] phy: ti: tusb1210: Move long delayed work on system_dfl_long_wq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the code enqueue work items using {queue|mod}_delayed_work(), using system_long_wq. This workqueue should be used when long works are expected and it is a per-cpu workqueue. The function(s) end up calling __queue_delayed_work(), which set a global timer that could fire anywhere, enqueuing the work where the timer fired. Unbound works could benefit from scheduler task placement, to optimize performance and power consumption. Long work shouldn't stick to a single CPU. Recently, a new unbound workqueue specific for long running work has been added:     c116737e972e ("workqueue: Add system_dfl_long_wq for long unbound works") Since the workqueue work doesn't rely on per-cpu variables, there is no obvious reason that justify the use of a per-cpu workqueue. So change system_long_wq with system_dfl_long_wq so that the work may benefit from scheduler task placement. Signed-off-by: Marco Crivellari Link: https://patch.msgid.link/20260507131439.264906-1-marco.crivellari@suse.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-tusb1210.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c index c3ae9d7948d7..9956921c094b 100644 --- a/drivers/phy/ti/phy-tusb1210.c +++ b/drivers/phy/ti/phy-tusb1210.c @@ -197,7 +197,7 @@ static void tusb1210_chg_det_set_state(struct tusb1210 *tusb, tusb1210_chg_det_states[new_state], delay_ms); tusb->chg_det_state = new_state; - mod_delayed_work(system_long_wq, &tusb->chg_det_work, + mod_delayed_work(system_dfl_long_wq, &tusb->chg_det_work, msecs_to_jiffies(delay_ms)); } @@ -380,7 +380,7 @@ static int tusb1210_psy_notifier(struct notifier_block *nb, struct power_supply *psy = ptr; if (psy != tusb->psy && psy->desc->type == POWER_SUPPLY_TYPE_USB) - queue_delayed_work(system_long_wq, &tusb->chg_det_work, 0); + queue_delayed_work(system_dfl_long_wq, &tusb->chg_det_work, 0); return NOTIFY_OK; } @@ -458,7 +458,7 @@ static void tusb1210_probe_charger_detect(struct tusb1210 *tusb) */ tusb->chg_det_state = TUSB1210_CHG_DET_DISCONNECTED; INIT_DELAYED_WORK(&tusb->chg_det_work, tusb1210_chg_det_work); - queue_delayed_work(system_long_wq, &tusb->chg_det_work, 2 * HZ); + queue_delayed_work(system_dfl_long_wq, &tusb->chg_det_work, 2 * HZ); tusb->psy_nb.notifier_call = tusb1210_psy_notifier; power_supply_reg_notifier(&tusb->psy_nb); From b3ee497970c63cea37976aeaa84bac39611fe0eb Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 10 Jun 2026 11:45:12 +0200 Subject: [PATCH 60/87] dt-bindings: phy: sc8280xp-qmp-pcie: Disallow bifurcation register on Purwa Neither of the two Gen4x4 PHYs found on Purwa supports bifurcation. The PHY is however physically laid out as if it were to, since there are two separate ports (A/B). Split out a new if-then block to un-require the bifurcation register handle to squash this warning: purwa-iot-evk.dtb: phy@1bd4000 (qcom,x1p42100-qmp-gen4x4-pcie-phy): 'qcom,4ln-config-sel' is a required property Fixes: 2e1ffd4c1805 ("dt-bindings: phy: qcom,qmp-pcie: Add X1P42100 PCIe Gen4x4 PHY") Reported-by: Rob Herring Closes: https://lore.kernel.org/linux-arm-msm/176857775469.1631885.16133311938753588148.robh@kernel.org/ Signed-off-by: Konrad Dybcio Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260610-topic-purwa_phy_shutup_warning-v2-1-951c1fbfe9b2@oss.qualcomm.com Signed-off-by: Vinod Koul --- .../bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) 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 3a35120a77ec..431e8cb5df84 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -136,13 +136,22 @@ allOf: items: - description: port a - description: port b - required: - - qcom,4ln-config-sel else: properties: reg: maxItems: 1 + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8280xp-qmp-gen3x4-pcie-phy + - qcom,x1e80100-qmp-gen4x4-pcie-phy + then: + required: + - qcom,4ln-config-sel + - if: properties: compatible: From 4904117935319233b1ec8f0528560dc91e8ae4c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Tue, 19 May 2026 17:19:57 +0200 Subject: [PATCH 61/87] phy: nxp-ptn3222: Use named initializers for struct i2c_device_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While being less compact, using named initializers allows to more easily see which members of the structs are assigned which value without having to lookup the declaration of the struct. And it's also more robust against changes to the struct definition. This patch doesn't modify the compiled arrays, only their representation in source form benefits. The former was confirmed with x86 and arm64 builds. Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://patch.msgid.link/20260519151957.1593214-2-u.kleine-koenig@baylibre.com Signed-off-by: Vinod Koul --- drivers/phy/phy-nxp-ptn3222.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/phy-nxp-ptn3222.c b/drivers/phy/phy-nxp-ptn3222.c index c6179d8701e6..6cb79b5c4fdb 100644 --- a/drivers/phy/phy-nxp-ptn3222.c +++ b/drivers/phy/phy-nxp-ptn3222.c @@ -97,7 +97,7 @@ static int ptn3222_probe(struct i2c_client *client) } static const struct i2c_device_id ptn3222_table[] = { - { "ptn3222" }, + { .name = "ptn3222" }, { } }; MODULE_DEVICE_TABLE(i2c, ptn3222_table); From afdf104ec11681aacba0865863647f725f47ab90 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Mon, 8 Jun 2026 14:18:13 +0530 Subject: [PATCH 62/87] dt-bindings: phy: sc8280xp-qmp-pcie: Document Eliza PCIe phy Add compatibles for the Eliza PCIe QMP PHY's, which supports Gen3x1 and Gen3x2 configurations. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Krishna Chaitanya Chundru Acked-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20260608-eliza-v3-1-9bdeb7434b28@oss.qualcomm.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml | 6 ++++++ 1 file changed, 6 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 431e8cb5df84..108cf9dc86ea 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -16,6 +16,8 @@ description: properties: compatible: enum: + - qcom,eliza-qmp-gen3x1-pcie-phy + - qcom,eliza-qmp-gen3x2-pcie-phy - qcom,glymur-qmp-gen4x2-pcie-phy - qcom,glymur-qmp-gen5x4-pcie-phy - qcom,kaanapali-qmp-gen3x2-pcie-phy @@ -190,6 +192,8 @@ allOf: compatible: contains: enum: + - qcom,eliza-qmp-gen3x1-pcie-phy + - qcom,eliza-qmp-gen3x2-pcie-phy - qcom,glymur-qmp-gen4x2-pcie-phy - qcom,glymur-qmp-gen5x4-pcie-phy - qcom,qcs8300-qmp-gen4x2-pcie-phy @@ -215,6 +219,8 @@ allOf: compatible: contains: enum: + - qcom,eliza-qmp-gen3x1-pcie-phy + - qcom,eliza-qmp-gen3x2-pcie-phy - qcom,glymur-qmp-gen4x2-pcie-phy - qcom,glymur-qmp-gen5x4-pcie-phy - qcom,kaanapali-qmp-gen3x2-pcie-phy From fdd2913a4e505716dce5c9f89c268628d9a019d5 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Mon, 8 Jun 2026 14:18:15 +0530 Subject: [PATCH 63/87] phy: qcom: qmp-pcie: Add QMP PCIe PHY support for Eliza Add QMP PCIe PHY support for the Eliza SoC. Introduce a new Gen3x1 PHY configuration with Eliza-specific initialization tables, and reuse the existing sm8550 Gen3x2 configuration for the Gen3x2 PHY instance. Also add the missing QPHY_PCIE_V6_PCS_PCIE_INT_AUX_CLK_CONFIG1 register definition to the PCIe V6 PCS header. Reviewed-by: Dmitry Baryshkov Signed-off-by: Krishna Chaitanya Chundru Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20260608-eliza-v3-3-9bdeb7434b28@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 139 ++++++++++++++++++ .../phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h | 1 + 2 files changed, 140 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 75afbd15aaf4..d3effad7a074 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -198,6 +198,112 @@ static const struct qmp_phy_init_tbl msm8998_pcie_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_SIGDET_CNTRL, 0x03), }; +static const struct qmp_phy_init_tbl eliza_qmp_gen3x1_pcie_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE1, 0x93), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORECLK_DIV_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE1_MODE1, 0xb4), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE2_MODE1, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0xf8), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE1_MODE0, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x62), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_ENABLE1, 0x90), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYS_CLK_CTRL, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x42), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_SELECT, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_ADDITIONAL_MISC_3, 0x0f), +}; + +static const struct qmp_phy_init_tbl eliza_qmp_gen3x1_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_REFGEN_REQ_CONFIG1, 0x05), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_G3S2_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_RX_SIGDET_LVL, 0x77), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_RATE_SLEW_CNTRL1, 0x0b), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_PCS_TX_RX_CONFIG, 0x0c), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_EQ_CONFIG2, 0x0f), +}; + +static const struct qmp_phy_init_tbl eliza_qmp_gen3x1_pcie_misc_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG2, 0x1d), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_INT_AUX_CLK_CONFIG1, 0x00), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_RXEQEVAL_TIME, 0x27), +}; + +static const struct qmp_phy_init_tbl eliza_qmp_gen3x1_pcie_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V6_TX_RES_CODE_LANE_OFFSET_RX, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_TX_LANE_MODE_1, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V6_TX_LANE_MODE_4, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V6_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V6_TX_PI_QEC_CTRL, 0x02), +}; + +static const struct qmp_phy_init_tbl eliza_qmp_gen3x1_pcie_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_FO_GAIN, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SO_GAIN, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_PI_CONTROLS, 0xf0), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SB2_THRESH1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SB2_THRESH2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_AUX_DATA_TCOARSE_TFINE, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_TX_ADAPT_POST_THRESH, 0xf0), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_VGA_CAL_CNTRL1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_VGA_CAL_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_GM_CAL, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_IDAC_TSETTLE_LOW, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_SIDGET_ENABLES, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_00_LOW, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_00_HIGH, 0xbf), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_00_HIGH2, 0xbf), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_00_HIGH3, 0xb7), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_00_HIGH4, 0xea), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_LOW, 0xdc), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_HIGH, 0x5c), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_HIGH2, 0x9c), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_HIGH3, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_HIGH4, 0x89), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH, 0x94), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH2, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH3, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH4, 0x89), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_SIGDET_CAL_TRIM, 0x08), +}; + static const struct qmp_phy_init_tbl ipq6018_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_PER1, 0x7d), QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_PER2, 0x01), @@ -3532,6 +3638,33 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v8_50 = { .txrxz = 0xd000, }; +static const struct qmp_phy_cfg eliza_qmp_gen3x1_pciephy_cfg = { + .lanes = 1, + + .offsets = &qmp_pcie_offsets_v5, + + .tbls = { + .serdes = eliza_qmp_gen3x1_pcie_serdes_tbl, + .serdes_num = ARRAY_SIZE(eliza_qmp_gen3x1_pcie_serdes_tbl), + .tx = eliza_qmp_gen3x1_pcie_tx_tbl, + .tx_num = ARRAY_SIZE(eliza_qmp_gen3x1_pcie_tx_tbl), + .rx = eliza_qmp_gen3x1_pcie_rx_tbl, + .rx_num = ARRAY_SIZE(eliza_qmp_gen3x1_pcie_rx_tbl), + .pcs = eliza_qmp_gen3x1_pcie_pcs_tbl, + .pcs_num = ARRAY_SIZE(eliza_qmp_gen3x1_pcie_pcs_tbl), + .pcs_misc = eliza_qmp_gen3x1_pcie_misc_pcs_tbl, + .pcs_misc_num = ARRAY_SIZE(eliza_qmp_gen3x1_pcie_misc_pcs_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_v6_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS, +}; + static const struct qmp_phy_cfg ipq8074_pciephy_cfg = { .lanes = 1, @@ -5399,6 +5532,12 @@ static int qmp_pcie_probe(struct platform_device *pdev) static const struct of_device_id qmp_pcie_of_match_table[] = { { + .compatible = "qcom,eliza-qmp-gen3x1-pcie-phy", + .data = &eliza_qmp_gen3x1_pciephy_cfg, + }, { + .compatible = "qcom,eliza-qmp-gen3x2-pcie-phy", + .data = &sm8550_qmp_gen3x2_pciephy_cfg, + }, { .compatible = "qcom,glymur-qmp-gen4x2-pcie-phy", .data = &glymur_qmp_gen4x2_pciephy_cfg, }, { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h index 45397cb3c0c6..17a0f9d18acf 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h @@ -12,6 +12,7 @@ #define QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG2 0x0c #define QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG4 0x14 #define QPHY_PCIE_V6_PCS_PCIE_ENDPOINT_REFCLK_DRIVE 0x20 +#define QPHY_PCIE_V6_PCS_PCIE_INT_AUX_CLK_CONFIG1 0x54 #define QPHY_PCIE_V6_PCS_PCIE_OSC_DTCT_ACTIONS 0x94 #define QPHY_PCIE_V6_PCS_LANE1_INSIG_SW_CTRL2 0x024 From 493f8fc57bf685e23d3c924dbd787249d47fb972 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:37 +0300 Subject: [PATCH 64/87] phy: lynx-28g: avoid returning NULL in of_xlate() function Sashiko points out that _of_phy_get() does not support a NULL returned output from phy_provider->of_xlate(), just a valid pointer or a pointer-encoded error. When lynx_28g_probe() -> for_each_available_child_of_node() skips over lanes which have OF nodes with status = "disabled", the priv->lane[idx].phy pointer will remain NULL. This NULL pointer may be propagated to lynx_28g_xlate() if the device tree contains a phandle to the disabled lane AND fw_devlink did not block probing for the consumer. In that case, the PHY core will crash when trying to dereference the NULL phy pointer. Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-2-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 92bfc5f65e0b..cacc128dc96a 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -1435,7 +1435,7 @@ static struct phy *lynx_28g_xlate(struct device *dev, idx < priv->info->first_lane)) return ERR_PTR(-EINVAL); - return priv->lane[idx].phy; + return priv->lane[idx].phy ?: ERR_PTR(-ENODEV); } static int lynx_28g_probe_lane(struct lynx_28g_priv *priv, int id, From a45f9dac20b6757487502109feac0298ec78f3bd Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:38 +0300 Subject: [PATCH 65/87] phy: lynx-28g: reject probing on devices with unsupported OF nodes It is possible to bind the lynx-28g driver to an arbitrary device with an OF node, using the driver_override mechanism that is available for the platform bus, and trigger a crash this way: $ echo 1ea0000.serdes > /sys/bus/platform/drivers/lynx-10g/unbind $ echo lynx-28g > /sys/bus/platform/devices/1ea0000.serdes/driver_override $ echo 1ea0000.serdes > /sys/bus/platform/drivers/lynx-28g/bind Internal error: Oops: 0000000096000004 [#1] SMP Hardware name: LS1028A RDB Board (DT) pc : lynx_probe+0x118/0x4fc lr : lynx_probe+0x110/0x4fc Call trace: lynx_probe+0x118/0x4fc (P) lynx_28g_probe+0x54/0x7c platform_probe+0x68/0xa4 really_probe+0x14c/0x2ec __driver_probe_device+0xc8/0x170 device_driver_attach+0x58/0xa8 bind_store+0xd8/0x118 drv_attr_store+0x24/0x38 The crash is caused by the fact that of_device_get_match_data() returns NULL (the bound device has a different compatible string) and this is not checked. There was a previous attempt to avoid this in commit c9d80e861034 ("phy: lynx-28g: require an OF node to probe"), but the mechanism was not fully understood and it only covered the case where the driver was bound to a device with no OF node. The issue was found during Sashiko review. Elevated privilege is required to override the driver for a device, so the real life impact of the issue should not be very high. Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-3-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index cacc128dc96a..1f5cb02931f5 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -1477,6 +1477,9 @@ static int lynx_28g_probe(struct platform_device *pdev) priv->dev = dev; priv->info = of_device_get_match_data(dev); + if (!priv->info) + return -ENODEV; + dev_set_drvdata(dev, priv); spin_lock_init(&priv->pcc_lock); INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check); From ac0ffe7cf1221182f4068d8aaf825b01655c7ca9 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:39 +0300 Subject: [PATCH 66/87] phy: lynx-28g: move lane mode helpers to new core module Do some preparation work for the introduction of the lynx-10g driver, which will share a common backbone with the 28G Lynx SerDes. This is just trivial stuff which can be moved without any surgery, and is easy to follow but otherwise pollutes more serious changes. The lane modes themselves are exported to a public header, because on the 10G Lynx, the hardware requires implementing a procedure called "RCW override". This requires coordination with drivers/soc/fsl/guts.c to tell it that a SerDes lane needs to be switched to a different protocol (enum lynx_lane_mode). Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-4-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/Kconfig | 4 ++ drivers/phy/freescale/Makefile | 1 + drivers/phy/freescale/phy-fsl-lynx-28g.c | 56 ++--------------------- drivers/phy/freescale/phy-fsl-lynx-core.c | 44 ++++++++++++++++++ drivers/phy/freescale/phy-fsl-lynx-core.h | 24 ++++++++++ include/soc/fsl/phy-fsl-lynx.h | 16 +++++++ 6 files changed, 92 insertions(+), 53 deletions(-) create mode 100644 drivers/phy/freescale/phy-fsl-lynx-core.c create mode 100644 drivers/phy/freescale/phy-fsl-lynx-core.h create mode 100644 include/soc/fsl/phy-fsl-lynx.h diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig index 81f53564ee15..ac575d531db7 100644 --- a/drivers/phy/freescale/Kconfig +++ b/drivers/phy/freescale/Kconfig @@ -51,11 +51,15 @@ config PHY_FSL_SAMSUNG_HDMI_PHY Enable this to add support for the Samsung HDMI PHY in i.MX8MP. endif +config PHY_FSL_LYNX_CORE + tristate + config PHY_FSL_LYNX_28G tristate "Freescale Layerscape Lynx 28G SerDes PHY support" depends on OF depends on ARCH_LAYERSCAPE || COMPILE_TEST select GENERIC_PHY + select PHY_FSL_LYNX_CORE help Enable this to add support for the Lynx SerDes 28G PHY as found on NXP's Layerscape platforms such as LX2160A. diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile index 658eac7d0a62..d7aa62cdeb39 100644 --- a/drivers/phy/freescale/Makefile +++ b/drivers/phy/freescale/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_PHY_MIXEL_LVDS_PHY) += phy-fsl-imx8qm-lvds-phy.o obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o obj-$(CONFIG_PHY_FSL_IMX8M_PCIE) += phy-fsl-imx8m-pcie.o obj-$(CONFIG_PHY_FSL_IMX8QM_HSIO) += phy-fsl-imx8qm-hsio.o +obj-$(CONFIG_PHY_FSL_LYNX_CORE) += phy-fsl-lynx-core.o obj-$(CONFIG_PHY_FSL_LYNX_28G) += phy-fsl-lynx-28g.o obj-$(CONFIG_PHY_FSL_SAMSUNG_HDMI_PHY) += phy-fsl-samsung-hdmi.o diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 1f5cb02931f5..d3f49d96340f 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -9,6 +9,8 @@ #include #include +#include "phy-fsl-lynx-core.h" + #define LYNX_28G_NUM_LANE 8 #define LYNX_28G_NUM_PLL 2 @@ -282,15 +284,6 @@ enum lynx_28g_proto_sel { PROTO_SEL_25G_50G_100G = 0x1a, }; -enum lynx_lane_mode { - LANE_MODE_UNKNOWN, - LANE_MODE_1000BASEX_SGMII, - LANE_MODE_10GBASER, - LANE_MODE_USXGMII, - LANE_MODE_25GBASER, - LANE_MODE_MAX, -}; - struct lynx_28g_proto_conf { /* LNaGCR0 */ int proto_sel; @@ -463,12 +456,6 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = { }, }; -struct lynx_pccr { - int offset; - int width; - int shift; -}; - struct lynx_28g_priv; struct lynx_28g_pll { @@ -487,11 +474,6 @@ struct lynx_28g_lane { enum lynx_lane_mode mode; }; -struct lynx_info { - bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode); - int first_lane; -}; - struct lynx_28g_priv { void __iomem *base; struct device *dev; @@ -531,39 +513,6 @@ static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off, #define lynx_28g_pll_read(pll, reg) \ ioread32((pll)->priv->base + reg((pll)->id)) -static const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode) -{ - switch (lane_mode) { - case LANE_MODE_1000BASEX_SGMII: - return "1000Base-X/SGMII"; - case LANE_MODE_10GBASER: - return "10GBase-R"; - case LANE_MODE_USXGMII: - return "USXGMII"; - case LANE_MODE_25GBASER: - return "25GBase-R"; - default: - return "unknown"; - } -} - -static enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf) -{ - switch (intf) { - case PHY_INTERFACE_MODE_SGMII: - case PHY_INTERFACE_MODE_1000BASEX: - return LANE_MODE_1000BASEX_SGMII; - case PHY_INTERFACE_MODE_10GBASER: - return LANE_MODE_10GBASER; - case PHY_INTERFACE_MODE_USXGMII: - return LANE_MODE_USXGMII; - case PHY_INTERFACE_MODE_25GBASER: - return LANE_MODE_25GBASER; - default: - return LANE_MODE_UNKNOWN; - } -} - /* A lane mode is supported if we have a PLL that can provide its required * clock net, and if there is a protocol converter for that mode on that lane. */ @@ -1572,6 +1521,7 @@ static struct platform_driver lynx_28g_driver = { }; module_platform_driver(lynx_28g_driver); +MODULE_IMPORT_NS("PHY_FSL_LYNX"); MODULE_AUTHOR("Ioana Ciornei "); MODULE_DESCRIPTION("Lynx 28G SerDes PHY driver for Layerscape SoCs"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c new file mode 100644 index 000000000000..d56f189c162d --- /dev/null +++ b/drivers/phy/freescale/phy-fsl-lynx-core.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright 2025-2026 NXP */ + +#include + +#include "phy-fsl-lynx-core.h" + +const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode) +{ + switch (lane_mode) { + case LANE_MODE_1000BASEX_SGMII: + return "1000Base-X/SGMII"; + case LANE_MODE_10GBASER: + return "10GBase-R"; + case LANE_MODE_USXGMII: + return "USXGMII"; + case LANE_MODE_25GBASER: + return "25GBase-R"; + default: + return "unknown"; + } +} +EXPORT_SYMBOL_NS_GPL(lynx_lane_mode_str, "PHY_FSL_LYNX"); + +enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf) +{ + switch (intf) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: + return LANE_MODE_1000BASEX_SGMII; + case PHY_INTERFACE_MODE_10GBASER: + return LANE_MODE_10GBASER; + case PHY_INTERFACE_MODE_USXGMII: + return LANE_MODE_USXGMII; + case PHY_INTERFACE_MODE_25GBASER: + return LANE_MODE_25GBASER; + default: + return LANE_MODE_UNKNOWN; + } +} +EXPORT_SYMBOL_NS_GPL(phy_interface_to_lane_mode, "PHY_FSL_LYNX"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Freescale Lynx SerDes core functionality"); diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.h b/drivers/phy/freescale/phy-fsl-lynx-core.h new file mode 100644 index 000000000000..fe15986482b0 --- /dev/null +++ b/drivers/phy/freescale/phy-fsl-lynx-core.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright 2025-2026 NXP */ + +#ifndef _PHY_FSL_LYNX_CORE_H +#define _PHY_FSL_LYNX_CORE_H + +#include +#include + +struct lynx_pccr { + int offset; + int width; + int shift; +}; + +struct lynx_info { + bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode); + int first_lane; +}; + +const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode); +enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf); + +#endif diff --git a/include/soc/fsl/phy-fsl-lynx.h b/include/soc/fsl/phy-fsl-lynx.h new file mode 100644 index 000000000000..92e8272d5ae1 --- /dev/null +++ b/include/soc/fsl/phy-fsl-lynx.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright 2023-2026 NXP */ + +#ifndef __PHY_FSL_LYNX_H_ +#define __PHY_FSL_LYNX_H_ + +enum lynx_lane_mode { + LANE_MODE_UNKNOWN, + LANE_MODE_1000BASEX_SGMII, + LANE_MODE_10GBASER, + LANE_MODE_USXGMII, + LANE_MODE_25GBASER, + LANE_MODE_MAX, +}; + +#endif /* __PHY_FSL_LYNX_H_ */ From b7021a4d3129aeb0e25c3edcaf3a36199e73f652 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:40 +0300 Subject: [PATCH 67/87] phy: lynx-28g: move data structures to core The goal is to avoid duplicating the core data structures when introducing the new lynx-10g driver. We move the following to phy-fsl-lynx-core: - struct lynx_28g_pll -> struct lynx_pll. This has some hardware-specific register fields which need to become hardware agnostic (the PLL register layout is different for Lynx 10G), So: - PLLnRSTCTL_DIS(pll->rstctl) becomes !pll->enabled - PLLnRSTCTL_LOCK(pll->rstctl) becomes pll->locked - FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1) becomes pll->frate_sel - FIELD_GET(PLLnCR0_REFCLK_SEL, pll->cr0) becomes pll->refclk_sel - struct lynx_28g_lane -> struct lynx_lane - struct lynx_28g_priv -> struct lynx_priv - field lane[LYNX_28G_NUM_LANE] has to be dynamically allocated. Not all Lynx 10G SerDes blocks have 8 lanes. - LYNX_28G_NUM_PLL -> LYNX_NUM_PLL. This is an architectural constant which is the same for Lynx 10G as well. To avoid major noise in the lynx-28g driver, we keep compatibility shims (for now) where the old lynx_28g names are preserved, but translate to the common data structures. Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-5-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 135 +++++++--------------- drivers/phy/freescale/phy-fsl-lynx-core.c | 23 ++++ drivers/phy/freescale/phy-fsl-lynx-core.h | 64 ++++++++++ 3 files changed, 129 insertions(+), 93 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index d3f49d96340f..570fa74daba0 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -12,7 +12,7 @@ #include "phy-fsl-lynx-core.h" #define LYNX_28G_NUM_LANE 8 -#define LYNX_28G_NUM_PLL 2 +#define LYNX_28G_NUM_PLL LYNX_NUM_PLL /* SoC IP wrapper for protocol converters */ #define PCC8 0x10a0 @@ -43,8 +43,8 @@ /* Per PLL registers */ #define PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0) -#define PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24) -#define PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23) +#define PLLnRSTCTL_DIS BIT(24) +#define PLLnRSTCTL_LOCK BIT(23) #define PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4) #define PLLnCR0_REFCLK_SEL GENMASK(20, 16) @@ -269,6 +269,17 @@ #define LYNX_28G_LANE_STOP_SLEEP_US 100 #define LYNX_28G_LANE_STOP_TIMEOUT_US 1000000 +#define lynx_28g_read lynx_read +#define lynx_28g_write lynx_write +#define lynx_28g_lane_rmw lynx_lane_rmw +#define lynx_28g_lane_read lynx_lane_read +#define lynx_28g_lane_write lynx_lane_write +#define lynx_28g_pll_read lynx_pll_read + +#define lynx_28g_priv lynx_priv +#define lynx_28g_lane lynx_lane +#define lynx_28g_pll lynx_pll + enum lynx_28g_eq_type { EQ_TYPE_NO_EQ = 0, EQ_TYPE_2TAP = 1, @@ -456,86 +467,6 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = { }, }; -struct lynx_28g_priv; - -struct lynx_28g_pll { - struct lynx_28g_priv *priv; - u32 rstctl, cr0, cr1; - int id; - DECLARE_BITMAP(supported, LANE_MODE_MAX); -}; - -struct lynx_28g_lane { - struct lynx_28g_priv *priv; - struct phy *phy; - bool powered_up; - bool init; - unsigned int id; - enum lynx_lane_mode mode; -}; - -struct lynx_28g_priv { - void __iomem *base; - struct device *dev; - const struct lynx_info *info; - /* Serialize concurrent access to registers shared between lanes, - * like PCCn - */ - spinlock_t pcc_lock; - struct lynx_28g_pll pll[LYNX_28G_NUM_PLL]; - struct lynx_28g_lane lane[LYNX_28G_NUM_LANE]; - - struct delayed_work cdr_check; -}; - -static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off, - u32 val, u32 mask) -{ - void __iomem *reg = priv->base + off; - u32 orig, tmp; - - orig = ioread32(reg); - tmp = orig & ~mask; - tmp |= val; - iowrite32(tmp, reg); -} - -#define lynx_28g_read(priv, off) \ - ioread32((priv)->base + (off)) -#define lynx_28g_write(priv, off, val) \ - iowrite32(val, (priv)->base + (off)) -#define lynx_28g_lane_rmw(lane, reg, val, mask) \ - lynx_28g_rmw((lane)->priv, reg(lane->id), val, mask) -#define lynx_28g_lane_read(lane, reg) \ - ioread32((lane)->priv->base + reg((lane)->id)) -#define lynx_28g_lane_write(lane, reg, val) \ - iowrite32(val, (lane)->priv->base + reg((lane)->id)) -#define lynx_28g_pll_read(pll, reg) \ - ioread32((pll)->priv->base + reg((pll)->id)) - -/* A lane mode is supported if we have a PLL that can provide its required - * clock net, and if there is a protocol converter for that mode on that lane. - */ -static bool lynx_28g_supports_lane_mode(struct lynx_28g_lane *lane, - enum lynx_lane_mode mode) -{ - struct lynx_28g_priv *priv = lane->priv; - int i; - - if (!priv->info->lane_supports_mode(lane->id, mode)) - return false; - - for (i = 0; i < LYNX_28G_NUM_PLL; i++) { - if (PLLnRSTCTL_DIS(priv->pll[i].rstctl)) - continue; - - if (test_bit(mode, priv->pll[i].supported)) - return true; - } - - return false; -} - static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv, enum lynx_lane_mode mode) { @@ -545,7 +476,7 @@ static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv, for (i = 0; i < LYNX_28G_NUM_PLL; i++) { pll = &priv->pll[i]; - if (PLLnRSTCTL_DIS(pll->rstctl)) + if (!pll->enabled) continue; if (test_bit(mode, pll->supported)) @@ -553,7 +484,7 @@ static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv, } /* no pll supports requested mode, either caller forgot to check - * lynx_28g_supports_lane_mode, or this is a bug. + * lynx_lane_supports_mode(), or this is a bug. */ dev_WARN_ONCE(priv->dev, 1, "no pll for lane mode %s\n", lynx_lane_mode_str(mode)); @@ -564,7 +495,7 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane, struct lynx_28g_pll *pll, enum lynx_lane_mode lane_mode) { - switch (FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1)) { + switch (pll->frate_sel) { case PLLnCR1_FRATE_5G_10GVCO: case PLLnCR1_FRATE_5G_25GVCO: switch (lane_mode) { @@ -879,27 +810,33 @@ static bool lynx_28g_compat_lane_supports_mode(int lane, static const struct lynx_info lynx_info_compat = { .lane_supports_mode = lynx_28g_compat_lane_supports_mode, + .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2160a_serdes1 = { .lane_supports_mode = lx2160a_serdes1_lane_supports_mode, + .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2160a_serdes2 = { .lane_supports_mode = lx2160a_serdes2_lane_supports_mode, + .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2160a_serdes3 = { .lane_supports_mode = lx2160a_serdes3_lane_supports_mode, + .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2162a_serdes1 = { .lane_supports_mode = lx2162a_serdes1_lane_supports_mode, .first_lane = 4, + .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2162a_serdes2 = { .lane_supports_mode = lx2162a_serdes2_lane_supports_mode, + .num_lanes = LYNX_28G_NUM_LANE, }; static int lynx_pccr_read(struct lynx_28g_lane *lane, enum lynx_lane_mode mode, @@ -1168,7 +1105,7 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode) return -EOPNOTSUPP; lane_mode = phy_interface_to_lane_mode(submode); - if (!lynx_28g_supports_lane_mode(lane, lane_mode)) + if (!lynx_lane_supports_mode(lane, lane_mode)) return -EOPNOTSUPP; if (lane_mode == lane->mode) @@ -1210,7 +1147,7 @@ static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode, return -EOPNOTSUPP; lane_mode = phy_interface_to_lane_mode(submode); - if (!lynx_28g_supports_lane_mode(lane, lane_mode)) + if (!lynx_lane_supports_mode(lane, lane_mode)) return -EOPNOTSUPP; return 0; @@ -1262,6 +1199,7 @@ static const struct phy_ops lynx_28g_ops = { static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv) { struct lynx_28g_pll *pll; + u32 val; int i; for (i = 0; i < LYNX_28G_NUM_PLL; i++) { @@ -1269,14 +1207,20 @@ static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv) pll->priv = priv; pll->id = i; - pll->rstctl = lynx_28g_pll_read(pll, PLLnRSTCTL); - pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0); - pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1); + val = lynx_28g_pll_read(pll, PLLnRSTCTL); + pll->enabled = !(val & PLLnRSTCTL_DIS); + pll->locked = !!(val & PLLnRSTCTL_LOCK); - if (PLLnRSTCTL_DIS(pll->rstctl)) + val = lynx_28g_pll_read(pll, PLLnCR0); + pll->refclk_sel = FIELD_GET(PLLnCR0_REFCLK_SEL, val); + + val = lynx_28g_pll_read(pll, PLLnCR1); + pll->frate_sel = FIELD_GET(PLLnCR1_FRATE_SEL, val); + + if (!pll->enabled) continue; - switch (FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1)) { + switch (pll->frate_sel) { case PLLnCR1_FRATE_5G_10GVCO: case PLLnCR1_FRATE_5G_25GVCO: /* 5GHz clock net */ @@ -1440,6 +1384,11 @@ static int lynx_28g_probe(struct platform_device *pdev) if (priv->info == &lynx_info_compat) dev_warn(dev, "Please update device tree to use per-device compatible strings\n"); + priv->lane = devm_kcalloc(dev, priv->info->num_lanes, + sizeof(*priv->lane), GFP_KERNEL); + if (!priv->lane) + return -ENOMEM; + priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c index d56f189c162d..de45b14d3fb6 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.c +++ b/drivers/phy/freescale/phy-fsl-lynx-core.c @@ -40,5 +40,28 @@ enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf) } EXPORT_SYMBOL_NS_GPL(phy_interface_to_lane_mode, "PHY_FSL_LYNX"); +/* A lane mode is supported if we have a PLL that can provide its required + * clock net, and if there is a protocol converter for that mode on that lane. + */ +bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode) +{ + struct lynx_priv *priv = lane->priv; + int i; + + if (!priv->info->lane_supports_mode(lane->id, mode)) + return false; + + for (i = 0; i < LYNX_NUM_PLL; i++) { + if (!priv->pll[i].enabled) + continue; + + if (test_bit(mode, priv->pll[i].supported)) + return true; + } + + return false; +} +EXPORT_SYMBOL_NS_GPL(lynx_lane_supports_mode, "PHY_FSL_LYNX"); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Freescale Lynx SerDes core functionality"); diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.h b/drivers/phy/freescale/phy-fsl-lynx-core.h index fe15986482b0..f0cb3e805235 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.h +++ b/drivers/phy/freescale/phy-fsl-lynx-core.h @@ -7,18 +7,82 @@ #include #include +#define LYNX_NUM_PLL 2 + struct lynx_pccr { int offset; int width; int shift; }; +struct lynx_priv; + +struct lynx_pll { + struct lynx_priv *priv; + int id; + int refclk_sel; + int frate_sel; + bool enabled; + bool locked; + DECLARE_BITMAP(supported, LANE_MODE_MAX); +}; + +struct lynx_lane { + struct lynx_priv *priv; + struct phy *phy; + bool powered_up; + bool init; + unsigned int id; + enum lynx_lane_mode mode; +}; + struct lynx_info { bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode); int first_lane; + int num_lanes; }; +struct lynx_priv { + void __iomem *base; + struct device *dev; + const struct lynx_info *info; + /* Serialize concurrent access to registers shared between lanes, + * like PCCn + */ + spinlock_t pcc_lock; + struct lynx_pll pll[LYNX_NUM_PLL]; + struct lynx_lane *lane; + + struct delayed_work cdr_check; +}; + +static inline void lynx_rmw(struct lynx_priv *priv, unsigned long off, u32 val, + u32 mask) +{ + void __iomem *reg = priv->base + off; + u32 orig, tmp; + + orig = ioread32(reg); + tmp = orig & ~mask; + tmp |= val; + iowrite32(tmp, reg); +} + +#define lynx_read(priv, off) \ + ioread32((priv)->base + (off)) +#define lynx_write(priv, off, val) \ + iowrite32(val, (priv)->base + (off)) +#define lynx_lane_rmw(lane, reg, val, mask) \ + lynx_rmw((lane)->priv, reg(lane->id), val, mask) +#define lynx_lane_read(lane, reg) \ + ioread32((lane)->priv->base + reg((lane)->id)) +#define lynx_lane_write(lane, reg, val) \ + iowrite32(val, (lane)->priv->base + reg((lane)->id)) +#define lynx_pll_read(pll, reg) \ + ioread32((pll)->priv->base + reg((pll)->id)) + const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode); enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf); +bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode); #endif From d4550ea4b161202607e31b0b6c6c34fef7e2b797 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:41 +0300 Subject: [PATCH 68/87] phy: lynx-28g: common lynx_pll_get() The logic should be absolutely unchanged in the new 10G Lynx SerDes driver, so let's move this to phy-fsl-lynx-core.c and update the 28G Lynx driver to use the common variant. While at it, update the call site, lynx_28g_lane_remap_pll(), to use the new data structures, and refactor the NULL pll pointer check (the current form triggers a checkpatch CHECK). Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-6-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 34 ++++------------------- drivers/phy/freescale/phy-fsl-lynx-core.c | 24 ++++++++++++++++ drivers/phy/freescale/phy-fsl-lynx-core.h | 2 ++ 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 570fa74daba0..5c473d6c233e 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -467,30 +467,6 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = { }, }; -static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv, - enum lynx_lane_mode mode) -{ - struct lynx_28g_pll *pll; - int i; - - for (i = 0; i < LYNX_28G_NUM_PLL; i++) { - pll = &priv->pll[i]; - - if (!pll->enabled) - continue; - - if (test_bit(mode, pll->supported)) - return pll; - } - - /* no pll supports requested mode, either caller forgot to check - * lynx_lane_supports_mode(), or this is a bug. - */ - dev_WARN_ONCE(priv->dev, 1, "no pll for lane mode %s\n", - lynx_lane_mode_str(mode)); - return NULL; -} - static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane, struct lynx_28g_pll *pll, enum lynx_lane_mode lane_mode) @@ -927,15 +903,15 @@ static int lynx_pcvt_rmw(struct lynx_28g_lane *lane, return lynx_pcvt_write(lane, lane_mode, cr, tmp); } -static void lynx_28g_lane_remap_pll(struct lynx_28g_lane *lane, +static void lynx_28g_lane_remap_pll(struct lynx_lane *lane, enum lynx_lane_mode lane_mode) { - struct lynx_28g_priv *priv = lane->priv; - struct lynx_28g_pll *pll; + struct lynx_priv *priv = lane->priv; + struct lynx_pll *pll; /* Switch to the PLL that works with this interface type */ - pll = lynx_28g_pll_get(priv, lane_mode); - if (unlikely(pll == NULL)) + pll = lynx_pll_get(priv, lane_mode); + if (unlikely(!pll)) return; lynx_28g_lane_set_pll(lane, pll); diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c index de45b14d3fb6..5e5bcaa54d09 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.c +++ b/drivers/phy/freescale/phy-fsl-lynx-core.c @@ -63,5 +63,29 @@ bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode) } EXPORT_SYMBOL_NS_GPL(lynx_lane_supports_mode, "PHY_FSL_LYNX"); +struct lynx_pll *lynx_pll_get(struct lynx_priv *priv, enum lynx_lane_mode mode) +{ + struct lynx_pll *pll; + int i; + + for (i = 0; i < LYNX_NUM_PLL; i++) { + pll = &priv->pll[i]; + + if (!pll->enabled) + continue; + + if (test_bit(mode, pll->supported)) + return pll; + } + + /* no pll supports requested mode, either caller forgot to check + * lynx_lane_supports_mode(), or this is a bug. + */ + dev_WARN_ONCE(priv->dev, 1, "no pll for lane mode %s\n", + lynx_lane_mode_str(mode)); + return NULL; +} +EXPORT_SYMBOL_NS_GPL(lynx_pll_get, "PHY_FSL_LYNX"); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Freescale Lynx SerDes core functionality"); diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.h b/drivers/phy/freescale/phy-fsl-lynx-core.h index f0cb3e805235..b726ff21972b 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.h +++ b/drivers/phy/freescale/phy-fsl-lynx-core.h @@ -85,4 +85,6 @@ const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode); enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf); bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode); +struct lynx_pll *lynx_pll_get(struct lynx_priv *priv, enum lynx_lane_mode mode); + #endif From 51c25f4b0c883c1b7eee5f8f3aa0c2245eb6351a Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:42 +0300 Subject: [PATCH 69/87] phy: lynx-28g: generalize protocol converter accessors The protocol converters on the 10G Lynx are architecturally similar, but different in layout from the 28G Lynx ones. Move lynx_pccr_read(), lynx_pccr_write(), lynx_pcvt_read() and lynx_pcvt_write() from the 28G Lynx driver to the common module, and permit each SerDes driver to provide just its own bits in order to use this common API. Currently, that just means that the direct calls to lynx_28g_get_pcvt_offset() are modified to go through the lynx->info->get_pcvt_offset() indirect function call, and similarly, lynx_28g_get_pccr() through lynx->info->get_pccr(). Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-7-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 102 +++------------------- drivers/phy/freescale/phy-fsl-lynx-core.c | 90 +++++++++++++++++++ drivers/phy/freescale/phy-fsl-lynx-core.h | 13 +++ 3 files changed, 115 insertions(+), 90 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 5c473d6c233e..1de663283faf 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -269,8 +269,6 @@ #define LYNX_28G_LANE_STOP_SLEEP_US 100 #define LYNX_28G_LANE_STOP_TIMEOUT_US 1000000 -#define lynx_28g_read lynx_read -#define lynx_28g_write lynx_write #define lynx_28g_lane_rmw lynx_lane_rmw #define lynx_28g_lane_read lynx_lane_read #define lynx_28g_lane_write lynx_lane_write @@ -785,124 +783,48 @@ static bool lynx_28g_compat_lane_supports_mode(int lane, } static const struct lynx_info lynx_info_compat = { + .get_pccr = lynx_28g_get_pccr, + .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lynx_28g_compat_lane_supports_mode, .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2160a_serdes1 = { + .get_pccr = lynx_28g_get_pccr, + .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2160a_serdes1_lane_supports_mode, .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2160a_serdes2 = { + .get_pccr = lynx_28g_get_pccr, + .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2160a_serdes2_lane_supports_mode, .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2160a_serdes3 = { + .get_pccr = lynx_28g_get_pccr, + .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2160a_serdes3_lane_supports_mode, .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2162a_serdes1 = { + .get_pccr = lynx_28g_get_pccr, + .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2162a_serdes1_lane_supports_mode, .first_lane = 4, .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2162a_serdes2 = { + .get_pccr = lynx_28g_get_pccr, + .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2162a_serdes2_lane_supports_mode, .num_lanes = LYNX_28G_NUM_LANE, }; -static int lynx_pccr_read(struct lynx_28g_lane *lane, enum lynx_lane_mode mode, - u32 *val) -{ - struct lynx_28g_priv *priv = lane->priv; - struct lynx_pccr pccr; - u32 tmp; - int err; - - err = lynx_28g_get_pccr(mode, lane->id, &pccr); - if (err) - return err; - - tmp = lynx_28g_read(priv, pccr.offset); - *val = (tmp >> pccr.shift) & GENMASK(pccr.width - 1, 0); - - return 0; -} - -static int lynx_pccr_write(struct lynx_28g_lane *lane, - enum lynx_lane_mode lane_mode, u32 val) -{ - struct lynx_28g_priv *priv = lane->priv; - struct lynx_pccr pccr; - u32 old, tmp, mask; - int err; - - err = lynx_28g_get_pccr(lane_mode, lane->id, &pccr); - if (err) - return err; - - old = lynx_28g_read(priv, pccr.offset); - mask = GENMASK(pccr.width - 1, 0) << pccr.shift; - tmp = (old & ~mask) | (val << pccr.shift); - lynx_28g_write(priv, pccr.offset, tmp); - - dev_dbg(&lane->phy->dev, "PCCR@0x%x: 0x%x -> 0x%x\n", - pccr.offset, old, tmp); - - return 0; -} - -static int lynx_pcvt_read(struct lynx_28g_lane *lane, - enum lynx_lane_mode lane_mode, int cr, u32 *val) -{ - struct lynx_28g_priv *priv = lane->priv; - int offset; - - offset = lynx_28g_get_pcvt_offset(lane->id, lane_mode); - if (offset < 0) - return offset; - - *val = lynx_28g_read(priv, offset + cr); - - return 0; -} - -static int lynx_pcvt_write(struct lynx_28g_lane *lane, - enum lynx_lane_mode lane_mode, int cr, u32 val) -{ - struct lynx_28g_priv *priv = lane->priv; - int offset; - - offset = lynx_28g_get_pcvt_offset(lane->id, lane_mode); - if (offset < 0) - return offset; - - lynx_28g_write(priv, offset + cr, val); - - return 0; -} - -static int lynx_pcvt_rmw(struct lynx_28g_lane *lane, - enum lynx_lane_mode lane_mode, - int cr, u32 val, u32 mask) -{ - int err; - u32 tmp; - - err = lynx_pcvt_read(lane, lane_mode, cr, &tmp); - if (err) - return err; - - tmp &= ~mask; - tmp |= val; - - return lynx_pcvt_write(lane, lane_mode, cr, tmp); -} - static void lynx_28g_lane_remap_pll(struct lynx_lane *lane, enum lynx_lane_mode lane_mode) { diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c index 5e5bcaa54d09..f49d594622cb 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.c +++ b/drivers/phy/freescale/phy-fsl-lynx-core.c @@ -87,5 +87,95 @@ struct lynx_pll *lynx_pll_get(struct lynx_priv *priv, enum lynx_lane_mode mode) } EXPORT_SYMBOL_NS_GPL(lynx_pll_get, "PHY_FSL_LYNX"); +int lynx_pccr_read(struct lynx_lane *lane, enum lynx_lane_mode mode, u32 *val) +{ + struct lynx_priv *priv = lane->priv; + struct lynx_pccr pccr; + u32 tmp; + int err; + + err = priv->info->get_pccr(mode, lane->id, &pccr); + if (err) + return err; + + tmp = lynx_read(priv, pccr.offset); + *val = (tmp >> pccr.shift) & GENMASK(pccr.width - 1, 0); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(lynx_pccr_read, "PHY_FSL_LYNX"); + +int lynx_pccr_write(struct lynx_lane *lane, enum lynx_lane_mode mode, u32 val) +{ + struct lynx_priv *priv = lane->priv; + struct lynx_pccr pccr; + u32 old, tmp, mask; + int err; + + err = priv->info->get_pccr(mode, lane->id, &pccr); + if (err) + return err; + + old = lynx_read(priv, pccr.offset); + mask = GENMASK(pccr.width - 1, 0) << pccr.shift; + tmp = (old & ~mask) | (val << pccr.shift); + lynx_write(priv, pccr.offset, tmp); + + dev_dbg(&lane->phy->dev, "PCCR@0x%x: 0x%x -> 0x%x\n", + pccr.offset, old, tmp); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(lynx_pccr_write, "PHY_FSL_LYNX"); + +int lynx_pcvt_read(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr, + u32 *val) +{ + struct lynx_priv *priv = lane->priv; + int offset; + + offset = priv->info->get_pcvt_offset(lane->id, mode); + if (offset < 0) + return offset; + + *val = lynx_read(priv, offset + cr); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(lynx_pcvt_read, "PHY_FSL_LYNX"); + +int lynx_pcvt_write(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr, + u32 val) +{ + struct lynx_priv *priv = lane->priv; + int offset; + + offset = priv->info->get_pcvt_offset(lane->id, mode); + if (offset < 0) + return offset; + + lynx_write(priv, offset + cr, val); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(lynx_pcvt_write, "PHY_FSL_LYNX"); + +int lynx_pcvt_rmw(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr, + u32 val, u32 mask) +{ + int err; + u32 tmp; + + err = lynx_pcvt_read(lane, mode, cr, &tmp); + if (err) + return err; + + tmp &= ~mask; + tmp |= val; + + return lynx_pcvt_write(lane, mode, cr, tmp); +} +EXPORT_SYMBOL_NS_GPL(lynx_pcvt_rmw, "PHY_FSL_LYNX"); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Freescale Lynx SerDes core functionality"); diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.h b/drivers/phy/freescale/phy-fsl-lynx-core.h index b726ff21972b..5cd86c9543cb 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.h +++ b/drivers/phy/freescale/phy-fsl-lynx-core.h @@ -4,6 +4,7 @@ #ifndef _PHY_FSL_LYNX_CORE_H #define _PHY_FSL_LYNX_CORE_H +#include #include #include @@ -37,6 +38,9 @@ struct lynx_lane { }; struct lynx_info { + int (*get_pccr)(enum lynx_lane_mode lane_mode, int lane, + struct lynx_pccr *pccr); + int (*get_pcvt_offset)(int lane, enum lynx_lane_mode mode); bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode); int first_lane; int num_lanes; @@ -87,4 +91,13 @@ bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode); struct lynx_pll *lynx_pll_get(struct lynx_priv *priv, enum lynx_lane_mode mode); +int lynx_pccr_read(struct lynx_lane *lane, enum lynx_lane_mode mode, u32 *val); +int lynx_pccr_write(struct lynx_lane *lane, enum lynx_lane_mode mode, u32 val); +int lynx_pcvt_read(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr, + u32 *val); +int lynx_pcvt_write(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr, + u32 val); +int lynx_pcvt_rmw(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr, + u32 val, u32 mask); + #endif From 09697afa157df0a420fb6b107a71bb45dd32aabf Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:43 +0300 Subject: [PATCH 70/87] phy: lynx-28g: provide default lynx_lane_supports_mode() implementation For the 28G Lynx, there are situations where a protocol is not supported on a lane despite there being a PCCR register and protocol converter available: - LX2160A SerDes 1: reference manual documents PCCD fields E25GC_CFG and E25GD_CFG and protocol converter registers E25GCCR1..E25GCCR3 / E25GDCR1..E25GDCR3, but nonetheless, Table 289. SerDes 1 protocol mapping shows no RCW[SRDS_PRTCL_S1] value for which lanes C and D support 25G - when using the "fsl,lynx-28g" fallback compatible string, we don't want to offer 25GbE because we don't know if the lane supports it, even though we know how to reach the PCCR and protocol converter registers for it. But for the upcoming 10G Lynx SerDes, the above situations don't exist. There, if we know how to reach the PCCR and protocol converter registers on a lane, we implicitly know that the protocol is supported there, so implementing priv->info->lane_supports_mode() would be redundant. Implement lynx_lane_supports_mode_default() which decides whether a lane mode is supported just based on priv->info->get_pccr() and priv->info->get_pcvt_offset(). Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-8-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-core.c | 27 ++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c index f49d594622cb..802e32dc6dca 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.c +++ b/drivers/phy/freescale/phy-fsl-lynx-core.c @@ -40,6 +40,27 @@ enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf) } EXPORT_SYMBOL_NS_GPL(phy_interface_to_lane_mode, "PHY_FSL_LYNX"); +/* By default, assume that if we know how to get the PCCR register and + * protocol converter for a lane, that protocol is supported. + */ +static bool lynx_lane_supports_mode_default(struct lynx_lane *lane, + enum lynx_lane_mode mode) +{ + struct lynx_priv *priv = lane->priv; + struct lynx_pccr pccr; + + if (!priv->info->get_pccr || !priv->info->get_pcvt_offset) + return false; + + if (priv->info->get_pccr(mode, lane->id, &pccr) < 0) + return false; + + if (priv->info->get_pcvt_offset(lane->id, mode) < 0) + return false; + + return true; +} + /* A lane mode is supported if we have a PLL that can provide its required * clock net, and if there is a protocol converter for that mode on that lane. */ @@ -48,8 +69,12 @@ bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode) struct lynx_priv *priv = lane->priv; int i; - if (!priv->info->lane_supports_mode(lane->id, mode)) + if (priv->info->lane_supports_mode) { + if (!priv->info->lane_supports_mode(lane->id, mode)) + return false; + } else if (!lynx_lane_supports_mode_default(lane, mode)) { return false; + } for (i = 0; i < LYNX_NUM_PLL; i++) { if (!priv->pll[i].enabled) From 9515c35eaac9fc51717c8dbb5d18ec5a923b8342 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:44 +0300 Subject: [PATCH 71/87] phy: lynx-28g: move struct lynx_info definitions downwards We need to be able to reference more function pointers in upcoming patches. The struct lynx_info definitions are currently placed a bit up in lynx-28g.c in order to be able to do that without function prototype forward declarations, so move them downward to avoid that situation. No functional change intended. Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-9-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 86 ++++++++++++------------ 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 1de663283faf..a3fbd31d4dbf 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -782,49 +782,6 @@ static bool lynx_28g_compat_lane_supports_mode(int lane, } } -static const struct lynx_info lynx_info_compat = { - .get_pccr = lynx_28g_get_pccr, - .get_pcvt_offset = lynx_28g_get_pcvt_offset, - .lane_supports_mode = lynx_28g_compat_lane_supports_mode, - .num_lanes = LYNX_28G_NUM_LANE, -}; - -static const struct lynx_info lynx_info_lx2160a_serdes1 = { - .get_pccr = lynx_28g_get_pccr, - .get_pcvt_offset = lynx_28g_get_pcvt_offset, - .lane_supports_mode = lx2160a_serdes1_lane_supports_mode, - .num_lanes = LYNX_28G_NUM_LANE, -}; - -static const struct lynx_info lynx_info_lx2160a_serdes2 = { - .get_pccr = lynx_28g_get_pccr, - .get_pcvt_offset = lynx_28g_get_pcvt_offset, - .lane_supports_mode = lx2160a_serdes2_lane_supports_mode, - .num_lanes = LYNX_28G_NUM_LANE, -}; - -static const struct lynx_info lynx_info_lx2160a_serdes3 = { - .get_pccr = lynx_28g_get_pccr, - .get_pcvt_offset = lynx_28g_get_pcvt_offset, - .lane_supports_mode = lx2160a_serdes3_lane_supports_mode, - .num_lanes = LYNX_28G_NUM_LANE, -}; - -static const struct lynx_info lynx_info_lx2162a_serdes1 = { - .get_pccr = lynx_28g_get_pccr, - .get_pcvt_offset = lynx_28g_get_pcvt_offset, - .lane_supports_mode = lx2162a_serdes1_lane_supports_mode, - .first_lane = 4, - .num_lanes = LYNX_28G_NUM_LANE, -}; - -static const struct lynx_info lynx_info_lx2162a_serdes2 = { - .get_pccr = lynx_28g_get_pccr, - .get_pcvt_offset = lynx_28g_get_pcvt_offset, - .lane_supports_mode = lx2162a_serdes2_lane_supports_mode, - .num_lanes = LYNX_28G_NUM_LANE, -}; - static void lynx_28g_lane_remap_pll(struct lynx_lane *lane, enum lynx_lane_mode lane_mode) { @@ -1248,6 +1205,49 @@ static int lynx_28g_probe_lane(struct lynx_28g_priv *priv, int id, return 0; } +static const struct lynx_info lynx_info_compat = { + .get_pccr = lynx_28g_get_pccr, + .get_pcvt_offset = lynx_28g_get_pcvt_offset, + .lane_supports_mode = lynx_28g_compat_lane_supports_mode, + .num_lanes = LYNX_28G_NUM_LANE, +}; + +static const struct lynx_info lynx_info_lx2160a_serdes1 = { + .get_pccr = lynx_28g_get_pccr, + .get_pcvt_offset = lynx_28g_get_pcvt_offset, + .lane_supports_mode = lx2160a_serdes1_lane_supports_mode, + .num_lanes = LYNX_28G_NUM_LANE, +}; + +static const struct lynx_info lynx_info_lx2160a_serdes2 = { + .get_pccr = lynx_28g_get_pccr, + .get_pcvt_offset = lynx_28g_get_pcvt_offset, + .lane_supports_mode = lx2160a_serdes2_lane_supports_mode, + .num_lanes = LYNX_28G_NUM_LANE, +}; + +static const struct lynx_info lynx_info_lx2160a_serdes3 = { + .get_pccr = lynx_28g_get_pccr, + .get_pcvt_offset = lynx_28g_get_pcvt_offset, + .lane_supports_mode = lx2160a_serdes3_lane_supports_mode, + .num_lanes = LYNX_28G_NUM_LANE, +}; + +static const struct lynx_info lynx_info_lx2162a_serdes1 = { + .get_pccr = lynx_28g_get_pccr, + .get_pcvt_offset = lynx_28g_get_pcvt_offset, + .lane_supports_mode = lx2162a_serdes1_lane_supports_mode, + .first_lane = 4, + .num_lanes = LYNX_28G_NUM_LANE, +}; + +static const struct lynx_info lynx_info_lx2162a_serdes2 = { + .get_pccr = lynx_28g_get_pccr, + .get_pcvt_offset = lynx_28g_get_pcvt_offset, + .lane_supports_mode = lx2162a_serdes2_lane_supports_mode, + .num_lanes = LYNX_28G_NUM_LANE, +}; + static int lynx_28g_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; From b1c4d866edb7aa62048f5e373586ac8580ef0ec8 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:45 +0300 Subject: [PATCH 72/87] phy: lynx-28g: make lynx_28g_pll_read_configuration() callable per PLL In a future change, lynx_28g_pll_read_configuration() and lynx_28g_lane_read_configuration() will be made methods of struct lynx_info. There is no functional reason, but lynx_28g_lane_read_configuration() is called per lane and lynx_28g_pll_read_configuration() iterates over PLLs internally. So the API exported by the lynx_info structure would not be uniform. Change lynx_28g_pll_read_configuration() to also permit reading the PLL configuration individually, and move the for loop at the call site. Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-10-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 73 ++++++++++++------------ 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index a3fbd31d4dbf..dbbadaa08cb6 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -272,7 +272,6 @@ #define lynx_28g_lane_rmw lynx_lane_rmw #define lynx_28g_lane_read lynx_lane_read #define lynx_28g_lane_write lynx_lane_write -#define lynx_28g_pll_read lynx_pll_read #define lynx_28g_priv lynx_priv #define lynx_28g_lane lynx_lane @@ -1051,49 +1050,41 @@ static const struct phy_ops lynx_28g_ops = { .owner = THIS_MODULE, }; -static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv) +static void lynx_28g_pll_read_configuration(struct lynx_pll *pll) { - struct lynx_28g_pll *pll; u32 val; - int i; - for (i = 0; i < LYNX_28G_NUM_PLL; i++) { - pll = &priv->pll[i]; - pll->priv = priv; - pll->id = i; + val = lynx_pll_read(pll, PLLnRSTCTL); + pll->enabled = !(val & PLLnRSTCTL_DIS); + pll->locked = !!(val & PLLnRSTCTL_LOCK); - val = lynx_28g_pll_read(pll, PLLnRSTCTL); - pll->enabled = !(val & PLLnRSTCTL_DIS); - pll->locked = !!(val & PLLnRSTCTL_LOCK); + val = lynx_pll_read(pll, PLLnCR0); + pll->refclk_sel = FIELD_GET(PLLnCR0_REFCLK_SEL, val); - val = lynx_28g_pll_read(pll, PLLnCR0); - pll->refclk_sel = FIELD_GET(PLLnCR0_REFCLK_SEL, val); + val = lynx_pll_read(pll, PLLnCR1); + pll->frate_sel = FIELD_GET(PLLnCR1_FRATE_SEL, val); - val = lynx_28g_pll_read(pll, PLLnCR1); - pll->frate_sel = FIELD_GET(PLLnCR1_FRATE_SEL, val); + if (!pll->enabled) + return; - if (!pll->enabled) - continue; - - switch (pll->frate_sel) { - case PLLnCR1_FRATE_5G_10GVCO: - case PLLnCR1_FRATE_5G_25GVCO: - /* 5GHz clock net */ - __set_bit(LANE_MODE_1000BASEX_SGMII, pll->supported); - break; - case PLLnCR1_FRATE_10G_20GVCO: - /* 10.3125GHz clock net */ - __set_bit(LANE_MODE_10GBASER, pll->supported); - __set_bit(LANE_MODE_USXGMII, pll->supported); - break; - case PLLnCR1_FRATE_12G_25GVCO: - /* 12.890625GHz clock net */ - __set_bit(LANE_MODE_25GBASER, pll->supported); - break; - default: - /* 6GHz, 8GHz */ - break; - } + switch (pll->frate_sel) { + case PLLnCR1_FRATE_5G_10GVCO: + case PLLnCR1_FRATE_5G_25GVCO: + /* 5GHz clock net */ + __set_bit(LANE_MODE_1000BASEX_SGMII, pll->supported); + break; + case PLLnCR1_FRATE_10G_20GVCO: + /* 10.3125GHz clock net */ + __set_bit(LANE_MODE_10GBASER, pll->supported); + __set_bit(LANE_MODE_USXGMII, pll->supported); + break; + case PLLnCR1_FRATE_12G_25GVCO: + /* 12.890625GHz clock net */ + __set_bit(LANE_MODE_25GBASER, pll->supported); + break; + default: + /* 6GHz, 8GHz */ + break; } } @@ -1291,7 +1282,13 @@ static int lynx_28g_probe(struct platform_device *pdev) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - lynx_28g_pll_read_configuration(priv); + for (int i = 0; i < LYNX_28G_NUM_PLL; i++) { + struct lynx_28g_pll *pll = &priv->pll[i]; + + pll->priv = priv; + pll->id = i; + lynx_28g_pll_read_configuration(pll); + } if (of_get_child_count(dn)) { struct device_node *child; From 719a2da392349db052532db89637622a71d14d49 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:46 +0300 Subject: [PATCH 73/87] phy: lynx-28g: common probe() and remove() Factor the device-agnostic logic from lynx_28g_probe() and lynx_28g_remove() into lynx_probe() and lynx_remove() inside phy-fsl-lynx-core.c. These will be shared with the 10G Lynx driver. Since the PLL configuration, lane configuration and CDR lock detection procedure are going to be different, introduce lynx_info function pointers so that this code remains in the 28G Lynx driver. Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-11-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 225 +++++----------------- drivers/phy/freescale/phy-fsl-lynx-core.c | 170 ++++++++++++++++ drivers/phy/freescale/phy-fsl-lynx-core.h | 12 +- 3 files changed, 227 insertions(+), 180 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index dbbadaa08cb6..50b991870edb 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -12,7 +12,6 @@ #include "phy-fsl-lynx-core.h" #define LYNX_28G_NUM_LANE 8 -#define LYNX_28G_NUM_PLL LYNX_NUM_PLL /* SoC IP wrapper for protocol converters */ #define PCC8 0x10a0 @@ -781,6 +780,30 @@ static bool lynx_28g_compat_lane_supports_mode(int lane, } } +static void lynx_28g_cdr_lock_check(struct lynx_lane *lane) +{ + u32 rrstctl; + int err; + + rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); + if (!!(rrstctl & LNaRRSTCTL_CDR_LOCK)) + return; + + lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_RST_REQ, + LNaRRSTCTL_RST_REQ); + + err = read_poll_timeout(lynx_28g_lane_read, rrstctl, + !!(rrstctl & LNaRRSTCTL_RST_DONE), + LYNX_28G_LANE_RESET_SLEEP_US, + LYNX_28G_LANE_RESET_TIMEOUT_US, + false, lane, LNaRRSTCTL); + if (err) { + dev_warn_once(&lane->phy->dev, + "Lane %c receiver reset failed: %pe\n", + 'A' + lane->id, ERR_PTR(err)); + } +} + static void lynx_28g_lane_remap_pll(struct lynx_lane *lane, enum lynx_lane_mode lane_mode) { @@ -1088,50 +1111,6 @@ static void lynx_28g_pll_read_configuration(struct lynx_pll *pll) } } -#define work_to_lynx(w) container_of((w), struct lynx_28g_priv, cdr_check.work) - -static void lynx_28g_cdr_lock_check(struct work_struct *work) -{ - struct lynx_28g_priv *priv = work_to_lynx(work); - struct lynx_28g_lane *lane; - u32 rrstctl; - int err, i; - - for (i = priv->info->first_lane; i < LYNX_28G_NUM_LANE; i++) { - lane = &priv->lane[i]; - if (!lane->phy) - continue; - - mutex_lock(&lane->phy->mutex); - - if (!lane->init || !lane->powered_up) { - mutex_unlock(&lane->phy->mutex); - continue; - } - - rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); - if (!(rrstctl & LNaRRSTCTL_CDR_LOCK)) { - lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_RST_REQ, - LNaRRSTCTL_RST_REQ); - - err = read_poll_timeout(lynx_28g_lane_read, rrstctl, - !!(rrstctl & LNaRRSTCTL_RST_DONE), - LYNX_28G_LANE_RESET_SLEEP_US, - LYNX_28G_LANE_RESET_TIMEOUT_US, - false, lane, LNaRRSTCTL); - if (err) { - dev_warn_once(&lane->phy->dev, - "Lane %c receiver reset failed: %pe\n", - 'A' + lane->id, ERR_PTR(err)); - } - } - - mutex_unlock(&lane->phy->mutex); - } - queue_delayed_work(system_power_efficient_wq, &priv->cdr_check, - msecs_to_jiffies(1000)); -} - static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane) { u32 pccr, pss, protocol; @@ -1157,49 +1136,13 @@ static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane) } } -static struct phy *lynx_28g_xlate(struct device *dev, - const struct of_phandle_args *args) -{ - struct lynx_28g_priv *priv = dev_get_drvdata(dev); - int idx; - - if (args->args_count == 0) - return of_phy_simple_xlate(dev, args); - else if (args->args_count != 1) - return ERR_PTR(-ENODEV); - - idx = args->args[0]; - - if (WARN_ON(idx >= LYNX_28G_NUM_LANE || - idx < priv->info->first_lane)) - return ERR_PTR(-EINVAL); - - return priv->lane[idx].phy ?: ERR_PTR(-ENODEV); -} - -static int lynx_28g_probe_lane(struct lynx_28g_priv *priv, int id, - struct device_node *dn) -{ - struct lynx_28g_lane *lane = &priv->lane[id]; - struct phy *phy; - - phy = devm_phy_create(priv->dev, dn, &lynx_28g_ops); - if (IS_ERR(phy)) - return PTR_ERR(phy); - - lane->priv = priv; - lane->phy = phy; - lane->id = id; - phy_set_drvdata(phy, lane); - lynx_28g_lane_read_configuration(lane); - - return 0; -} - static const struct lynx_info lynx_info_compat = { .get_pccr = lynx_28g_get_pccr, .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lynx_28g_compat_lane_supports_mode, + .pll_read_configuration = lynx_28g_pll_read_configuration, + .lane_read_configuration = lynx_28g_lane_read_configuration, + .cdr_lock_check = lynx_28g_cdr_lock_check, .num_lanes = LYNX_28G_NUM_LANE, }; @@ -1207,6 +1150,9 @@ static const struct lynx_info lynx_info_lx2160a_serdes1 = { .get_pccr = lynx_28g_get_pccr, .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2160a_serdes1_lane_supports_mode, + .pll_read_configuration = lynx_28g_pll_read_configuration, + .lane_read_configuration = lynx_28g_lane_read_configuration, + .cdr_lock_check = lynx_28g_cdr_lock_check, .num_lanes = LYNX_28G_NUM_LANE, }; @@ -1214,6 +1160,9 @@ static const struct lynx_info lynx_info_lx2160a_serdes2 = { .get_pccr = lynx_28g_get_pccr, .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2160a_serdes2_lane_supports_mode, + .pll_read_configuration = lynx_28g_pll_read_configuration, + .lane_read_configuration = lynx_28g_lane_read_configuration, + .cdr_lock_check = lynx_28g_cdr_lock_check, .num_lanes = LYNX_28G_NUM_LANE, }; @@ -1221,6 +1170,9 @@ static const struct lynx_info lynx_info_lx2160a_serdes3 = { .get_pccr = lynx_28g_get_pccr, .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2160a_serdes3_lane_supports_mode, + .pll_read_configuration = lynx_28g_pll_read_configuration, + .lane_read_configuration = lynx_28g_lane_read_configuration, + .cdr_lock_check = lynx_28g_cdr_lock_check, .num_lanes = LYNX_28G_NUM_LANE, }; @@ -1228,6 +1180,9 @@ static const struct lynx_info lynx_info_lx2162a_serdes1 = { .get_pccr = lynx_28g_get_pccr, .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2162a_serdes1_lane_supports_mode, + .pll_read_configuration = lynx_28g_pll_read_configuration, + .lane_read_configuration = lynx_28g_lane_read_configuration, + .cdr_lock_check = lynx_28g_cdr_lock_check, .first_lane = 4, .num_lanes = LYNX_28G_NUM_LANE, }; @@ -1236,112 +1191,26 @@ static const struct lynx_info lynx_info_lx2162a_serdes2 = { .get_pccr = lynx_28g_get_pccr, .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2162a_serdes2_lane_supports_mode, + .pll_read_configuration = lynx_28g_pll_read_configuration, + .lane_read_configuration = lynx_28g_lane_read_configuration, + .cdr_lock_check = lynx_28g_cdr_lock_check, .num_lanes = LYNX_28G_NUM_LANE, }; static int lynx_28g_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct phy_provider *provider; - struct lynx_28g_priv *priv; - struct device_node *dn; - int err; - - dn = dev_of_node(dev); - if (!dn) { - dev_err(dev, "Device requires an OF node\n"); - return -EINVAL; - } - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->dev = dev; - priv->info = of_device_get_match_data(dev); - if (!priv->info) - return -ENODEV; - - dev_set_drvdata(dev, priv); - spin_lock_init(&priv->pcc_lock); - INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check); + const struct lynx_info *info; /* * If we get here it means we probed on a device tree where * "fsl,lynx-28g" wasn't the fallback, but the sole compatible string. */ - if (priv->info == &lynx_info_compat) + info = of_device_get_match_data(dev); + if (info == &lynx_info_compat) dev_warn(dev, "Please update device tree to use per-device compatible strings\n"); - priv->lane = devm_kcalloc(dev, priv->info->num_lanes, - sizeof(*priv->lane), GFP_KERNEL); - if (!priv->lane) - return -ENOMEM; - - priv->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(priv->base)) - return PTR_ERR(priv->base); - - for (int i = 0; i < LYNX_28G_NUM_PLL; i++) { - struct lynx_28g_pll *pll = &priv->pll[i]; - - pll->priv = priv; - pll->id = i; - lynx_28g_pll_read_configuration(pll); - } - - if (of_get_child_count(dn)) { - struct device_node *child; - - for_each_available_child_of_node(dn, child) { - u32 reg; - - /* PHY subnode name must be 'phy'. */ - if (!(of_node_name_eq(child, "phy"))) - continue; - - if (of_property_read_u32(child, "reg", ®)) { - dev_err(dev, "No \"reg\" property for %pOF\n", child); - of_node_put(child); - return -EINVAL; - } - - if (reg < priv->info->first_lane || reg >= LYNX_28G_NUM_LANE) { - dev_err(dev, "\"reg\" property out of range for %pOF\n", child); - of_node_put(child); - return -EINVAL; - } - - err = lynx_28g_probe_lane(priv, reg, child); - if (err) { - of_node_put(child); - return err; - } - } - } else { - for (int i = priv->info->first_lane; i < LYNX_28G_NUM_LANE; i++) { - err = lynx_28g_probe_lane(priv, i, NULL); - if (err) - return err; - } - } - - provider = devm_of_phy_provider_register(dev, lynx_28g_xlate); - if (IS_ERR(provider)) - return PTR_ERR(provider); - - queue_delayed_work(system_power_efficient_wq, &priv->cdr_check, - msecs_to_jiffies(1000)); - - return 0; -} - -static void lynx_28g_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct lynx_28g_priv *priv = dev_get_drvdata(dev); - - cancel_delayed_work_sync(&priv->cdr_check); + return lynx_probe(pdev, info, &lynx_28g_ops); } static const struct of_device_id lynx_28g_of_match_table[] = { @@ -1357,7 +1226,7 @@ MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table); static struct platform_driver lynx_28g_driver = { .probe = lynx_28g_probe, - .remove = lynx_28g_remove, + .remove = lynx_remove, .driver = { .name = "lynx-28g", .of_match_table = lynx_28g_of_match_table, diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c index 802e32dc6dca..3fb89bb4b0d6 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.c +++ b/drivers/phy/freescale/phy-fsl-lynx-core.c @@ -2,6 +2,7 @@ /* Copyright 2025-2026 NXP */ #include +#include #include "phy-fsl-lynx-core.h" @@ -202,5 +203,174 @@ int lynx_pcvt_rmw(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr, } EXPORT_SYMBOL_NS_GPL(lynx_pcvt_rmw, "PHY_FSL_LYNX"); +#define work_to_lynx(w) container_of((w), struct lynx_priv, cdr_check.work) + +static void lynx_cdr_lock_check(struct work_struct *work) +{ + struct lynx_priv *priv = work_to_lynx(work); + struct lynx_lane *lane; + + for (int i = priv->info->first_lane; i < priv->info->num_lanes; i++) { + lane = &priv->lane[i]; + if (!lane->phy) + continue; + + mutex_lock(&lane->phy->mutex); + + if (!lane->init || !lane->powered_up) { + mutex_unlock(&lane->phy->mutex); + continue; + } + + priv->info->cdr_lock_check(lane); + + mutex_unlock(&lane->phy->mutex); + } + + queue_delayed_work(system_power_efficient_wq, &priv->cdr_check, + msecs_to_jiffies(1000)); +} + +static struct phy *lynx_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct lynx_priv *priv = dev_get_drvdata(dev); + int idx; + + if (args->args_count == 0) + return of_phy_simple_xlate(dev, args); + else if (args->args_count != 1) + return ERR_PTR(-ENODEV); + + idx = args->args[0]; + + if (WARN_ON(idx >= priv->info->num_lanes || + idx < priv->info->first_lane)) + return ERR_PTR(-EINVAL); + + return priv->lane[idx].phy ?: ERR_PTR(-ENODEV); +} + +static int lynx_probe_lane(struct lynx_priv *priv, int id, + struct device_node *dn, + const struct phy_ops *phy_ops) +{ + struct lynx_lane *lane = &priv->lane[id]; + struct phy *phy; + + phy = devm_phy_create(priv->dev, dn, phy_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + lane->priv = priv; + lane->phy = phy; + lane->id = id; + phy_set_drvdata(phy, lane); + priv->info->lane_read_configuration(lane); + + return 0; +} + +int lynx_probe(struct platform_device *pdev, const struct lynx_info *info, + const struct phy_ops *phy_ops) +{ + struct device *dev = &pdev->dev; + struct phy_provider *provider; + struct device_node *dn; + struct lynx_priv *priv; + int err; + + dn = dev_of_node(dev); + if (!dn) { + dev_err(dev, "Device requires an OF node\n"); + return -EINVAL; + } + + if (!info) + return -ENODEV; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->info = info; + dev_set_drvdata(dev, priv); + spin_lock_init(&priv->pcc_lock); + INIT_DELAYED_WORK(&priv->cdr_check, lynx_cdr_lock_check); + + priv->lane = devm_kcalloc(dev, priv->info->num_lanes, + sizeof(*priv->lane), GFP_KERNEL); + if (!priv->lane) + return -ENOMEM; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + for (int i = 0; i < LYNX_NUM_PLL; i++) { + struct lynx_pll *pll = &priv->pll[i]; + + pll->priv = priv; + pll->id = i; + priv->info->pll_read_configuration(pll); + } + + if (of_get_child_count(dn)) { + struct device_node *child; + + for_each_available_child_of_node(dn, child) { + u32 reg; + + /* PHY subnode name must be 'phy'. */ + if (!(of_node_name_eq(child, "phy"))) + continue; + + if (of_property_read_u32(child, "reg", ®)) { + dev_err(dev, "No \"reg\" property for %pOF\n", child); + of_node_put(child); + return -EINVAL; + } + + if (reg < priv->info->first_lane || reg >= priv->info->num_lanes) { + dev_err(dev, "\"reg\" property out of range for %pOF\n", child); + of_node_put(child); + return -EINVAL; + } + + err = lynx_probe_lane(priv, reg, child, phy_ops); + if (err) { + of_node_put(child); + return err; + } + } + } else { + for (int i = priv->info->first_lane; i < priv->info->num_lanes; i++) { + err = lynx_probe_lane(priv, i, NULL, phy_ops); + if (err) + return err; + } + } + + provider = devm_of_phy_provider_register(dev, lynx_xlate); + if (IS_ERR(provider)) + return PTR_ERR(provider); + + queue_delayed_work(system_power_efficient_wq, &priv->cdr_check, + msecs_to_jiffies(1000)); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(lynx_probe, "PHY_FSL_LYNX"); + +void lynx_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct lynx_priv *priv = dev_get_drvdata(dev); + + cancel_delayed_work_sync(&priv->cdr_check); +} +EXPORT_SYMBOL_NS_GPL(lynx_remove, "PHY_FSL_LYNX"); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Freescale Lynx SerDes core functionality"); diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.h b/drivers/phy/freescale/phy-fsl-lynx-core.h index 5cd86c9543cb..e8b280cc9b38 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.h +++ b/drivers/phy/freescale/phy-fsl-lynx-core.h @@ -10,14 +10,15 @@ #define LYNX_NUM_PLL 2 +struct lynx_priv; +struct lynx_lane; + struct lynx_pccr { int offset; int width; int shift; }; -struct lynx_priv; - struct lynx_pll { struct lynx_priv *priv; int id; @@ -42,6 +43,9 @@ struct lynx_info { struct lynx_pccr *pccr); int (*get_pcvt_offset)(int lane, enum lynx_lane_mode mode); bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode); + void (*pll_read_configuration)(struct lynx_pll *pll); + void (*lane_read_configuration)(struct lynx_lane *lane); + void (*cdr_lock_check)(struct lynx_lane *lane); int first_lane; int num_lanes; }; @@ -85,6 +89,10 @@ static inline void lynx_rmw(struct lynx_priv *priv, unsigned long off, u32 val, #define lynx_pll_read(pll, reg) \ ioread32((pll)->priv->base + reg((pll)->id)) +int lynx_probe(struct platform_device *pdev, const struct lynx_info *info, + const struct phy_ops *phy_ops); +void lynx_remove(struct platform_device *pdev); + const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode); enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf); bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode); From c6c1d7dfd59b181b96b0909b63e140b0aa61ac59 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:47 +0300 Subject: [PATCH 74/87] phy: lynx-28g: add support for big endian register maps Some 10G Lynx SerDes blocks are big endian and require byte swapping because the CPUs are little endian armv8 (LS1046A). Parse the "big-endian" device tree property, and modify the base lynx_read() and lynx_write() accessors to test this property before issuing either the ioread32() or ioread32be() variants (as per Documentation/driver-api/device-io.rst). All other accessors - lynx_rmw(), lynx_lane_read(), lynx_lane_write(), lynx_lane_rmw(), lynx_pll_read() - need to go through these endian-aware helpers. Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-12-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-core.c | 1 + drivers/phy/freescale/phy-fsl-lynx-core.h | 36 ++++++++++++++++------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c index 3fb89bb4b0d6..226b2af2b599 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.c +++ b/drivers/phy/freescale/phy-fsl-lynx-core.c @@ -295,6 +295,7 @@ int lynx_probe(struct platform_device *pdev, const struct lynx_info *info, priv->dev = dev; priv->info = info; + priv->big_endian = device_property_read_bool(dev, "big-endian"); dev_set_drvdata(dev, priv); spin_lock_init(&priv->pcc_lock); INIT_DELAYED_WORK(&priv->cdr_check, lynx_cdr_lock_check); diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.h b/drivers/phy/freescale/phy-fsl-lynx-core.h index e8b280cc9b38..d82e529fa65a 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.h +++ b/drivers/phy/freescale/phy-fsl-lynx-core.h @@ -58,36 +58,52 @@ struct lynx_priv { * like PCCn */ spinlock_t pcc_lock; + bool big_endian; struct lynx_pll pll[LYNX_NUM_PLL]; struct lynx_lane *lane; struct delayed_work cdr_check; }; +static inline u32 lynx_read(struct lynx_priv *priv, unsigned long off) +{ + void __iomem *reg = priv->base + off; + + if (priv->big_endian) + return ioread32be(reg); + + return ioread32(reg); +} + +static inline void lynx_write(struct lynx_priv *priv, unsigned long off, u32 val) +{ + void __iomem *reg = priv->base + off; + + if (priv->big_endian) + return iowrite32be(val, reg); + + return iowrite32(val, reg); +} + static inline void lynx_rmw(struct lynx_priv *priv, unsigned long off, u32 val, u32 mask) { - void __iomem *reg = priv->base + off; u32 orig, tmp; - orig = ioread32(reg); + orig = lynx_read(priv, off); tmp = orig & ~mask; tmp |= val; - iowrite32(tmp, reg); + lynx_write(priv, off, tmp); } -#define lynx_read(priv, off) \ - ioread32((priv)->base + (off)) -#define lynx_write(priv, off, val) \ - iowrite32(val, (priv)->base + (off)) #define lynx_lane_rmw(lane, reg, val, mask) \ lynx_rmw((lane)->priv, reg(lane->id), val, mask) #define lynx_lane_read(lane, reg) \ - ioread32((lane)->priv->base + reg((lane)->id)) + lynx_read((lane)->priv, reg((lane)->id)) #define lynx_lane_write(lane, reg, val) \ - iowrite32(val, (lane)->priv->base + reg((lane)->id)) + lynx_write((lane)->priv, reg((lane)->id), val) #define lynx_pll_read(pll, reg) \ - ioread32((pll)->priv->base + reg((pll)->id)) + lynx_read((pll)->priv, reg((pll)->id)) int lynx_probe(struct platform_device *pdev, const struct lynx_info *info, const struct phy_ops *phy_ops); From f64ef1995dd6f902da0bd3bc60c72c825098b652 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:48 +0300 Subject: [PATCH 75/87] phy: lynx-28g: optimize read-modify-write operation It is unnecessary to rewrite a register if the masked field already contains the desired value upon reading. The hardware behaviour does not depend upon register writes with identical values. Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-13-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-core.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.h b/drivers/phy/freescale/phy-fsl-lynx-core.h index d82e529fa65a..3d9508dfb2c1 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.h +++ b/drivers/phy/freescale/phy-fsl-lynx-core.h @@ -93,7 +93,8 @@ static inline void lynx_rmw(struct lynx_priv *priv, unsigned long off, u32 val, orig = lynx_read(priv, off); tmp = orig & ~mask; tmp |= val; - lynx_write(priv, off, tmp); + if (orig != tmp) + lynx_write(priv, off, tmp); } #define lynx_lane_rmw(lane, reg, val, mask) \ From f124b54b19223c85dabd9421ec622d8256e240de Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:49 +0300 Subject: [PATCH 76/87] phy: lynx-28g: improve phy_validate() procedure lynx_28g_validate() suffers from the following shortcomings: - Changing the protocol should not be possible if the source protocol of the lane is unsupported. This is because lynx_28g_proto_conf[] only covers the register deltas between any pair of supported lane modes, but that delta is probably incomplete if the source protocol is, say, PCIe (which is currently assimilated by the driver to LANE_MODE_UNKNOWN). lynx_28g_proto_conf() does refuse changing the protocol if the current one is unsupported, but we shouldn't advertise it via phy_validate() at all. The phy_set_mode_ext() call should perform the exact same verifications as phy_validate() did, in case the caller bypassed phy_validate(). So we need to centralize the logic into a common validation. But lynx_28g_set_mode() later needs the lane_mode that this validation needs to compute anyway, so name the common helper lynx_phy_mode_to_lane_mode() and let it return that lane_mode. - Future core sanity checks on phy_validate() will want to differentiate the case where this optional method is not implemented from the case where the mode/submode is really not supported. So we shouldn't return -EOPNOTSUPP from lynx_28g_validate(), but -EINVAL to signal that we do implement the operation: https://lore.kernel.org/linux-phy/aY2lFTIALH7qEJmM@shell.armlinux.org.uk/ Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-14-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 38 +++++++---------------- drivers/phy/freescale/phy-fsl-lynx-core.c | 30 ++++++++++++++++++ drivers/phy/freescale/phy-fsl-lynx-core.h | 2 ++ 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 50b991870edb..38afcd081a2a 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -968,22 +968,22 @@ static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane, return err; } +static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode, + union phy_configure_opts *opts) +{ + return lynx_phy_mode_to_lane_mode(phy, mode, submode, NULL); +} + static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode) { - struct lynx_28g_lane *lane = phy_get_drvdata(phy); + struct lynx_lane *lane = phy_get_drvdata(phy); int powered_up = lane->powered_up; enum lynx_lane_mode lane_mode; - int err = 0; + int err; - if (mode != PHY_MODE_ETHERNET) - return -EOPNOTSUPP; - - if (lane->mode == LANE_MODE_UNKNOWN) - return -EOPNOTSUPP; - - lane_mode = phy_interface_to_lane_mode(submode); - if (!lynx_lane_supports_mode(lane, lane_mode)) - return -EOPNOTSUPP; + err = lynx_phy_mode_to_lane_mode(phy, mode, submode, &lane_mode); + if (err) + return err; if (lane_mode == lane->mode) return 0; @@ -1014,22 +1014,6 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode) return err; } -static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode, - union phy_configure_opts *opts __always_unused) -{ - struct lynx_28g_lane *lane = phy_get_drvdata(phy); - enum lynx_lane_mode lane_mode; - - if (mode != PHY_MODE_ETHERNET) - return -EOPNOTSUPP; - - lane_mode = phy_interface_to_lane_mode(submode); - if (!lynx_lane_supports_mode(lane, lane_mode)) - return -EOPNOTSUPP; - - return 0; -} - static int lynx_28g_init(struct phy *phy) { struct lynx_28g_lane *lane = phy_get_drvdata(phy); diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c index 226b2af2b599..1e411bfab404 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.c +++ b/drivers/phy/freescale/phy-fsl-lynx-core.c @@ -89,6 +89,36 @@ bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode) } EXPORT_SYMBOL_NS_GPL(lynx_lane_supports_mode, "PHY_FSL_LYNX"); +/* Translate the mode/submode from phy_validate() and phy_set_mode_ext() to a + * lane_mode and return 0 if it is supported and we can transition to it from + * the current lane mode, or return negative error otherwise. + */ +int lynx_phy_mode_to_lane_mode(struct phy *phy, enum phy_mode mode, + int submode, enum lynx_lane_mode *lane_mode) +{ + struct lynx_lane *lane = phy_get_drvdata(phy); + enum lynx_lane_mode tmp_lane_mode; + + /* The protocol configuration tables are incomplete for full lane + * reconfiguration from an arbitrary protocol. + */ + if (lane->mode == LANE_MODE_UNKNOWN) + return -EINVAL; + + if (mode != PHY_MODE_ETHERNET) + return -EINVAL; + + tmp_lane_mode = phy_interface_to_lane_mode(submode); + if (!lynx_lane_supports_mode(lane, tmp_lane_mode)) + return -EINVAL; + + if (lane_mode) + *lane_mode = tmp_lane_mode; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(lynx_phy_mode_to_lane_mode, "PHY_FSL_LYNX"); + struct lynx_pll *lynx_pll_get(struct lynx_priv *priv, enum lynx_lane_mode mode) { struct lynx_pll *pll; diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.h b/drivers/phy/freescale/phy-fsl-lynx-core.h index 3d9508dfb2c1..37fa4b544faa 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.h +++ b/drivers/phy/freescale/phy-fsl-lynx-core.h @@ -113,6 +113,8 @@ void lynx_remove(struct platform_device *pdev); const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode); enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf); bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode); +int lynx_phy_mode_to_lane_mode(struct phy *phy, enum phy_mode mode, + int submode, enum lynx_lane_mode *lane_mode); struct lynx_pll *lynx_pll_get(struct lynx_priv *priv, enum lynx_lane_mode mode); From a7dc4e95d31c6bc674b24697aacadf7c6f1cbe6a Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:50 +0300 Subject: [PATCH 77/87] dt-bindings: phy: lynx-10g: initial document Add a schema for the 10G Lynx SerDes. This is very similar to the modern form of the 28G Lynx SerDes, which is very much the intention. There is intentionally no generic fsl,lynx-10g compatible string due to the hardware inability to report its capabilities, despite having a common register map. We allow both forms of #phy-cells = <1> in the top-level provider and #phy-cells = <0> in the per-lane provider for more flexibility to consumers, and because the kernel code is shared with the 28G Lynx which already has that support for compatibility reasons. Signed-off-by: Vladimir Oltean Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260610151952.2141019-15-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/fsl,lynx-10g.yaml | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/fsl,lynx-10g.yaml diff --git a/Documentation/devicetree/bindings/phy/fsl,lynx-10g.yaml b/Documentation/devicetree/bindings/phy/fsl,lynx-10g.yaml new file mode 100644 index 000000000000..2e7d0abfa71a --- /dev/null +++ b/Documentation/devicetree/bindings/phy/fsl,lynx-10g.yaml @@ -0,0 +1,139 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/fsl,lynx-10g.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale Lynx 10G SerDes PHY + +maintainers: + - Vladimir Oltean + +description: + The 10G Lynx is a multi-protocol SerDes block which handles networking, PCIe, + SATA and other high-speed interfaces. It is present on most QorIQ and + Layerscape SoCs. The register map is common, but the integration is + SoC-specific, with the differences consisting in register endianness, the + number of lanes, protocol converters available per lane and their location in + the PCCR registers. Some SoCs have multiple SerDes blocks and those differ in + their protocol capabilities per lane. + +properties: + compatible: + enum: + - fsl,ls1028a-serdes + - fsl,ls1046a-serdes1 + - fsl,ls1046a-serdes2 + - fsl,ls1088a-serdes1 + - fsl,ls1088a-serdes2 + - fsl,ls2088a-serdes1 + - fsl,ls2088a-serdes2 + + reg: + maxItems: 1 + + big-endian: true + + "#phy-cells": + const: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^phy@[0-7]$": + type: object + description: SerDes lane (single RX/TX differential pair) + + properties: + reg: + minimum: 0 + maximum: 7 + description: Lane index as seen in register map + + "#phy-cells": + const: 0 + + required: + - reg + - "#phy-cells" + + additionalProperties: false + +required: + - compatible + - reg + - "#phy-cells" + - "#address-cells" + - "#size-cells" + +allOf: + - if: + properties: + compatible: + contains: + enum: + - fsl,ls1028a-serdes + - fsl,ls1046a-serdes1 + - fsl,ls1046a-serdes2 + - fsl,ls1088a-serdes1 + - fsl,ls1088a-serdes2 + then: + patternProperties: + "^phy@[0-7]$": + properties: + reg: + minimum: 0 + maximum: 3 + - if: + properties: + compatible: + enum: + - fsl,ls1046a-serdes1 + - fsl,ls1046a-serdes2 + then: + required: + - big-endian + else: + properties: + big-endian: false + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + + serdes@1ea0000 { + compatible = "fsl,ls1028a-serdes"; + reg = <0x0 0x1ea0000 0x0 0xffff>; + #address-cells = <1>; + #size-cells = <0>; + #phy-cells = <1>; + + phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + + phy@2 { + reg = <2>; + #phy-cells = <0>; + }; + + phy@3 { + reg = <3>; + #phy-cells = <0>; + }; + }; + }; From 6dc92ba487a21b923eb409357ffe966a6e9d2343 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:51 +0300 Subject: [PATCH 78/87] phy: lynx-10g: new driver Introduce a driver for the networking lanes of the 10G Lynx SerDes block, present on the majority of Layerscape and QorIQ (Freescale/NXP) SoCs. As with the 28G Lynx, the SerDes lanes come pre-initialized out of reset and the consumers use them that way outside the Generic PHY framework (for networking, the static configuration remains for the entire SoC lifetime, whereas for SATA and PCIe, the hardware reconfigures itself automatically for other link speeds). The need for the Generic PHY framework comes specifically for networking use cases where a static lane configuration is not sufficient. For example a network MAC is connected to an SFP cage, where various SFP or SFP+ modules can be connected. Each of them may require a different SerDes protocol (SGMII, 1000Base-X, 10GBase-R), which phylink + sfp-bus are responsible of figuring out. The phylink drivers are: - enetc - felix - dpaa_eth (fman_memac) - dpaa2-eth - dpaa2-switch and they all need to reconfigure the SerDes for the requested link mode, using phy_set_mode_ext() (and phy_validate() to see if it is supported in the first place). Note that SerDes 2 on LS1088A is exclusively non-networking, so there is currently no need for this driver. Therefore we skip matching on its compatible string and do not probe on that device. Co-developed-by: Ioana Ciornei Signed-off-by: Ioana Ciornei Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-16-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/Kconfig | 10 + drivers/phy/freescale/Makefile | 1 + drivers/phy/freescale/phy-fsl-lynx-10g.c | 1321 +++++++++++++++++++++ drivers/phy/freescale/phy-fsl-lynx-core.c | 38 + drivers/phy/freescale/phy-fsl-lynx-core.h | 4 + include/soc/fsl/phy-fsl-lynx.h | 27 + 6 files changed, 1401 insertions(+) create mode 100644 drivers/phy/freescale/phy-fsl-lynx-10g.c diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig index ac575d531db7..5bf3864fbe64 100644 --- a/drivers/phy/freescale/Kconfig +++ b/drivers/phy/freescale/Kconfig @@ -54,6 +54,16 @@ endif config PHY_FSL_LYNX_CORE tristate +config PHY_FSL_LYNX_10G + tristate "Freescale Layerscape Lynx 10G SerDes PHY support" + depends on OF + depends on ARCH_LAYERSCAPE || COMPILE_TEST + select GENERIC_PHY + select PHY_FSL_LYNX_CORE + help + Enable this to add support for the Lynx 10G SerDes PHY as found on + NXP's Layerscape platform such as LS1088A or LS1028A. + config PHY_FSL_LYNX_28G tristate "Freescale Layerscape Lynx 28G SerDes PHY support" depends on OF diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile index d7aa62cdeb39..5b0e180d6972 100644 --- a/drivers/phy/freescale/Makefile +++ b/drivers/phy/freescale/Makefile @@ -5,5 +5,6 @@ obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o obj-$(CONFIG_PHY_FSL_IMX8M_PCIE) += phy-fsl-imx8m-pcie.o obj-$(CONFIG_PHY_FSL_IMX8QM_HSIO) += phy-fsl-imx8qm-hsio.o obj-$(CONFIG_PHY_FSL_LYNX_CORE) += phy-fsl-lynx-core.o +obj-$(CONFIG_PHY_FSL_LYNX_10G) += phy-fsl-lynx-10g.o obj-$(CONFIG_PHY_FSL_LYNX_28G) += phy-fsl-lynx-28g.o obj-$(CONFIG_PHY_FSL_SAMSUNG_HDMI_PHY) += phy-fsl-samsung-hdmi.o diff --git a/drivers/phy/freescale/phy-fsl-lynx-10g.c b/drivers/phy/freescale/phy-fsl-lynx-10g.c new file mode 100644 index 000000000000..38def160ef1a --- /dev/null +++ b/drivers/phy/freescale/phy-fsl-lynx-10g.c @@ -0,0 +1,1321 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright 2021-2026 NXP */ + +#include +#include +#include +#include +#include +#include +#include + +#include "phy-fsl-lynx-core.h" + +/* SoC IP wrapper for protocol converters */ +#define PCCR8 0x220 +#define PCCR8_SGMIIa_KX BIT(3) +#define PCCR8_SGMIIa_CFG GENMASK(2, 0) + +#define PCCR9 0x224 +#define PCCR9_QSGMIIa_CFG GENMASK(2, 0) +#define PCCR9_QXGMIIa_CFG GENMASK(2, 0) + +#define PCCRB 0x22c +#define PCCRB_XFIa_CFG GENMASK(2, 0) +#define PCCRB_SXGMIIa_CFG GENMASK(2, 0) + +#define SGMII_CFG(id) (28 - (id) * 4) +#define QSGMII_CFG(id) (28 - (id) * 4) +#define SXGMII_CFG(id) (28 - (id) * 4) +#define QXGMII_CFG(id) (12 - (id) * 4) +#define XFI_CFG(id) (28 - (id) * 4) + +#define CR(x) ((x) * 4) + +#define A 0 +#define B 1 +#define C 2 +#define D 3 +#define E 4 +#define F 5 +#define G 6 +#define H 7 + +#define SGMIIaCR0(id) (0x1800 + (id) * 0x10) +#define QSGMIIaCR0(id) (0x1880 + (id) * 0x10) +#define XAUIaCR0(id) (0x1900 + (id) * 0x10) +#define XFIaCR0(id) (0x1980 + (id) * 0x10) +#define SXGMIIaCR0(id) (0x1a80 + (id) * 0x10) +#define QXGMIIaCR0(id) (0x1b00 + (id) * 0x20) + +#define SGMIIaCR0_RST_SGM BIT(31) +#define SGMIIaCR0_RST_SGM_OFF SGMIIaCR0_RST_SGM +#define SGMIIaCR0_RST_SGM_ON 0 +#define SGMIIaCR0_PD_SGM BIT(30) +#define SGMIIaCR1_SGPCS_EN BIT(11) +#define SGMIIaCR1_SGPCS_DIS 0x0 + +#define QSGMIIaCR0_RST_QSGM BIT(31) +#define QSGMIIaCR0_RST_QSGM_OFF QSGMIIaCR0_RST_QSGM +#define QSGMIIaCR0_RST_QSGM_ON 0 +#define QSGMIIaCR0_PD_QSGM BIT(30) + +/* Per PLL registers */ +#define PLLnCR0(pll) ((pll) * 0x20 + 0x4) + +#define PLLnCR0_POFF BIT(31) + +#define PLLnCR0_REFCLK_SEL GENMASK(30, 28) +#define PLLnCR0_REFCLK_SEL_100MHZ 0x0 +#define PLLnCR0_REFCLK_SEL_125MHZ 0x1 +#define PLLnCR0_REFCLK_SEL_156MHZ 0x2 +#define PLLnCR0_REFCLK_SEL_150MHZ 0x3 +#define PLLnCR0_REFCLK_SEL_161MHZ 0x4 +#define PLLnCR0_PLL_LCK BIT(23) +#define PLLnCR0_FRATE_SEL GENMASK(19, 16) +#define PLLnCR0_FRATE_5G 0x0 +#define PLLnCR0_FRATE_5_15625G 0x6 +#define PLLnCR0_FRATE_4G 0x7 +#define PLLnCR0_FRATE_3_125G 0x9 +#define PLLnCR0_FRATE_3G 0xa + +/* Per SerDes lane registers */ + +/* Lane a Protocol Select status register */ +#define LNaPSSR0(lane) (0x100 + (lane) * 0x20) +#define LNaPSSR0_TYPE GENMASK(30, 26) +#define LNaPSSR0_IS_QUAD GENMASK(25, 24) +#define LNaPSSR0_MAC GENMASK(19, 16) +#define LNaPSSR0_PCS GENMASK(10, 8) +#define LNaPSSR0_LANE GENMASK(2, 0) + +/* Lane a General Control Register */ +#define LNaGCR0(lane) (0x800 + (lane) * 0x40 + 0x0) +#define LNaGCR0_RPLL_PLLF BIT(31) +#define LNaGCR0_RPLL_PLLS 0x0 +#define LNaGCR0_RPLL_MSK BIT(31) +#define LNaGCR0_RRAT_SEL GENMASK(29, 28) +#define LNaGCR0_TRAT_SEL GENMASK(25, 24) +#define LNaGCR0_TPLL_PLLF BIT(27) +#define LNaGCR0_TPLL_PLLS 0x0 +#define LNaGCR0_TPLL_MSK BIT(27) +#define LNaGCR0_RRST_OFF LNaGCR0_RRST +#define LNaGCR0_TRST_OFF LNaGCR0_TRST +#define LNaGCR0_RRST_ON 0x0 +#define LNaGCR0_TRST_ON 0x0 +#define LNaGCR0_RRST BIT(22) +#define LNaGCR0_TRST BIT(21) +#define LNaGCR0_RX_PD BIT(20) +#define LNaGCR0_TX_PD BIT(19) +#define LNaGCR0_IF20BIT_EN BIT(18) +#define LNaGCR0_PROTS GENMASK(11, 7) + +#define LNaGCR1(lane) (0x800 + (lane) * 0x40 + 0x4) +#define LNaGCR1_RDAT_INV BIT(31) +#define LNaGCR1_TDAT_INV BIT(30) +#define LNaGCR1_OPAD_CTL BIT(26) +#define LNaGCR1_REIDL_TH GENMASK(22, 20) +#define LNaGCR1_REIDL_EX_SEL GENMASK(19, 18) +#define LNaGCR1_REIDL_ET_SEL GENMASK(17, 16) +#define LNaGCR1_REIDL_EX_MSB BIT(15) +#define LNaGCR1_REIDL_ET_MSB BIT(14) +#define LNaGCR1_REQ_CTL_SNP BIT(13) +#define LNaGCR1_REQ_CDR_SNP BIT(12) +#define LNaGCR1_TRSTDIR BIT(7) +#define LNaGCR1_REQ_BIN_SNP BIT(6) +#define LNaGCR1_ISLEW_RCTL GENMASK(5, 4) +#define LNaGCR1_OSLEW_RCTL GENMASK(1, 0) + +#define LNaRECR0(lane) (0x800 + (lane) * 0x40 + 0x10) +#define LNaRECR0_RXEQ_BST BIT(28) +#define LNaRECR0_GK2OVD GENMASK(27, 24) +#define LNaRECR0_GK3OVD GENMASK(19, 16) +#define LNaRECR0_GK2OVD_EN BIT(15) +#define LNaRECR0_GK3OVD_EN BIT(14) +#define LNaRECR0_OSETOVD_EN BIT(13) +#define LNaRECR0_BASE_WAND GENMASK(11, 10) +#define LNaRECR0_OSETOVD GENMASK(6, 0) + +#define LNaTECR0(lane) (0x800 + (lane) * 0x40 + 0x18) +#define LNaTECR0_TEQ_TYPE GENMASK(29, 28) +#define LNaTECR0_SGN_PREQ BIT(26) +#define LNaTECR0_RATIO_PREQ GENMASK(25, 22) +#define LNaTECR0_SGN_POST1Q BIT(21) +#define LNaTECR0_RATIO_PST1Q GENMASK(20, 16) +#define LNaTECR0_ADPT_EQ GENMASK(13, 8) +#define LNaTECR0_AMP_RED GENMASK(5, 0) + +#define LNaTTLCR0(lane) (0x800 + (lane) * 0x40 + 0x20) +#define LNaTTLCR1(lane) (0x800 + (lane) * 0x40 + 0x24) +#define LNaTTLCR2(lane) (0x800 + (lane) * 0x40 + 0x28) + +#define LNaTCSR3(lane) (0x800 + (lane) * 0x40 + 0x3C) +#define LNaTCSR3_CDR_LCK BIT(27) + +enum lynx_10g_rat_sel { + RAT_SEL_FULL = 0x0, + RAT_SEL_HALF = 0x1, + RAT_SEL_QUARTER = 0x2, + RAT_SEL_DOUBLE = 0x3, +}; + +enum lynx_10g_eq_type { + EQ_TYPE_NO_EQ = 0, + EQ_TYPE_2TAP = 1, + EQ_TYPE_3TAP = 2, +}; + +enum lynx_10g_proto_sel { + PROTO_SEL_PCIE = 0, + PROTO_SEL_SGMII_BASEX_KX_QSGMII = 1, + PROTO_SEL_SATA = 2, + PROTO_SEL_XAUI = 4, + PROTO_SEL_XFI_10GBASER_KR_SXGMII = 0xa, +}; + +struct lynx_10g_proto_conf { + int proto_sel; + int if20bit_en; + int reidl_th; + int reidl_et_msb; + int reidl_et_sel; + int reidl_ex_msb; + int reidl_ex_sel; + int islew_rctl; + int oslew_rctl; + int rxeq_bst; + int gk2ovd; + int gk3ovd; + int gk2ovd_en; + int gk3ovd_en; + int base_wand; + int teq_type; + int sgn_preq; + int ratio_preq; + int sgn_post1q; + int ratio_post1q; + int adpt_eq; + int amp_red; + int ttlcr0; +}; + +static const struct lynx_10g_proto_conf lynx_10g_proto_conf[LANE_MODE_MAX] = { + [LANE_MODE_1000BASEX_SGMII] = { + .proto_sel = PROTO_SEL_SGMII_BASEX_KX_QSGMII, + .reidl_th = 1, + .reidl_ex_sel = 3, + .reidl_et_msb = 1, + .islew_rctl = 1, + .oslew_rctl = 1, + .gk2ovd = 15, + .gk3ovd = 15, + .gk2ovd_en = 1, + .gk3ovd_en = 1, + .teq_type = EQ_TYPE_NO_EQ, + .adpt_eq = 48, + .amp_red = 6, + .ttlcr0 = 0x39000400, + }, + [LANE_MODE_2500BASEX] = { + .proto_sel = PROTO_SEL_SGMII_BASEX_KX_QSGMII, + .islew_rctl = 2, + .oslew_rctl = 2, + .teq_type = EQ_TYPE_2TAP, + .sgn_post1q = 1, + .ratio_post1q = 6, + .adpt_eq = 48, + .ttlcr0 = 0x00000400, + }, + [LANE_MODE_QSGMII] = { + .proto_sel = PROTO_SEL_SGMII_BASEX_KX_QSGMII, + .islew_rctl = 1, + .oslew_rctl = 1, + .teq_type = EQ_TYPE_2TAP, + .sgn_post1q = 1, + .ratio_post1q = 6, + .adpt_eq = 48, + .amp_red = 2, + .ttlcr0 = 0x00000400, + }, + [LANE_MODE_10G_QXGMII] = { + .proto_sel = PROTO_SEL_XFI_10GBASER_KR_SXGMII, + .if20bit_en = 1, + .islew_rctl = 1, + .oslew_rctl = 1, + .base_wand = 1, + .teq_type = EQ_TYPE_NO_EQ, + .adpt_eq = 48, + .ttlcr0 = 0x00000400, + }, + [LANE_MODE_USXGMII] = { + .proto_sel = PROTO_SEL_XFI_10GBASER_KR_SXGMII, + .if20bit_en = 1, + .islew_rctl = 1, + .oslew_rctl = 1, + .base_wand = 1, + .teq_type = EQ_TYPE_NO_EQ, + .sgn_post1q = 1, + .adpt_eq = 48, + .ttlcr0 = 0x00000400, + }, + [LANE_MODE_10GBASER] = { + .proto_sel = PROTO_SEL_XFI_10GBASER_KR_SXGMII, + .if20bit_en = 1, + .islew_rctl = 2, + .oslew_rctl = 2, + .rxeq_bst = 1, + .base_wand = 1, + .teq_type = EQ_TYPE_2TAP, + .sgn_post1q = 1, + .ratio_post1q = 3, + .adpt_eq = 48, + .amp_red = 7, + .ttlcr0 = 0x00000400, + }, +}; + +static void lynx_10g_cdr_lock_check(struct lynx_lane *lane) +{ + u32 tcsr3 = lynx_lane_read(lane, LNaTCSR3); + + if (tcsr3 & LNaTCSR3_CDR_LCK) + return; + + dev_dbg(&lane->phy->dev, + "Lane %c CDR unlocked, resetting receiver...\n", + 'A' + lane->id); + + lynx_lane_rmw(lane, LNaGCR0, LNaGCR0_RRST_ON, LNaGCR0_RRST); + usleep_range(1, 2); + lynx_lane_rmw(lane, LNaGCR0, LNaGCR0_RRST_OFF, LNaGCR0_RRST); + + usleep_range(1, 2); +} + +static void lynx_10g_pll_read_configuration(struct lynx_pll *pll) +{ + u32 val; + + val = lynx_pll_read(pll, PLLnCR0); + pll->frate_sel = FIELD_GET(PLLnCR0_FRATE_SEL, val); + pll->refclk_sel = FIELD_GET(PLLnCR0_REFCLK_SEL, val); + pll->enabled = !(val & PLLnCR0_POFF); + pll->locked = !!(val & PLLnCR0_PLL_LCK); + + if (!pll->enabled) + return; + + switch (pll->frate_sel) { + case PLLnCR0_FRATE_5G: + /* 5GHz clock net */ + __set_bit(LANE_MODE_1000BASEX_SGMII, pll->supported); + __set_bit(LANE_MODE_QSGMII, pll->supported); + break; + case PLLnCR0_FRATE_3_125G: + __set_bit(LANE_MODE_2500BASEX, pll->supported); + break; + case PLLnCR0_FRATE_5_15625G: + /* 10.3125GHz clock net */ + __set_bit(LANE_MODE_10GBASER, pll->supported); + __set_bit(LANE_MODE_USXGMII, pll->supported); + __set_bit(LANE_MODE_10G_QXGMII, pll->supported); + break; + default: + break; + } +} + +/* On LS1028A, SGMIIA_CFG, SGMIIB_CFG, and SGMIIC_CFG from PCCR8 have the + * ability to map either an ENETC PCS (PCCR8_SGMIIa_CFG=2) or a Felix switch + * PCS (PCCR8_SGMIIa_CFG=1) to the same lane. + * + * On LS1088A, the same QSGMII PCS B can be connected to SerDes lane 1 + * (PCCR9_QSGMIIa_CFG=1) or to lane 3 (PCCR9_QSGMIIa_CFG=2). + * + * The PHY API lacks the capability to distinguish anything about the consumer, + * so we don't support changing the initial muxing done by the RCW. + * + * However, after disabling a PCS through PCCR8, we need to properly restore + * the original value to keep the same muxing, and for that we need to back + * it up (here). + */ +static void lynx_10g_backup_pccr_val(struct lynx_lane *lane) +{ + u32 val; + int err; + + if (lane->mode == LANE_MODE_UNKNOWN) + return; + + err = lynx_pccr_read(lane, lane->mode, &val); + if (err) { + dev_warn(&lane->phy->dev, + "The driver doesn't know how to access the PCCR for lane mode %s\n", + lynx_lane_mode_str(lane->mode)); + lane->mode = LANE_MODE_UNKNOWN; + return; + } + + lane->default_pccr[lane->mode] = val; + + /* 1000Base-X, 1000Base-KX, 2500Base-KX and SGMII use the same PCCR8. + * Only the KX bit differs (set for 1000Base-KX). Since we back up PCCR + * values per lane mode, make sure to not back up the PCCR8 value with + * the KX bit set for the non-KX modes, if the lane was in KX mode at + * boot time. Just preserve bits 2:0, which tell whether the (and + * which) 1G PCS was enabled. + */ + switch (lane->mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + lane->default_pccr[LANE_MODE_1000BASEX_SGMII] = val & ~PCCR8_SGMIIa_KX; + lane->default_pccr[LANE_MODE_2500BASEX] = val & ~PCCR8_SGMIIa_KX; + break; + default: + break; + } +} + +/* Is the PCS enabled, according to the value backed up from the PCCR register + * for this lane mode? + * + * Normally we'd need to ask "what lane mode are we talking about?", but the + * answer is invariably the same regardless - PCCR8_SGMIIa_CFG has the same + * layout as PCCR9_QSGMIIa_CFG, PCCRB_XFIa_CFG etc etc, and the value 0 + * universally means "PCS disabled". So this is just a shorthand answer. + */ +static bool lynx_10g_pccr_val_enabled(u32 pccr) +{ + return FIELD_PREP(PCCR8_SGMIIa_CFG, pccr) != 0; +} + +static bool lynx_10g_lane_is_3_125g(struct lynx_lane *lane) +{ + struct lynx_priv *priv = lane->priv; + struct lynx_pll *pll; + u32 gcr0; + + gcr0 = lynx_lane_read(lane, LNaGCR0); + + if (gcr0 & LNaGCR0_TPLL_PLLF) + pll = &priv->pll[0]; + else + pll = &priv->pll[1]; + + if (pll->frate_sel != PLLnCR0_FRATE_3_125G) + return false; + + if (FIELD_GET(LNaGCR0_TRAT_SEL, gcr0) != RAT_SEL_FULL || + FIELD_GET(LNaGCR0_RRAT_SEL, gcr0) != RAT_SEL_FULL) + return false; + + return true; +} + +static void lynx_10g_lane_read_configuration(struct lynx_lane *lane) +{ + u32 pssr0 = lynx_lane_read(lane, LNaPSSR0); + struct lynx_priv *priv = lane->priv; + int proto; + + proto = FIELD_GET(LNaPSSR0_TYPE, pssr0); + switch (proto) { + case PROTO_SEL_SGMII_BASEX_KX_QSGMII: + if (lynx_10g_lane_is_3_125g(lane)) + lane->mode = LANE_MODE_2500BASEX; + else if (FIELD_GET(LNaPSSR0_IS_QUAD, pssr0)) + lane->mode = LANE_MODE_QSGMII; + else + lane->mode = LANE_MODE_1000BASEX_SGMII; + break; + case PROTO_SEL_XFI_10GBASER_KR_SXGMII: + if (FIELD_GET(LNaPSSR0_IS_QUAD, pssr0)) + lane->mode = LANE_MODE_10G_QXGMII; + else if (priv->info->quirks & LYNX_QUIRK_HAS_HARDCODED_USXGMII) + lane->mode = LANE_MODE_USXGMII; + else + lane->mode = LANE_MODE_10GBASER; + break; + case PROTO_SEL_PCIE: + case PROTO_SEL_SATA: + case PROTO_SEL_XAUI: + break; + default: + dev_warn(&lane->phy->dev, "Unknown lane protocol 0x%x\n", + proto); + } + + lynx_10g_backup_pccr_val(lane); +} + +static int ls1028a_get_pccr(enum lynx_lane_mode lane_mode, int lane, + struct lynx_pccr *pccr) +{ + switch (lane_mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + pccr->offset = PCCR8; + pccr->width = 4; + pccr->shift = SGMII_CFG(lane); + break; + case LANE_MODE_QSGMII: + if (lane != 1) + return -EINVAL; + + pccr->offset = PCCR9; + pccr->width = 3; + pccr->shift = QSGMII_CFG(A); + break; + case LANE_MODE_10G_QXGMII: + if (lane != 1) + return -EINVAL; + + pccr->offset = PCCR9; + pccr->width = 3; + pccr->shift = QXGMII_CFG(A); + break; + case LANE_MODE_USXGMII: + if (lane != 0) + return -EINVAL; + + pccr->offset = PCCRB; + pccr->width = 3; + pccr->shift = SXGMII_CFG(A); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ls1028a_get_pcvt_offset(int lane, enum lynx_lane_mode mode) +{ + switch (mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + return SGMIIaCR0(lane); + case LANE_MODE_QSGMII: + return lane == 1 ? QSGMIIaCR0(A) : -EINVAL; + case LANE_MODE_USXGMII: + return lane == 0 ? SXGMIIaCR0(A) : -EINVAL; + case LANE_MODE_10G_QXGMII: + return lane == 1 ? QXGMIIaCR0(A) : -EINVAL; + default: + return -EINVAL; + } +} + +static const struct lynx_info lynx_info_ls1028a = { + .get_pccr = ls1028a_get_pccr, + .get_pcvt_offset = ls1028a_get_pcvt_offset, + .pll_read_configuration = lynx_10g_pll_read_configuration, + .lane_read_configuration = lynx_10g_lane_read_configuration, + .cdr_lock_check = lynx_10g_cdr_lock_check, + .num_lanes = 4, + .index = 1, + .quirks = LYNX_QUIRK_HAS_HARDCODED_USXGMII, +}; + +static int ls1046a_serdes1_get_pccr(enum lynx_lane_mode lane_mode, int lane, + struct lynx_pccr *pccr) +{ + switch (lane_mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + pccr->offset = PCCR8; + pccr->width = 4; + pccr->shift = SGMII_CFG(lane); + break; + case LANE_MODE_QSGMII: + if (lane != 1) + return -EINVAL; + + pccr->offset = PCCR9; + pccr->width = 3; + pccr->shift = QSGMII_CFG(B); + break; + case LANE_MODE_10GBASER: + switch (lane) { + case 2: + pccr->shift = XFI_CFG(A); + break; + case 3: + pccr->shift = XFI_CFG(B); + break; + default: + return -EINVAL; + } + + pccr->offset = PCCRB; + pccr->width = 3; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ls1046a_serdes1_get_pcvt_offset(int lane, enum lynx_lane_mode mode) +{ + switch (mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + return SGMIIaCR0(lane); + case LANE_MODE_QSGMII: + if (lane != 1) + return -EINVAL; + + return QSGMIIaCR0(B); + case LANE_MODE_10GBASER: + switch (lane) { + case 2: + return XFIaCR0(A); + case 3: + return XFIaCR0(B); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static const struct lynx_info lynx_info_ls1046a_serdes1 = { + .get_pccr = ls1046a_serdes1_get_pccr, + .get_pcvt_offset = ls1046a_serdes1_get_pcvt_offset, + .pll_read_configuration = lynx_10g_pll_read_configuration, + .lane_read_configuration = lynx_10g_lane_read_configuration, + .cdr_lock_check = lynx_10g_cdr_lock_check, + .num_lanes = 4, + .index = 1, +}; + +static int ls1046a_serdes2_get_pccr(enum lynx_lane_mode lane_mode, int lane, + struct lynx_pccr *pccr) +{ + switch (lane_mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + if (lane != 1) + return -EINVAL; + + pccr->offset = PCCR8; + pccr->width = 4; + pccr->shift = SGMII_CFG(B); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ls1046a_serdes2_get_pcvt_offset(int lane, enum lynx_lane_mode mode) +{ + switch (mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + if (lane != 1) + return -EINVAL; + + return SGMIIaCR0(B); + default: + return -EINVAL; + } +} + +static const struct lynx_info lynx_info_ls1046a_serdes2 = { + .get_pccr = ls1046a_serdes2_get_pccr, + .get_pcvt_offset = ls1046a_serdes2_get_pcvt_offset, + .pll_read_configuration = lynx_10g_pll_read_configuration, + .lane_read_configuration = lynx_10g_lane_read_configuration, + .cdr_lock_check = lynx_10g_cdr_lock_check, + .num_lanes = 4, + .index = 2, +}; + +static int ls1088a_serdes1_get_pccr(enum lynx_lane_mode lane_mode, int lane, + struct lynx_pccr *pccr) +{ + switch (lane_mode) { + case LANE_MODE_1000BASEX_SGMII: + pccr->offset = PCCR8; + pccr->width = 4; + pccr->shift = SGMII_CFG(lane); + break; + case LANE_MODE_QSGMII: + switch (lane) { + case 0: + pccr->shift = QSGMII_CFG(A); + break; + case 1: + case 3: + pccr->shift = QSGMII_CFG(B); + break; + default: + return -EINVAL; + } + + pccr->offset = PCCR9; + pccr->width = 3; + break; + case LANE_MODE_10GBASER: + switch (lane) { + case 2: + pccr->shift = XFI_CFG(A); + break; + case 3: + pccr->shift = XFI_CFG(B); + break; + default: + return -EINVAL; + } + + pccr->offset = PCCRB; + pccr->width = 3; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ls1088a_serdes1_get_pcvt_offset(int lane, enum lynx_lane_mode mode) +{ + switch (mode) { + case LANE_MODE_1000BASEX_SGMII: + return SGMIIaCR0(lane); + case LANE_MODE_QSGMII: + switch (lane) { + case 0: + return QSGMIIaCR0(A); + case 1: + case 3: + return QSGMIIaCR0(B); + default: + return -EINVAL; + } + case LANE_MODE_10GBASER: + switch (lane) { + case 2: + return XFIaCR0(A); + case 3: + return XFIaCR0(B); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static const struct lynx_info lynx_info_ls1088a_serdes1 = { + .get_pccr = ls1088a_serdes1_get_pccr, + .get_pcvt_offset = ls1088a_serdes1_get_pcvt_offset, + .pll_read_configuration = lynx_10g_pll_read_configuration, + .lane_read_configuration = lynx_10g_lane_read_configuration, + .cdr_lock_check = lynx_10g_cdr_lock_check, + .num_lanes = 4, + .index = 1, +}; + +static int ls2088a_serdes1_get_pccr(enum lynx_lane_mode lane_mode, int lane, + struct lynx_pccr *pccr) +{ + switch (lane_mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + pccr->offset = PCCR8; + pccr->width = 4; + pccr->shift = SGMII_CFG(lane); + break; + case LANE_MODE_QSGMII: + switch (lane) { + case 2: + case 6: + pccr->shift = QSGMII_CFG(A); + break; + case 7: + pccr->shift = QSGMII_CFG(B); + break; + case 0: + case 4: + pccr->shift = QSGMII_CFG(C); + break; + case 1: + case 5: + pccr->shift = QSGMII_CFG(D); + break; + default: + return -EINVAL; + } + + pccr->offset = PCCR9; + pccr->width = 3; + break; + case LANE_MODE_10GBASER: + pccr->offset = PCCRB; + pccr->width = 3; + pccr->shift = XFI_CFG(lane); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ls2088a_serdes1_get_pcvt_offset(int lane, enum lynx_lane_mode mode) +{ + switch (mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + return SGMIIaCR0(lane); + case LANE_MODE_QSGMII: + switch (lane) { + case 2: + case 6: + return QSGMIIaCR0(A); + case 7: + return QSGMIIaCR0(B); + case 0: + case 4: + return QSGMIIaCR0(C); + case 1: + case 5: + return QSGMIIaCR0(D); + default: + return -EINVAL; + } + case LANE_MODE_10GBASER: + return XFIaCR0(lane); + default: + return -EINVAL; + } +} + +static const struct lynx_info lynx_info_ls2088a_serdes1 = { + .get_pccr = ls2088a_serdes1_get_pccr, + .get_pcvt_offset = ls2088a_serdes1_get_pcvt_offset, + .pll_read_configuration = lynx_10g_pll_read_configuration, + .lane_read_configuration = lynx_10g_lane_read_configuration, + .cdr_lock_check = lynx_10g_cdr_lock_check, + .num_lanes = 8, + .index = 1, +}; + +static int ls2088a_serdes2_get_pccr(enum lynx_lane_mode lane_mode, int lane, + struct lynx_pccr *pccr) +{ + switch (lane_mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + pccr->offset = PCCR8; + pccr->width = 4; + pccr->shift = SGMII_CFG(lane); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ls2088a_serdes2_get_pcvt_offset(int lane, enum lynx_lane_mode mode) +{ + switch (mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + return SGMIIaCR0(lane); + default: + return -EINVAL; + } +} + +static const struct lynx_info lynx_info_ls2088a_serdes2 = { + .get_pccr = ls2088a_serdes2_get_pccr, + .get_pcvt_offset = ls2088a_serdes2_get_pcvt_offset, + .pll_read_configuration = lynx_10g_pll_read_configuration, + .lane_read_configuration = lynx_10g_lane_read_configuration, + .cdr_lock_check = lynx_10g_cdr_lock_check, + .num_lanes = 8, + .index = 2, +}; + +/* Halting puts the lane in a mode in which it can be reconfigured */ +static void lynx_10g_lane_halt(struct phy *phy) +{ + struct lynx_lane *lane = phy_get_drvdata(phy); + + /* Issue a reset request */ + lynx_lane_rmw(lane, LNaGCR0, + LNaGCR0_RRST_ON | LNaGCR0_TRST_ON, + LNaGCR0_RRST | LNaGCR0_TRST); + + /* The RM says to wait for at least 50ns */ + usleep_range(1, 2); +} + +static void lynx_10g_lane_reset(struct phy *phy) +{ + struct lynx_lane *lane = phy_get_drvdata(phy); + + /* Finalize the reset request */ + lynx_lane_rmw(lane, LNaGCR0, + LNaGCR0_RRST_OFF | LNaGCR0_TRST_OFF, + LNaGCR0_RRST | LNaGCR0_TRST); +} + +static int lynx_10g_power_off(struct phy *phy) +{ + struct lynx_lane *lane = phy_get_drvdata(phy); + + if (!lane->powered_up) + return 0; + + /* Issue a reset request with the power down bits set */ + lynx_lane_rmw(lane, LNaGCR0, + LNaGCR0_RRST_ON | LNaGCR0_TRST_ON | + LNaGCR0_RX_PD | LNaGCR0_TX_PD, + LNaGCR0_RRST | LNaGCR0_TRST | + LNaGCR0_RX_PD | LNaGCR0_TX_PD); + + /* The RM says to wait for at least 50ns */ + usleep_range(1, 2); + + lane->powered_up = false; + + return 0; +} + +static int lynx_10g_power_on(struct phy *phy) +{ + struct lynx_lane *lane = phy_get_drvdata(phy); + + if (lane->powered_up) + return 0; + + /* RM says that to enable a previously powered down lane, set + * LNmGCR0[{R,T}X_PD]=0, wait 15 us, then set LNmGCR0[{R,T}RST]=1. + */ + lynx_lane_rmw(lane, LNaGCR0, 0, LNaGCR0_RX_PD | LNaGCR0_TX_PD); + usleep_range(150, 300); + lynx_10g_lane_reset(phy); + + lane->powered_up = true; + + return 0; +} + +static void lynx_10g_lane_set_nrate(struct lynx_lane *lane, + struct lynx_pll *pll, + enum lynx_lane_mode mode) +{ + enum lynx_10g_rat_sel nrate; + + switch (pll->frate_sel) { + case PLLnCR0_FRATE_5G: + switch (mode) { + case LANE_MODE_1000BASEX_SGMII: + nrate = RAT_SEL_QUARTER; + break; + case LANE_MODE_QSGMII: + nrate = RAT_SEL_FULL; + break; + default: + return; + } + break; + case PLLnCR0_FRATE_3_125G: + switch (mode) { + case LANE_MODE_2500BASEX: + nrate = RAT_SEL_FULL; + break; + default: + return; + } + break; + case PLLnCR0_FRATE_5_15625G: + switch (mode) { + case LANE_MODE_10GBASER: + case LANE_MODE_USXGMII: + case LANE_MODE_10G_QXGMII: + nrate = RAT_SEL_DOUBLE; + break; + default: + return; + } + break; + default: + return; + } + + lynx_lane_rmw(lane, LNaGCR0, + FIELD_PREP(LNaGCR0_TRAT_SEL, nrate) | + FIELD_PREP(LNaGCR0_RRAT_SEL, nrate), + LNaGCR0_RRAT_SEL | LNaGCR0_TRAT_SEL); +} + +static void lynx_10g_lane_set_pll(struct lynx_lane *lane, + struct lynx_pll *pll) +{ + if (pll->id == 0) { + lynx_lane_rmw(lane, LNaGCR0, + LNaGCR0_RPLL_PLLF | LNaGCR0_TPLL_PLLF, + LNaGCR0_RPLL_MSK | LNaGCR0_TPLL_MSK); + } else { + lynx_lane_rmw(lane, LNaGCR0, + LNaGCR0_RPLL_PLLS | LNaGCR0_TPLL_PLLS, + LNaGCR0_RPLL_MSK | LNaGCR0_TPLL_MSK); + } +} + +static void lynx_10g_lane_remap_pll(struct lynx_lane *lane, + enum lynx_lane_mode lane_mode) +{ + struct lynx_priv *priv = lane->priv; + struct lynx_pll *pll; + + /* Switch to the PLL that works with this interface type */ + pll = lynx_pll_get(priv, lane_mode); + if (unlikely(!pll)) + return; + + lynx_10g_lane_set_pll(lane, pll); + + /* Choose the portion of clock net to be used on this lane */ + lynx_10g_lane_set_nrate(lane, pll, lane_mode); +} + +static void lynx_10g_lane_change_proto_conf(struct lynx_lane *lane, + enum lynx_lane_mode mode) +{ + const struct lynx_10g_proto_conf *conf = &lynx_10g_proto_conf[mode]; + + lynx_lane_rmw(lane, LNaGCR0, + FIELD_PREP(LNaGCR0_PROTS, conf->proto_sel) | + FIELD_PREP(LNaGCR0_IF20BIT_EN, conf->if20bit_en), + LNaGCR0_PROTS | LNaGCR0_IF20BIT_EN); + lynx_lane_rmw(lane, LNaGCR1, + FIELD_PREP(LNaGCR1_REIDL_TH, conf->reidl_th) | + FIELD_PREP(LNaGCR1_REIDL_ET_MSB, conf->reidl_et_msb) | + FIELD_PREP(LNaGCR1_REIDL_ET_SEL, conf->reidl_et_sel) | + FIELD_PREP(LNaGCR1_REIDL_EX_MSB, conf->reidl_ex_msb) | + FIELD_PREP(LNaGCR1_REIDL_EX_SEL, conf->reidl_ex_sel) | + FIELD_PREP(LNaGCR1_ISLEW_RCTL, conf->islew_rctl) | + FIELD_PREP(LNaGCR1_OSLEW_RCTL, conf->oslew_rctl), + LNaGCR1_REIDL_TH | + LNaGCR1_REIDL_ET_MSB | LNaGCR1_REIDL_ET_SEL | + LNaGCR1_REIDL_EX_MSB | LNaGCR1_REIDL_EX_SEL | + LNaGCR1_ISLEW_RCTL | LNaGCR1_OSLEW_RCTL); + lynx_lane_rmw(lane, LNaRECR0, + FIELD_PREP(LNaRECR0_RXEQ_BST, conf->rxeq_bst) | + FIELD_PREP(LNaRECR0_GK2OVD, conf->gk2ovd) | + FIELD_PREP(LNaRECR0_GK3OVD, conf->gk3ovd) | + FIELD_PREP(LNaRECR0_GK2OVD_EN, conf->gk2ovd_en) | + FIELD_PREP(LNaRECR0_GK3OVD_EN, conf->gk3ovd_en) | + FIELD_PREP(LNaRECR0_BASE_WAND, conf->base_wand), + LNaRECR0_RXEQ_BST | LNaRECR0_GK2OVD | LNaRECR0_GK3OVD | + LNaRECR0_GK2OVD_EN | LNaRECR0_GK3OVD_EN | + LNaRECR0_BASE_WAND); + lynx_lane_rmw(lane, LNaTECR0, + FIELD_PREP(LNaTECR0_TEQ_TYPE, conf->teq_type) | + FIELD_PREP(LNaTECR0_SGN_PREQ, conf->sgn_preq) | + FIELD_PREP(LNaTECR0_RATIO_PREQ, conf->ratio_preq) | + FIELD_PREP(LNaTECR0_SGN_POST1Q, conf->sgn_post1q) | + FIELD_PREP(LNaTECR0_RATIO_PST1Q, conf->ratio_post1q) | + FIELD_PREP(LNaTECR0_ADPT_EQ, conf->adpt_eq) | + FIELD_PREP(LNaTECR0_AMP_RED, conf->amp_red), + LNaTECR0_TEQ_TYPE | LNaTECR0_SGN_PREQ | + LNaTECR0_RATIO_PREQ | LNaTECR0_SGN_POST1Q | + LNaTECR0_RATIO_PST1Q | LNaTECR0_ADPT_EQ | + LNaTECR0_AMP_RED); + lynx_lane_write(lane, LNaTTLCR0, conf->ttlcr0); +} + +static int lynx_10g_lane_disable_pcvt(struct lynx_lane *lane, + enum lynx_lane_mode mode) +{ + struct lynx_priv *priv = lane->priv; + int err; + + spin_lock(&priv->pcc_lock); + + err = lynx_pccr_write(lane, mode, 0); + if (err) + goto out; + + switch (mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + err = lynx_pcvt_rmw(lane, mode, CR(1), SGMIIaCR1_SGPCS_DIS, + SGMIIaCR1_SGPCS_EN); + if (err) + goto out; + + lynx_pcvt_rmw(lane, mode, CR(0), + SGMIIaCR0_RST_SGM_ON | SGMIIaCR0_PD_SGM, + SGMIIaCR0_RST_SGM | SGMIIaCR0_PD_SGM); + break; + case LANE_MODE_QSGMII: + err = lynx_pcvt_rmw(lane, mode, CR(0), + QSGMIIaCR0_RST_QSGM_ON | QSGMIIaCR0_PD_QSGM, + QSGMIIaCR0_RST_QSGM | QSGMIIaCR0_PD_QSGM); + if (err) + goto out; + break; + default: + err = 0; + } + +out: + spin_unlock(&priv->pcc_lock); + + return err; +} + +static int lynx_10g_lane_enable_pcvt(struct lynx_lane *lane, + enum lynx_lane_mode mode) +{ + struct lynx_priv *priv = lane->priv; + u32 val; + int err; + + spin_lock(&priv->pcc_lock); + + switch (mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + err = lynx_pcvt_rmw(lane, mode, CR(1), SGMIIaCR1_SGPCS_EN, + SGMIIaCR1_SGPCS_EN); + if (err) + goto out; + + lynx_pcvt_rmw(lane, mode, CR(0), SGMIIaCR0_RST_SGM_OFF, + SGMIIaCR0_RST_SGM | SGMIIaCR0_PD_SGM); + break; + case LANE_MODE_QSGMII: + err = lynx_pcvt_rmw(lane, mode, CR(0), QSGMIIaCR0_RST_QSGM_OFF, + QSGMIIaCR0_RST_QSGM | QSGMIIaCR0_PD_QSGM); + if (err) + goto out; + break; + default: + err = 0; + } + + /* If the PCS was enabled at boot time, use the backed up PCCR value to + * re-enable it here, to preserve the muxing. + */ + if (lynx_10g_pccr_val_enabled(lane->default_pccr[mode])) { + err = lynx_pccr_write(lane, mode, lane->default_pccr[mode]); + goto out; + } + + /* If the PCS was not enabled, set the PCCR to a default value which + * enables it (1). The assumption is that this is the only PCS <-> + * SerDes lane muxing value possible. + * + * This is mostly useful for SGMII <-> 10GBase-R major protocol + * reconfiguration, where at boot time, either the SGMII or the + * 10GBase-R PCS is enabled for the lane, but not both. + * + * In fact, if there are multiple lane muxing options, this function + * will most likely not choose the right one. For correct functionality + * there, we assume that the PCS we are enabling here was found enabled + * at boot time (reset default, or through PBL, or...), and we preserve + * its muxing through the default_pccr branch above. + */ + val = 0; + + switch (mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + val |= FIELD_PREP(PCCR8_SGMIIa_CFG, 1); + break; + case LANE_MODE_QSGMII: + val |= FIELD_PREP(PCCR9_QSGMIIa_CFG, 1); + break; + case LANE_MODE_10G_QXGMII: + val |= FIELD_PREP(PCCR9_QXGMIIa_CFG, 1); + break; + case LANE_MODE_10GBASER: + val |= FIELD_PREP(PCCRB_XFIa_CFG, 1); + break; + case LANE_MODE_USXGMII: + val |= FIELD_PREP(PCCRB_SXGMIIa_CFG, 1); + break; + default: + err = 0; + goto out; + } + + err = lynx_pccr_write(lane, mode, val); +out: + spin_unlock(&priv->pcc_lock); + + return err; +} + +static bool lynx_10g_lane_mode_needs_rcw_override(struct lynx_lane *lane, + enum lynx_lane_mode new) +{ + enum lynx_lane_mode curr = lane->mode; + + /* Major protocol changes, which involve changing the PCS connection to + * the GMII MAC with the one to the XGMII MAC, require an RCW override + * procedure to reconfigure an internal mux, as documented here: + * https://lore.kernel.org/linux-phy/20230810102631.bvozjer3t67r67iy@skbuf/ + * This is SoC-specific, and not yet implemented in drivers/soc/fsl/guts.c. + * + * So the supported set of protocols depends on the initial lane mode. + * + * Minor protocol changes (SGMII <-> 1000Base-X <-> 2500Base-X or + * 10GBase-R <-> USXGMII) are supported. + */ + if ((lynx_lane_mode_uses_gmii_mac(curr) && + lynx_lane_mode_uses_xgmii_mac(new)) || + (lynx_lane_mode_uses_xgmii_mac(curr) && + lynx_lane_mode_uses_gmii_mac(new))) + return true; + + return false; +} + +static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode, + union phy_configure_opts *opts) +{ + struct lynx_lane *lane = phy_get_drvdata(phy); + enum lynx_lane_mode lane_mode; + int err; + + err = lynx_phy_mode_to_lane_mode(phy, mode, submode, &lane_mode); + if (err) + return err; + + if (lynx_10g_lane_mode_needs_rcw_override(lane, lane_mode)) + return -EINVAL; + + return 0; +} + +static int lynx_10g_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct lynx_lane *lane = phy_get_drvdata(phy); + bool powered_up = lane->powered_up; + enum lynx_lane_mode lane_mode; + int err; + + err = lynx_10g_validate(phy, mode, submode, NULL); + if (err) + return err; + + lane_mode = phy_interface_to_lane_mode(submode); + /* lynx_10g_validate() already made sure the lane_mode is supported */ + + if (lane_mode == lane->mode) + return 0; + + /* If the lane is powered up, put the lane into the halt state while + * the reconfiguration is being done. + */ + if (powered_up) + lynx_10g_lane_halt(phy); + + err = lynx_10g_lane_disable_pcvt(lane, lane->mode); + if (err) + goto out; + + lynx_10g_lane_change_proto_conf(lane, lane_mode); + lynx_10g_lane_remap_pll(lane, lane_mode); + WARN_ON(lynx_10g_lane_enable_pcvt(lane, lane_mode)); + + lane->mode = lane_mode; + +out: + if (powered_up) { + /* The RM says to wait for at least 120 ns */ + usleep_range(1, 2); + lynx_10g_lane_reset(phy); + } + + return err; +} + +static int lynx_10g_init(struct phy *phy) +{ + struct lynx_lane *lane = phy_get_drvdata(phy); + + /* Mark the fact that the lane was init */ + lane->init = true; + + /* SerDes lanes are powered on at boot time. Any lane that is + * managed by this driver will get powered off when its consumer + * calls phy_init(). + */ + lane->powered_up = true; + lynx_10g_power_off(phy); + + return 0; +} + +static int lynx_10g_exit(struct phy *phy) +{ + struct lynx_lane *lane = phy_get_drvdata(phy); + + /* The lane returns to the state where it isn't managed by the + * consumer, so we must treat is as if it isn't initialized, and always + * powered on. + */ + lane->init = false; + lane->powered_up = false; + lynx_10g_power_on(phy); + + return 0; +} + +static const struct phy_ops lynx_10g_ops = { + .init = lynx_10g_init, + .exit = lynx_10g_exit, + .power_on = lynx_10g_power_on, + .power_off = lynx_10g_power_off, + .set_mode = lynx_10g_set_mode, + .validate = lynx_10g_validate, + .owner = THIS_MODULE, +}; + +static int lynx_10g_probe(struct platform_device *pdev) +{ + return lynx_probe(pdev, of_device_get_match_data(&pdev->dev), + &lynx_10g_ops); +} + +static const struct of_device_id lynx_10g_of_match_table[] = { + { .compatible = "fsl,ls1028a-serdes", .data = &lynx_info_ls1028a }, + { .compatible = "fsl,ls1046a-serdes1", .data = &lynx_info_ls1046a_serdes1 }, + { .compatible = "fsl,ls1046a-serdes2", .data = &lynx_info_ls1046a_serdes2 }, + { .compatible = "fsl,ls1088a-serdes1", .data = &lynx_info_ls1088a_serdes1 }, + { .compatible = "fsl,ls2088a-serdes1", .data = &lynx_info_ls2088a_serdes1 }, + { .compatible = "fsl,ls2088a-serdes2", .data = &lynx_info_ls2088a_serdes2 }, + {} +}; +MODULE_DEVICE_TABLE(of, lynx_10g_of_match_table); + +static struct platform_driver lynx_10g_driver = { + .probe = lynx_10g_probe, + .remove = lynx_remove, + .driver = { + .name = "lynx-10g", + .of_match_table = lynx_10g_of_match_table, + }, +}; +module_platform_driver(lynx_10g_driver); + +MODULE_IMPORT_NS("PHY_FSL_LYNX"); +MODULE_AUTHOR("Ioana Ciornei "); +MODULE_AUTHOR("Vladimir Oltean "); +MODULE_DESCRIPTION("Lynx 10G SerDes PHY driver for Layerscape SoCs"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c index 1e411bfab404..2cfe9236ffc5 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.c +++ b/drivers/phy/freescale/phy-fsl-lynx-core.c @@ -11,6 +11,12 @@ const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode) switch (lane_mode) { case LANE_MODE_1000BASEX_SGMII: return "1000Base-X/SGMII"; + case LANE_MODE_2500BASEX: + return "2500Base-X"; + case LANE_MODE_QSGMII: + return "QSGMII"; + case LANE_MODE_10G_QXGMII: + return "10G-QXGMII"; case LANE_MODE_10GBASER: return "10GBase-R"; case LANE_MODE_USXGMII: @@ -29,6 +35,12 @@ enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf) case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_1000BASEX: return LANE_MODE_1000BASEX_SGMII; + case PHY_INTERFACE_MODE_2500BASEX: + return LANE_MODE_2500BASEX; + case PHY_INTERFACE_MODE_QSGMII: + return LANE_MODE_QSGMII; + case PHY_INTERFACE_MODE_10G_QXGMII: + return LANE_MODE_10G_QXGMII; case PHY_INTERFACE_MODE_10GBASER: return LANE_MODE_10GBASER; case PHY_INTERFACE_MODE_USXGMII: @@ -89,6 +101,29 @@ bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode) } EXPORT_SYMBOL_NS_GPL(lynx_lane_supports_mode, "PHY_FSL_LYNX"); +/* The quad protocols are fixed because the lane has multiple consumers, and + * one phy_set_mode_ext() affects the other consumers as well. We have no use + * case for dynamic protocol changing here, so disallow it. + */ +static enum lynx_lane_mode lynx_fixed_protocols[] = { + LANE_MODE_QSGMII, + LANE_MODE_10G_QXGMII, +}; + +static bool lynx_lane_restrict_fixed_mode_change(struct lynx_lane *lane, + enum lynx_lane_mode new) +{ + enum lynx_lane_mode curr = lane->mode; + + for (int i = 0; i < ARRAY_SIZE(lynx_fixed_protocols); i++) + if ((curr == lynx_fixed_protocols[i] || + new == lynx_fixed_protocols[i]) && + curr != new) + return true; + + return false; +} + /* Translate the mode/submode from phy_validate() and phy_set_mode_ext() to a * lane_mode and return 0 if it is supported and we can transition to it from * the current lane mode, or return negative error otherwise. @@ -112,6 +147,9 @@ int lynx_phy_mode_to_lane_mode(struct phy *phy, enum phy_mode mode, if (!lynx_lane_supports_mode(lane, tmp_lane_mode)) return -EINVAL; + if (lynx_lane_restrict_fixed_mode_change(lane, tmp_lane_mode)) + return -EINVAL; + if (lane_mode) *lane_mode = tmp_lane_mode; diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.h b/drivers/phy/freescale/phy-fsl-lynx-core.h index 37fa4b544faa..a60429ba9324 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-core.h +++ b/drivers/phy/freescale/phy-fsl-lynx-core.h @@ -9,6 +9,7 @@ #include #define LYNX_NUM_PLL 2 +#define LYNX_QUIRK_HAS_HARDCODED_USXGMII BIT(0) struct lynx_priv; struct lynx_lane; @@ -36,6 +37,7 @@ struct lynx_lane { bool init; unsigned int id; enum lynx_lane_mode mode; + u32 default_pccr[LANE_MODE_MAX]; }; struct lynx_info { @@ -48,6 +50,8 @@ struct lynx_info { void (*cdr_lock_check)(struct lynx_lane *lane); int first_lane; int num_lanes; + int index; + unsigned long quirks; }; struct lynx_priv { diff --git a/include/soc/fsl/phy-fsl-lynx.h b/include/soc/fsl/phy-fsl-lynx.h index 92e8272d5ae1..ff5a7d1835b5 100644 --- a/include/soc/fsl/phy-fsl-lynx.h +++ b/include/soc/fsl/phy-fsl-lynx.h @@ -7,10 +7,37 @@ enum lynx_lane_mode { LANE_MODE_UNKNOWN, LANE_MODE_1000BASEX_SGMII, + LANE_MODE_2500BASEX, + LANE_MODE_QSGMII, + LANE_MODE_10G_QXGMII, LANE_MODE_10GBASER, LANE_MODE_USXGMII, LANE_MODE_25GBASER, LANE_MODE_MAX, }; +static inline bool lynx_lane_mode_uses_gmii_mac(enum lynx_lane_mode mode) +{ + switch (mode) { + case LANE_MODE_1000BASEX_SGMII: + case LANE_MODE_2500BASEX: + case LANE_MODE_QSGMII: + case LANE_MODE_10G_QXGMII: + return true; + default: + return false; + } +} + +static inline bool lynx_lane_mode_uses_xgmii_mac(enum lynx_lane_mode mode) +{ + switch (mode) { + case LANE_MODE_10GBASER: + case LANE_MODE_USXGMII: + return true; + default: + return false; + } +} + #endif /* __PHY_FSL_LYNX_H_ */ From 61df73e12eb245adc54606de287cf8898b3a66c4 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 10 Jun 2026 18:19:52 +0300 Subject: [PATCH 79/87] MAINTAINERS: expand Lynx 28G entry to cover Lynx 10G SerDes The lynx-28g and lynx-10g drivers share code and hardware architecture, so let them be covered by a single MAINTAINERS entry. Add myself as a second maintainer alongside Ioana Ciornei. Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260610151952.2141019-17-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul --- MAINTAINERS | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 06563ce3f459..50f45492a600 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15284,12 +15284,18 @@ S: Maintained F: Documentation/devicetree/bindings/iio/light/liteon,ltr390.yaml F: drivers/iio/light/ltr390.c -LYNX 28G SERDES PHY DRIVER +LYNX SERDES PHY DRIVERS M: Ioana Ciornei +M: Vladimir Oltean L: netdev@vger.kernel.org S: Supported +F: Documentation/devicetree/bindings/phy/fsl,lynx-10g.yaml F: Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml +F: drivers/phy/freescale/phy-fsl-lynx-10g.c F: drivers/phy/freescale/phy-fsl-lynx-28g.c +F: drivers/phy/freescale/phy-fsl-lynx-core.c +F: drivers/phy/freescale/phy-fsl-lynx-core.h +F: include/soc/fsl/phy-fsl-lynx.h LYNX PCS MODULE M: Ioana Ciornei From b28ec8ce03d8f9a0f7a9ec84f1ed9b5a6f393791 Mon Sep 17 00:00:00 2001 From: Felix Gu Date: Tue, 9 Jun 2026 22:48:50 +0800 Subject: [PATCH 80/87] phy: freescale: phy-fsl-imx8qm-lvds-phy: Use synchronous PM runtime put in reset The mixel_lvds_phy_reset() function pairs pm_runtime_resume_and_get() with pm_runtime_put(). The asynchronous variant queues a work item to handle the idle check and potential suspend, which can be cancelled by a subsequent pm_runtime_disable() call if probe fails after the reset. Switch to pm_runtime_put_sync() to run the idle check and suspend synchronously. Fixes: 06ff622d61d2 ("phy: freescale: Add i.MX8qm Mixel LVDS PHY support") Reported-by: sashiko Closes: https://sashiko.dev/#/patchset/20260605-lvds-v2-1-3ce7539d1104%40gmail.com Signed-off-by: Felix Gu Reviewed-by: Frank Li Link: https://patch.msgid.link/20260609-lvds-phy-v1-1-6ad790c6d0ea@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c index ece357443521..e2a1645000ae 100644 --- a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c +++ b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c @@ -286,7 +286,7 @@ static int mixel_lvds_phy_reset(struct device *dev) regmap_write(priv->regmap, PHY_CTRL, CTRL_RESET_VAL); - pm_runtime_put(dev); + pm_runtime_put_sync(dev); return 0; } From a9a9bae2174bbad63fc73a0d445b7437f63b2498 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Mon, 8 Jun 2026 16:03:43 +0530 Subject: [PATCH 81/87] dt-bindings: phy: qcom,qusb2: Document IPQ5210 compatible Document the QUSB2 PHY compatible for the IPQ5210 SoC. The IPQ5210 PHY is compatible with the IPQ6018 QUSB2 PHY, so allow it to use qcom,ipq6018-qusb2-phy as the fallback compatible. Signed-off-by: Varadarajan Narayanan Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260608103344.2740174-2-varadarajan.narayanan@oss.qualcomm.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml index 39851ba9de43..449c2a7e5fec 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml @@ -30,6 +30,10 @@ properties: - qcom,sdm660-qusb2-phy - qcom,sm4250-qusb2-phy - qcom,sm6115-qusb2-phy + - items: + - enum: + - qcom,ipq5210-qusb2-phy + - const: qcom,ipq6018-qusb2-phy - items: - enum: - qcom,sc7180-qusb2-phy From 609878c1b684ea3f77ab72237511eb9bec927102 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Mon, 8 Jun 2026 16:03:44 +0530 Subject: [PATCH 82/87] dt-bindings: phy: qcom,qmp-usb: Add ipq5210 USB3 PHY Add dt-bindings for the USB3 QMP PHY found on the Qualcomm IPQ5210 SoC. The IPQ5210 PHY is compatible with the IPQ9574 PHY, so add it as a fallback- compatible entry using a oneOf construct rather than a plain enum entry. Signed-off-by: Varadarajan Narayanan Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260608103344.2740174-3-varadarajan.narayanan@oss.qualcomm.com Signed-off-by: Vinod Koul --- .../phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml index 623c2f8c7d22..01342823e57f 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml @@ -15,26 +15,32 @@ description: properties: compatible: - enum: - - qcom,glymur-qmp-usb3-uni-phy - - qcom,ipq5424-qmp-usb3-phy - - qcom,ipq6018-qmp-usb3-phy - - qcom,ipq8074-qmp-usb3-phy - - qcom,ipq9574-qmp-usb3-phy - - qcom,msm8996-qmp-usb3-phy - - qcom,qcs8300-qmp-usb3-uni-phy - - qcom,qdu1000-qmp-usb3-uni-phy - - qcom,sa8775p-qmp-usb3-uni-phy - - qcom,sc8180x-qmp-usb3-uni-phy - - qcom,sc8280xp-qmp-usb3-uni-phy - - qcom,sdm845-qmp-usb3-uni-phy - - qcom,sdx55-qmp-usb3-uni-phy - - qcom,sdx65-qmp-usb3-uni-phy - - qcom,sdx75-qmp-usb3-uni-phy - - qcom,sm8150-qmp-usb3-uni-phy - - qcom,sm8250-qmp-usb3-uni-phy - - qcom,sm8350-qmp-usb3-uni-phy - - qcom,x1e80100-qmp-usb3-uni-phy + oneOf: + - items: + - enum: + - qcom,glymur-qmp-usb3-uni-phy + - qcom,ipq5424-qmp-usb3-phy + - qcom,ipq6018-qmp-usb3-phy + - qcom,ipq8074-qmp-usb3-phy + - qcom,ipq9574-qmp-usb3-phy + - qcom,msm8996-qmp-usb3-phy + - qcom,qcs8300-qmp-usb3-uni-phy + - qcom,qdu1000-qmp-usb3-uni-phy + - qcom,sa8775p-qmp-usb3-uni-phy + - qcom,sc8180x-qmp-usb3-uni-phy + - qcom,sc8280xp-qmp-usb3-uni-phy + - qcom,sdm845-qmp-usb3-uni-phy + - qcom,sdx55-qmp-usb3-uni-phy + - qcom,sdx65-qmp-usb3-uni-phy + - qcom,sdx75-qmp-usb3-uni-phy + - qcom,sm8150-qmp-usb3-uni-phy + - qcom,sm8250-qmp-usb3-uni-phy + - qcom,sm8350-qmp-usb3-uni-phy + - qcom,x1e80100-qmp-usb3-uni-phy + - items: + - enum: + - qcom,ipq5210-qmp-usb3-phy + - const: qcom,ipq9574-qmp-usb3-phy reg: maxItems: 1 From 799e7cf2f0b50b34660b5ffce0f7d8dec376a0d5 Mon Sep 17 00:00:00 2001 From: Felix Gu Date: Fri, 5 Jun 2026 19:57:20 +0800 Subject: [PATCH 83/87] phy: freescale: phy-fsl-imx8qm-lvds-phy: Fix missing pm_runtime_disable() on probe error path If mixel_lvds_phy_reset() fails in probe after pm_runtime_enable(), the function returns directly without calling pm_runtime_disable(), leaving runtime PM permanently enabled for the device. Fix this by using devm_pm_runtime_enable() so that cleanup is automatic on any probe failure or driver unbind. This also allows removing the manual err label and the .remove callback. Fixes: 06ff622d61d2 ("phy: freescale: Add i.MX8qm Mixel LVDS PHY support") Acked-by: Liu Ying Signed-off-by: Felix Gu Reviewed-by: Frank Li Link: https://patch.msgid.link/20260605-lvds-v2-1-3ce7539d1104@gmail.com Signed-off-by: Vinod Koul --- .../phy/freescale/phy-fsl-imx8qm-lvds-phy.c | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c index e2a1645000ae..368679436d86 100644 --- a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c +++ b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c @@ -345,7 +345,9 @@ static int mixel_lvds_phy_probe(struct platform_device *pdev) dev_set_drvdata(dev, priv); - pm_runtime_enable(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; ret = mixel_lvds_phy_reset(dev); if (ret) { @@ -355,17 +357,15 @@ static int mixel_lvds_phy_probe(struct platform_device *pdev) for (i = 0; i < PHY_NUM; i++) { lvds_phy = devm_kzalloc(dev, sizeof(*lvds_phy), GFP_KERNEL); - if (!lvds_phy) { - ret = -ENOMEM; - goto err; - } + if (!lvds_phy) + return -ENOMEM; phy = devm_phy_create(dev, NULL, &mixel_lvds_phy_ops); if (IS_ERR(phy)) { ret = PTR_ERR(phy); dev_err(dev, "failed to create PHY for channel%d: %d\n", i, ret); - goto err; + return ret; } lvds_phy->phy = phy; @@ -379,19 +379,10 @@ static int mixel_lvds_phy_probe(struct platform_device *pdev) if (IS_ERR(phy_provider)) { ret = PTR_ERR(phy_provider); dev_err(dev, "failed to register PHY provider: %d\n", ret); - goto err; + return ret; } return 0; -err: - pm_runtime_disable(dev); - - return ret; -} - -static void mixel_lvds_phy_remove(struct platform_device *pdev) -{ - pm_runtime_disable(&pdev->dev); } static int __maybe_unused mixel_lvds_phy_runtime_suspend(struct device *dev) @@ -432,7 +423,6 @@ MODULE_DEVICE_TABLE(of, mixel_lvds_phy_of_match); static struct platform_driver mixel_lvds_phy_driver = { .probe = mixel_lvds_phy_probe, - .remove = mixel_lvds_phy_remove, .driver = { .pm = &mixel_lvds_phy_pm_ops, .name = "mixel-lvds-phy", From baacd0af457c2505137c4774e71efe044c11b26d Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Tue, 2 Jun 2026 10:25:37 +0200 Subject: [PATCH 84/87] dt-bindings: phy: add support for NXPs TJA1145 CAN transceiver Adding documentation for NXPs TJA1145 CAN transceiver, which resides like the ti,tcan104x-can.yaml in the same directory as other generic PHY subsystem bindings. At the moment there is only support for simple PHYs by using regulator bindings in combination with can-transceiver.yaml or PHYs that implement the generic PHY subsystem like the NXP TJA1145. Reviewed-by: Conor Dooley Signed-off-by: Dimitri Fedrau Link: https://patch.msgid.link/20260602-tja1145-support-v6-1-0e0ffc8ee63d@liebherr.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/nxp,tja1145.yaml | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/nxp,tja1145.yaml diff --git a/Documentation/devicetree/bindings/phy/nxp,tja1145.yaml b/Documentation/devicetree/bindings/phy/nxp,tja1145.yaml new file mode 100644 index 000000000000..fb068f7d774f --- /dev/null +++ b/Documentation/devicetree/bindings/phy/nxp,tja1145.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/nxp,tja1145.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TJA1145 CAN transceiver + +maintainers: + - Dimitri Fedrau + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + const: nxp,tja1145 + + interrupts: + maxItems: 1 + + reg: + maxItems: 1 + + "#phy-cells": + const: 0 + + spi-cpha: true + + spi-max-frequency: + maximum: 4000000 + + spi-cs-setup-delay-ns: + minimum: 50 + default: 50 + + spi-cs-hold-delay-ns: + minimum: 50 + default: 50 + + spi-cs-inactive-delay-ns: + minimum: 250 + default: 250 + + vcc-supply: + description: + CAN transceiver supply voltage + + vio-supply: + description: + Supply voltage for I/O level adaptor + + vbat-supply: + description: + Battery supply voltage + +required: + - compatible + - reg + - "#phy-cells" + - spi-cpha + +additionalProperties: false + +examples: + - | + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + can-phy@0 { + compatible = "nxp,tja1145"; + interrupt-parent = <&gpio0>; + interrupts = <31 IRQ_TYPE_LEVEL_LOW>; + reg = <0>; + #phy-cells = <0>; + spi-cpha; + spi-max-frequency = <4000000>; + spi-cs-setup-delay-ns = <50>; + spi-cs-hold-delay-ns = <50>; + spi-cs-inactive-delay-ns = <250>; + vcc-supply = <®_5v0>; + vio-supply = <®_3v3>; + vbat-supply = <®_24v0>; + }; + }; From e5a9c1c917b59a4aff066b9f317501834c6d5af2 Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Tue, 2 Jun 2026 10:25:38 +0200 Subject: [PATCH 85/87] phy: add basic support for NXPs TJA1145 CAN transceiver Add basic driver support for NXPs TJA1145 CAN transceiver which brings the PHY up/down by switching to normal/standby mode using SPI commands. Tested-by: lee.lockhey@gmail.com Reviewed-by: Marc Kleine-Budde Signed-off-by: Dimitri Fedrau Link: https://patch.msgid.link/20260602-tja1145-support-v6-2-0e0ffc8ee63d@liebherr.com Signed-off-by: Vinod Koul --- drivers/phy/Kconfig | 10 ++ drivers/phy/Makefile | 1 + drivers/phy/phy-nxp-tja1145.c | 184 ++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 drivers/phy/phy-nxp-tja1145.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 7ef342f4bbb6..19f3b7d12b7d 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -136,6 +136,16 @@ config PHY_NXP_PTN3222 schemes. It supports all three USB 2.0 data rates: Low Speed, Full Speed and High Speed. +config PHY_NXP_TJA1145 + tristate "NXP TJA1145 CAN transceiver PHY" + select GENERIC_PHY + select REGMAP_SPI + depends on SPI + help + This option enables support for NXPs TJA1145 CAN transceiver as a PHY. + This driver provides function for putting the transceiver in various + functional modes using SPI commands. + config PHY_PISTACHIO_USB tristate "IMG Pistachio USB2.0 PHY driver" depends on MIPS || COMPILE_TEST diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 1e69ed50fb17..d7aa516bcc49 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_PHY_GOOGLE_USB) += phy-google-usb.o obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o +obj-$(CONFIG_PHY_NXP_TJA1145) += phy-nxp-tja1145.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_PHY_SNPS_EUSB2) += phy-snps-eusb2.o obj-$(CONFIG_PHY_XGENE) += phy-xgene.o diff --git a/drivers/phy/phy-nxp-tja1145.c b/drivers/phy/phy-nxp-tja1145.c new file mode 100644 index 000000000000..1e8bd169743a --- /dev/null +++ b/drivers/phy/phy-nxp-tja1145.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Liebherr-Electronics and Drives GmbH + */ +#include +#include + +#include +#include + +#define TJA1145_MODE_CTRL 0x01 +#define TJA1145_MODE_CTRL_MC GENMASK(2, 0) +#define TJA1145_MODE_CTRL_STBY BIT(2) +#define TJA1145_MODE_CTRL_NORMAL TJA1145_MODE_CTRL_MC + +#define TJA1145_CAN_CTRL 0x20 +#define TJA1145_CAN_CTRL_CMC GENMASK(1, 0) +#define TJA1145_CAN_CTRL_ACTIVE BIT(1) + +#define TJA1145_IDENT 0x7e +#define TJA1145_IDENT_TJA1145T 0x70 + +#define TJA1145_SPI_READ_BIT BIT(0) +#define TJA1145T_MAX_BITRATE 1000000 + +static int tja1145_phy_power_on(struct phy *phy) +{ + struct regmap *map = phy_get_drvdata(phy); + int ret; + + /* + * Switch operating mode to normal which is the active operating mode. + * In this mode, the device is fully operational. + */ + ret = regmap_update_bits(map, TJA1145_MODE_CTRL, TJA1145_MODE_CTRL_MC, + TJA1145_MODE_CTRL_NORMAL); + if (ret) + return ret; + + /* + * Switch to CAN operating mode active where the PHY can transmit and + * receive data. + */ + return regmap_update_bits(map, TJA1145_CAN_CTRL, TJA1145_CAN_CTRL_CMC, + TJA1145_CAN_CTRL_ACTIVE); +} + +static int tja1145_phy_power_off(struct phy *phy) +{ + struct regmap *map = phy_get_drvdata(phy); + + /* + * Switch to operating mode standby, the PHY is unable to transmit or + * receive data in standby mode. + */ + return regmap_update_bits(map, TJA1145_MODE_CTRL, TJA1145_MODE_CTRL_MC, + TJA1145_MODE_CTRL_STBY); +} + +static const struct phy_ops tja1145_phy_ops = { + .power_on = tja1145_phy_power_on, + .power_off = tja1145_phy_power_off, + .owner = THIS_MODULE, +}; + +static const struct regmap_range tja1145_wr_holes_ranges[] = { + regmap_reg_range(0x00, 0x00), + regmap_reg_range(0x02, 0x03), + regmap_reg_range(0x05, 0x05), + regmap_reg_range(0x0b, 0x1f), + regmap_reg_range(0x21, 0x22), + regmap_reg_range(0x24, 0x25), + regmap_reg_range(0x30, 0x4b), + regmap_reg_range(0x4d, 0x60), + regmap_reg_range(0x62, 0x62), + regmap_reg_range(0x65, 0x67), + regmap_reg_range(0x70, 0xff), +}; + +static const struct regmap_access_table tja1145_wr_table = { + .no_ranges = tja1145_wr_holes_ranges, + .n_no_ranges = ARRAY_SIZE(tja1145_wr_holes_ranges), +}; + +static const struct regmap_range tja1145_rd_holes_ranges[] = { + regmap_reg_range(0x00, 0x00), + regmap_reg_range(0x02, 0x02), + regmap_reg_range(0x05, 0x05), + regmap_reg_range(0x0b, 0x1f), + regmap_reg_range(0x21, 0x21), + regmap_reg_range(0x24, 0x25), + regmap_reg_range(0x30, 0x4a), + regmap_reg_range(0x4d, 0x5f), + regmap_reg_range(0x62, 0x62), + regmap_reg_range(0x65, 0x67), + regmap_reg_range(0x70, 0x7d), + regmap_reg_range(0x7f, 0xff), +}; + +static const struct regmap_access_table tja1145_rd_table = { + .no_ranges = tja1145_rd_holes_ranges, + .n_no_ranges = ARRAY_SIZE(tja1145_rd_holes_ranges), +}; + +static const struct regmap_config tja1145_regmap_config = { + .reg_bits = 8, + .reg_shift = -1, + .val_bits = 8, + .wr_table = &tja1145_wr_table, + .rd_table = &tja1145_rd_table, + .read_flag_mask = TJA1145_SPI_READ_BIT, + .max_register = TJA1145_IDENT, +}; + +static int tja1145_check_ident(struct device *dev, struct regmap *map) +{ + unsigned int val; + int ret; + + ret = regmap_read(map, TJA1145_IDENT, &val); + if (ret) + return ret; + + if (val != TJA1145_IDENT_TJA1145T) { + dev_err(dev, "Expected device id: 0x%02x, got: 0x%02x\n", + TJA1145_IDENT_TJA1145T, val); + return -ENODEV; + } + + return 0; +} + +static int tja1145_probe(struct spi_device *spi) +{ + struct phy_provider *phy_provider; + struct device *dev = &spi->dev; + struct regmap *map; + struct phy *phy; + int ret; + + map = devm_regmap_init_spi(spi, &tja1145_regmap_config); + if (IS_ERR(map)) + return dev_err_probe(dev, PTR_ERR(map), "failed to init regmap\n"); + + ret = tja1145_check_ident(dev, map); + if (ret) + return dev_err_probe(dev, ret, "failed to identify device\n"); + + phy = devm_phy_create(dev, dev->of_node, &tja1145_phy_ops); + if (IS_ERR(phy)) + return dev_err_probe(dev, PTR_ERR(phy), "failed to create PHY\n"); + + phy->attrs.max_link_rate = TJA1145T_MAX_BITRATE; + phy_set_drvdata(phy, map); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct spi_device_id tja1145_spi_id[] = { + { "tja1145" }, + { } +}; +MODULE_DEVICE_TABLE(spi, tja1145_spi_id); + +static const struct of_device_id tja1145_of_match[] = { + { .compatible = "nxp,tja1145" }, + { } +}; +MODULE_DEVICE_TABLE(of, tja1145_of_match); + +static struct spi_driver tja1145_driver = { + .driver = { + .name = "tja1145", + .of_match_table = tja1145_of_match, + }, + .probe = tja1145_probe, + .id_table = tja1145_spi_id, +}; +module_spi_driver(tja1145_driver); + +MODULE_DESCRIPTION("NXP TJA1145 CAN transceiver PHY driver"); +MODULE_AUTHOR("Dimitri Fedrau "); +MODULE_LICENSE("GPL"); From 1e8065dfac34d1217f961e079959b71c69123417 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 May 2026 12:29:14 +0200 Subject: [PATCH 86/87] phy: Move MODULE_DEVICE_TABLE next to the table itself By convention MODULE_DEVICE_TABLE() immediately follows the ID table it exports, because this is easier to read and verify. It also makes more sense since #ifdef for ACPI or OF could hide both of them. Most of the privers already have this correctly placed, so adjust the missing ones. No functional impact. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20260505102913.188406-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/broadcom/phy-bcm-ns-usb3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb3.c b/drivers/phy/broadcom/phy-bcm-ns-usb3.c index 6e56498d0644..9240600aeef6 100644 --- a/drivers/phy/broadcom/phy-bcm-ns-usb3.c +++ b/drivers/phy/broadcom/phy-bcm-ns-usb3.c @@ -65,6 +65,7 @@ static const struct of_device_id bcm_ns_usb3_id_table[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, bcm_ns_usb3_id_table); static int bcm_ns_usb3_mdio_phy_write(struct bcm_ns_usb3 *usb3, u16 reg, u16 value); @@ -242,4 +243,3 @@ mdio_module_driver(bcm_ns_usb3_mdio_driver); MODULE_DESCRIPTION("Broadcom Northstar USB 3.0 PHY Driver"); MODULE_LICENSE("GPL v2"); -MODULE_DEVICE_TABLE(of, bcm_ns_usb3_id_table); From 2ace2e949979b82f82f12dd76d7c5a6145246ca3 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Wed, 20 May 2026 12:28:59 +0200 Subject: [PATCH 87/87] phy: rockchip: inno-usb2: Add missing clkout_ctl_phy kerneldoc Add the missing documentation for the newly added clkout_ctl_phy field. Fixes: 2775541de058 ("phy: rockchip: inno-usb2: Add clkout_ctl_phy support") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202605150315.MyBNQOPB-lkp@intel.com/ Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20260520102859.1357411-1-heiko@sntech.de Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 133cfd6624e8..7d8a533f24ae 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -170,7 +170,8 @@ struct rockchip_usb2phy_port_cfg { * @reg: the address offset of grf for usb-phy config. * @num_ports: specify how many ports that the phy has. * @phy_tuning: phy default parameters tuning. - * @clkout_ctl: keep on/turn off output clk of phy. + * @clkout_ctl: register to enable output clk of phy, when set in GRF + * @clkout_ctl_phy: register to enable output clk of phy, when set inside phy * @port_cfgs: usb-phy port configurations. * @chg_det: charger detection registers. */