[openwrt/openwrt] qualcommbe: update ipq9574 PCS driver
LEDE Commits
lede-commits at lists.infradead.org
Sun Nov 30 07:51:19 PST 2025
robimarko pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/95bd7a76a138d533c9b6b37bf91c4a006d94b22f
commit 95bd7a76a138d533c9b6b37bf91c4a006d94b22f
Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
AuthorDate: Thu Nov 6 21:52:11 2025 -0600
qualcommbe: update ipq9574 PCS driver
Update the ipq9574 PCS driver the version provided by Qualcomm via
github. The updated driver simplifies link up handling by removing
unnecessary clock rate changes.
Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
Link: https://github.com/openwrt/openwrt/pull/20993
Signed-off-by: Robert Marko <robimarko at gmail.com>
---
...m-ipq9574-Add-PCS-instantiation-and-phyli.patch | 17 +-
...m-ipq9574-remove-neg_mode-argument-from-i.patch | 29 --
...m-ipq9574-delay-mii-clock-probing-until-i.patch | 82 -----
...m-ipq9574-add-changes-not-submitted-upstr.patch | 362 ---------------------
...m64-dts-qcom-ipq9574-add-PCS-uniphy-nodes.patch | 30 +-
...-10GBASER-interface-mode-support-to-IPQ-U.patch | 94 +++---
...-2500BASEX-interface-mode-support-to-IPQ-.patch | 130 +++-----
...-1000BASEX-interface-mode-support-to-IPQ-.patch | 71 ++--
...-10G_QXGMII-interface-mode-support-to-IPQ.patch | 224 ++++++-------
...-uniphy-control-MISC2-register-for-2.5G-s.patch | 42 ++-
...-uniphy-keep-autoneg-enabled-in-SGMII-mod.patch | 25 --
...cs-ipq-uniphy-fix-USXGMII-link-up-failure.patch | 4 +-
...cs-qcom-ipq9574-Update-IPQ9574-PCS-driver.patch | 282 ++++++++++++++++
13 files changed, 557 insertions(+), 835 deletions(-)
diff --git a/target/linux/qualcommbe/patches-6.12/0316-net-pcs-qcom-ipq9574-Add-PCS-instantiation-and-phyli.patch b/target/linux/qualcommbe/patches-6.12/0316-net-pcs-qcom-ipq9574-Add-PCS-instantiation-and-phyli.patch
index 1e7453a35c..7d071c2e25 100644
--- a/target/linux/qualcommbe/patches-6.12/0316-net-pcs-qcom-ipq9574-Add-PCS-instantiation-and-phyli.patch
+++ b/target/linux/qualcommbe/patches-6.12/0316-net-pcs-qcom-ipq9574-Add-PCS-instantiation-and-phyli.patch
@@ -1,4 +1,4 @@
-From 240ae5e0ca2ed858e25d7da6d5291d9c1f2c660a Mon Sep 17 00:00:00 2001
+From 10b609ddbf4d369c80098efa39451ef3973759b5 Mon Sep 17 00:00:00 2001
From: Lei Wei <quic_leiwei at quicinc.com>
Date: Fri, 7 Feb 2025 23:53:14 +0800
Subject: [PATCH] net: pcs: qcom-ipq9574: Add PCS instantiation and phylink
@@ -14,10 +14,12 @@ MAC.
c.) PCS phylink operations for SGMII/QSGMII interface modes.
Signed-off-by: Lei Wei <quic_leiwei at quicinc.com>
+Alex G: remove phylink_pcs .neg_mode boolean
+Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
---
- drivers/net/pcs/pcs-qcom-ipq9574.c | 469 +++++++++++++++++++++++++++
+ drivers/net/pcs/pcs-qcom-ipq9574.c | 468 +++++++++++++++++++++++++++
include/linux/pcs/pcs-qcom-ipq9574.h | 15 +
- 2 files changed, 484 insertions(+)
+ 2 files changed, 483 insertions(+)
create mode 100644 include/linux/pcs/pcs-qcom-ipq9574.h
--- a/drivers/net/pcs/pcs-qcom-ipq9574.c
@@ -88,7 +90,7 @@ Signed-off-by: Lei Wei <quic_leiwei at quicinc.com>
/* PCS private data */
struct ipq_pcs {
struct device *dev;
-@@ -31,8 +77,359 @@ struct ipq_pcs {
+@@ -31,8 +77,358 @@ struct ipq_pcs {
struct clk_hw rx_hw;
/* TX clock supplied to NSSCC */
struct clk_hw tx_hw;
@@ -310,7 +312,7 @@ Signed-off-by: Lei Wei <quic_leiwei at quicinc.com>
+ clk_disable_unprepare(qpcs_mii->tx_clk);
+}
+
-+static void ipq_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
++static void ipq_pcs_get_state(struct phylink_pcs *pcs,
+ struct phylink_link_state *state)
+{
+ struct ipq_pcs_mii *qpcs_mii = phylink_pcs_to_qpcs_mii(pcs);
@@ -422,7 +424,6 @@ Signed-off-by: Lei Wei <quic_leiwei at quicinc.com>
+ qpcs_mii->qpcs = qpcs;
+ qpcs_mii->index = index;
+ qpcs_mii->pcs.ops = &ipq_pcs_phylink_ops;
-+ qpcs_mii->pcs.neg_mode = true;
+ qpcs_mii->pcs.poll = true;
+
+ qpcs_mii->rx_clk = devm_get_clk_from_child(dev, mii_np, "rx");
@@ -448,7 +449,7 @@ Signed-off-by: Lei Wei <quic_leiwei at quicinc.com>
static unsigned long ipq_pcs_clk_rate_get(struct ipq_pcs *qpcs)
{
switch (qpcs->interface) {
-@@ -219,6 +616,10 @@ static int ipq9574_pcs_probe(struct plat
+@@ -219,6 +615,10 @@ static int ipq9574_pcs_probe(struct plat
if (ret)
return ret;
@@ -459,7 +460,7 @@ Signed-off-by: Lei Wei <quic_leiwei at quicinc.com>
platform_set_drvdata(pdev, qpcs);
return 0;
-@@ -230,6 +631,74 @@ static const struct of_device_id ipq9574
+@@ -230,6 +630,74 @@ static const struct of_device_id ipq9574
};
MODULE_DEVICE_TABLE(of, ipq9574_pcs_of_mtable);
diff --git a/target/linux/qualcommbe/patches-6.12/0319-net-pcs-qcom-ipq9574-remove-neg_mode-argument-from-i.patch b/target/linux/qualcommbe/patches-6.12/0319-net-pcs-qcom-ipq9574-remove-neg_mode-argument-from-i.patch
deleted file mode 100644
index 6fc9652f08..0000000000
--- a/target/linux/qualcommbe/patches-6.12/0319-net-pcs-qcom-ipq9574-remove-neg_mode-argument-from-i.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From ffe2a80fb76ccdc1781f817f6bbc9a8aa919816e Mon Sep 17 00:00:00 2001
-From: Alexandru Gagniuc <mr.nuke.me at gmail.com>
-Date: Mon, 12 May 2025 09:11:05 -0500
-Subject: [PATCH] net: pcs: qcom-ipq9574: remove "neg_mode" argument from
- ipq_pcs_get_state
-
-Since commit c6739623c91bb ("net: phylink: pass neg_mode into
-.pcs_get_state() method"), the "neg_mode" parameter is part of the
-argument list of .pcs_get_state(). This is available starting with
-v6.14. However, we want to use the backported IPQ9574 driver on v6.12.
-Remove this parameter from ipq_pcs_get_state(), as it is not part of
-.pcs_get_state() in v6.12.
-
-Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
----
- drivers/net/pcs/pcs-qcom-ipq9574.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/pcs/pcs-qcom-ipq9574.c
-+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
-@@ -457,7 +457,7 @@ static void ipq_pcs_disable(struct phyli
- clk_disable_unprepare(qpcs_mii->tx_clk);
- }
-
--static void ipq_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
-+static void ipq_pcs_get_state(struct phylink_pcs *pcs,
- struct phylink_link_state *state)
- {
- struct ipq_pcs_mii *qpcs_mii = phylink_pcs_to_qpcs_mii(pcs);
diff --git a/target/linux/qualcommbe/patches-6.12/0320-net-pcs-qcom-ipq9574-delay-mii-clock-probing-until-i.patch b/target/linux/qualcommbe/patches-6.12/0320-net-pcs-qcom-ipq9574-delay-mii-clock-probing-until-i.patch
deleted file mode 100644
index ac4c44a720..0000000000
--- a/target/linux/qualcommbe/patches-6.12/0320-net-pcs-qcom-ipq9574-delay-mii-clock-probing-until-i.patch
+++ /dev/null
@@ -1,82 +0,0 @@
-From 5b2f02ccca7b9496f0a8da6ade063b82810c75e7 Mon Sep 17 00:00:00 2001
-From: Alexandru Gagniuc <mr.nuke.me at gmail.com>
-Date: Mon, 12 May 2025 09:27:17 -0500
-Subject: [PATCH] net: pcs: qcom-ipq9574: delay mii clock probing until
- ipq_pcs_get()
-
-NSSCC generates the SYS and AHB clocks for the PCS block The PCS then
-feeds the uniphy clocks back to the NSSCC, which are in turn, used to
-feed the PCS MII clocks. This works fine in hardware:
-
- GCC -> NSSCC -> PCS -> NSSCC -> PCS(MII)
-
-However, when the PCS MII clocks are probed within the .probe() of
-the PCS block, it creates a circular dependency. The MII clocks depend
-on the uniphy clocks, which depend on the PCS block being probed.
-Since we are in the process of probing the PCS block, this results in
-both blocks returning with -EPROBE_DEFER:
-
- platform 39b00000.clock-controller: deferred probe pending: platform: supplier 7a00000.ethernet-pcs not ready
- mdio_bus 90000.mdio-1:18: deferred probe pending: mdio_bus: supplier 7a20000.ethernet-pcs not ready
- mdio_bus 90000.mdio-1:00: deferred probe pending: mdio_bus: supplier 90000.mdio-1:18 not ready
- mdio_bus 90000.mdio-1:01: deferred probe pending: mdio_bus: supplier 90000.mdio-1:18 not ready
- mdio_bus 90000.mdio-1:02: deferred probe pending: mdio_bus: supplier 90000.mdio-1:18 not ready
- mdio_bus 90000.mdio-1:03: deferred probe pending: mdio_bus: supplier 90000.mdio-1:18 not ready
- platform 7a00000.ethernet-pcs: deferred probe pending: ipq9574_pcs: Failed to get MII 0 RX clock
- platform 7a20000.ethernet-pcs: deferred probe pending: ipq9574_pcs: Failed to get MII 0 RX clock
- platform 3a000000.qcom-ppe: deferred probe pending: platform: supplier 39b00000.clock-controller not ready
-
-To break this dependency, let the PCS block probe, and only probe the
-PCS MII clocks from ipq_pcs_get().
-
-Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
----
- drivers/net/pcs/pcs-qcom-ipq9574.c | 30 ++++++++++++++++--------------
- 1 file changed, 16 insertions(+), 14 deletions(-)
-
---- a/drivers/net/pcs/pcs-qcom-ipq9574.c
-+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
-@@ -580,20 +580,6 @@ static int ipq_pcs_create_miis(struct ip
- qpcs_mii->pcs.neg_mode = true;
- qpcs_mii->pcs.poll = true;
-
-- qpcs_mii->rx_clk = devm_get_clk_from_child(dev, mii_np, "rx");
-- if (IS_ERR(qpcs_mii->rx_clk)) {
-- of_node_put(mii_np);
-- return dev_err_probe(dev, PTR_ERR(qpcs_mii->rx_clk),
-- "Failed to get MII %d RX clock\n", index);
-- }
--
-- qpcs_mii->tx_clk = devm_get_clk_from_child(dev, mii_np, "tx");
-- if (IS_ERR(qpcs_mii->tx_clk)) {
-- of_node_put(mii_np);
-- return dev_err_probe(dev, PTR_ERR(qpcs_mii->tx_clk),
-- "Failed to get MII %d TX clock\n", index);
-- }
--
- qpcs->qpcs_mii[index] = qpcs_mii;
- }
-
-@@ -848,6 +834,22 @@ struct phylink_pcs *ipq_pcs_get(struct d
- return ERR_PTR(-ENOENT);
- }
-
-+ qpcs_mii->rx_clk = devm_get_clk_from_child(&pdev->dev, np, "rx");
-+ if (IS_ERR(qpcs_mii->rx_clk)) {
-+ put_device(&pdev->dev);
-+ return dev_err_ptr_probe(&pdev->dev, PTR_ERR(qpcs_mii->rx_clk),
-+ "Failed to get MII %d RX clock\n",
-+ index);
-+ }
-+
-+ qpcs_mii->tx_clk = devm_get_clk_from_child(&pdev->dev, np, "tx");
-+ if (IS_ERR(qpcs_mii->tx_clk)) {
-+ put_device(&pdev->dev);
-+ return dev_err_ptr_probe(&pdev->dev, PTR_ERR(qpcs_mii->tx_clk),
-+ "Failed to get MII %d TX clock\n",
-+ index);
-+ }
-+
- return &qpcs_mii->pcs;
- }
- EXPORT_SYMBOL(ipq_pcs_get);
diff --git a/target/linux/qualcommbe/patches-6.12/0321-net-pcs-qcom-ipq9574-add-changes-not-submitted-upstr.patch b/target/linux/qualcommbe/patches-6.12/0321-net-pcs-qcom-ipq9574-add-changes-not-submitted-upstr.patch
deleted file mode 100644
index 64a5bf6229..0000000000
--- a/target/linux/qualcommbe/patches-6.12/0321-net-pcs-qcom-ipq9574-add-changes-not-submitted-upstr.patch
+++ /dev/null
@@ -1,362 +0,0 @@
-From 7de372abe7a4b5b380fdbeedd268445f234990c8 Mon Sep 17 00:00:00 2001
-From: Lei Wei <quic_leiwei at quicinc.com>
-Date: Mon, 29 Jan 2024 11:39:36 +0800
-Subject: [PATCH] net: pcs: qcom-ipq9574: add changes not submitted upstream
-
-Was ("net: pcs: Add driver for Qualcomm IPQ UNIPHY PCS").
-
-The UNIPHY hardware block in Qualcomm's IPQ SoC based boards enables
-PCS and XPCS functions, and helps in interfacing the Ethernet MAC in
-IPQ SoC to external PHYs.
-
-This patch adds the PCS driver support for the UNIPHY hardware used in
-IPQ SoC based boards. Support for SGMII/QSGMII/PSGMII and USXGMII
-interface modes are added in the driver.
-
-Change-Id: Id2c8f993f121098f7b02186b53770b75bb539a93
-Signed-off-by: Lei Wei <quic_leiwei at quicinc.com>
-Alex G: Rebase original patch on top of 20250207 uniphy submission
- Remove mutex that is not required according to
- https://lore.kernel.org/lkml/Z3ZwURgIErzpzpEr@shell.armlinux.org.uk/
-Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
----
- drivers/net/pcs/pcs-qcom-ipq9574.c | 180 +++++++++++++++++++++++-
- include/linux/pcs/pcs-qcom-ipq-uniphy.h | 13 ++
- 2 files changed, 192 insertions(+), 1 deletion(-)
- create mode 100644 include/linux/pcs/pcs-qcom-ipq-uniphy.h
-
---- a/drivers/net/pcs/pcs-qcom-ipq9574.c
-+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
-@@ -9,10 +9,12 @@
- #include <linux/of.h>
- #include <linux/of_platform.h>
- #include <linux/pcs/pcs-qcom-ipq9574.h>
-+#include <linux/pcs/pcs-qcom-ipq-uniphy.h>
- #include <linux/phy.h>
- #include <linux/phylink.h>
- #include <linux/platform_device.h>
- #include <linux/regmap.h>
-+#include <linux/reset.h>
-
- #include <dt-bindings/net/qcom,ipq9574-pcs.h>
-
-@@ -26,6 +28,7 @@
- #define PCS_MODE_SEL_MASK GENMASK(12, 8)
- #define PCS_MODE_SGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x4)
- #define PCS_MODE_QSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x1)
-+#define PCS_MODE_PSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x2)
- #define PCS_MODE_XPCS FIELD_PREP(PCS_MODE_SEL_MASK, 0x10)
-
- #define PCS_MII_CTRL(x) (0x480 + 0x18 * (x))
-@@ -43,6 +46,8 @@
- #define PCS_MII_STS_SPEED_10 0
- #define PCS_MII_STS_SPEED_100 1
- #define PCS_MII_STS_SPEED_1000 2
-+#define PCS_MII_STS_PAUSE_TX_EN BIT(1)
-+#define PCS_MII_STS_PAUSE_RX_EN BIT(0)
-
- #define PCS_PLL_RESET 0x780
- #define PCS_ANA_SW_RESET BIT(6)
-@@ -95,12 +100,35 @@ struct ipq_pcs_mii {
- struct clk *tx_clk;
- };
-
-+/* UNIPHY PCS reset ID */
-+enum {
-+ PCS_SYS_RESET,
-+ PCS_AHB_RESET,
-+ XPCS_RESET,
-+ PCS_RESET_MAX
-+};
-+
-+/* UNIPHY PCS reset name */
-+static const char *const pcs_reset_name[PCS_RESET_MAX] = {
-+ "sys",
-+ "ahb",
-+ "xpcs",
-+};
-+
-+/* UNIPHY PCS channel clock ID */
-+enum {
-+ PCS_CH_RX_CLK,
-+ PCS_CH_TX_CLK,
-+ PCS_CH_CLK_MAX
-+};
-+
- /* PCS private data */
- struct ipq_pcs {
- struct device *dev;
- void __iomem *base;
- struct regmap *regmap;
- phy_interface_t interface;
-+ struct reset_control *reset[PCS_RESET_MAX];
-
- /* RX clock supplied to NSSCC */
- struct clk_hw rx_hw;
-@@ -150,6 +178,11 @@ static void ipq_pcs_get_state_sgmii(stru
- state->duplex = DUPLEX_FULL;
- else
- state->duplex = DUPLEX_HALF;
-+
-+ if (val & PCS_MII_STS_PAUSE_TX_EN)
-+ state->pause |= MLO_PAUSE_TX;
-+ if (val & PCS_MII_STS_PAUSE_RX_EN)
-+ state->pause |= MLO_PAUSE_RX;
- }
-
- static void ipq_pcs_get_state_usxgmii(struct ipq_pcs *qpcs,
-@@ -203,6 +236,9 @@ static int ipq_pcs_config_mode(struct ip
- unsigned int val;
- int ret;
-
-+ /* Assert XPCS reset */
-+ reset_control_assert(qpcs->reset[XPCS_RESET]);
-+
- /* Configure PCS interface mode */
- switch (interface) {
- case PHY_INTERFACE_MODE_SGMII:
-@@ -211,11 +247,16 @@ static int ipq_pcs_config_mode(struct ip
- case PHY_INTERFACE_MODE_QSGMII:
- val = PCS_MODE_QSGMII;
- break;
-+ case PHY_INTERFACE_MODE_PSGMII:
-+ val = PCS_MODE_PSGMII;
-+ break;
- case PHY_INTERFACE_MODE_USXGMII:
- val = PCS_MODE_XPCS;
- rate = 312500000;
- break;
- default:
-+ dev_err(qpcs->dev,
-+ "interface %s not supported\n", phy_modes(interface));
- return -EOPNOTSUPP;
- }
-
-@@ -300,6 +341,9 @@ static int ipq_pcs_config_usxgmii(struct
- if (ret)
- return ret;
-
-+ /* Deassert XPCS and configure XPCS USXGMII */
-+ reset_control_deassert(qpcs->reset[XPCS_RESET]);
-+
- ret = regmap_set_bits(qpcs->regmap, XPCS_DIG_CTRL, XPCS_USXG_EN);
- if (ret)
- return ret;
-@@ -311,6 +355,91 @@ static int ipq_pcs_config_usxgmii(struct
- return regmap_set_bits(qpcs->regmap, XPCS_MII_CTRL, XPCS_MII_AN_EN);
- }
-
-+static unsigned long ipq_unipcs_clock_rate_get_gmii(int speed)
-+{
-+ unsigned long rate = 0;
-+
-+ switch (speed) {
-+ case SPEED_1000:
-+ rate = 125000000;
-+ break;
-+ case SPEED_100:
-+ rate = 25000000;
-+ break;
-+ case SPEED_10:
-+ rate = 2500000;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return rate;
-+}
-+
-+static unsigned long ipq_unipcs_clock_rate_get_xgmii(int speed)
-+{
-+ unsigned long rate = 0;
-+
-+ switch (speed) {
-+ case SPEED_10000:
-+ rate = 312500000;
-+ break;
-+ case SPEED_5000:
-+ rate = 156250000;
-+ break;
-+ case SPEED_2500:
-+ rate = 78125000;
-+ break;
-+ case SPEED_1000:
-+ rate = 125000000;
-+ break;
-+ case SPEED_100:
-+ rate = 12500000;
-+ break;
-+ case SPEED_10:
-+ rate = 1250000;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return rate;
-+}
-+
-+static void
-+ipq_unipcs_link_up_clock_rate_set(struct ipq_pcs_mii *qunipcs_ch,
-+ phy_interface_t interface,
-+ int speed)
-+{
-+ struct ipq_pcs *qpcs = qunipcs_ch->qpcs;
-+ unsigned long rate = 0;
-+
-+ switch (interface) {
-+ case PHY_INTERFACE_MODE_SGMII:
-+ case PHY_INTERFACE_MODE_QSGMII:
-+ case PHY_INTERFACE_MODE_PSGMII:
-+ rate = ipq_unipcs_clock_rate_get_gmii(speed);
-+ break;
-+ case PHY_INTERFACE_MODE_USXGMII:
-+ rate = ipq_unipcs_clock_rate_get_xgmii(speed);
-+ break;
-+ default:
-+ dev_err(qpcs->dev,
-+ "interface %s not supported\n", phy_modes(interface));
-+ return;
-+ }
-+
-+ if (rate == 0) {
-+ dev_err(qpcs->dev, "Invalid PCS clock rate\n");
-+ return;
-+ }
-+
-+ clk_set_rate(qunipcs_ch->rx_clk, rate);
-+ clk_set_rate(qunipcs_ch->tx_clk, rate);
-+
-+ fsleep(10000);
-+}
-+
- static int ipq_pcs_link_up_config_sgmii(struct ipq_pcs *qpcs,
- int index,
- unsigned int neg_mode,
-@@ -467,6 +596,7 @@ static void ipq_pcs_get_state(struct phy
- switch (state->interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_QSGMII:
-+ case PHY_INTERFACE_MODE_PSGMII:
- ipq_pcs_get_state_sgmii(qpcs, index, state);
- break;
- case PHY_INTERFACE_MODE_USXGMII:
-@@ -497,10 +627,13 @@ static int ipq_pcs_config(struct phylink
- switch (interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_QSGMII:
-+ case PHY_INTERFACE_MODE_PSGMII:
- return ipq_pcs_config_sgmii(qpcs, index, neg_mode, interface);
- case PHY_INTERFACE_MODE_USXGMII:
- return ipq_pcs_config_usxgmii(qpcs);
- default:
-+ dev_err(qpcs->dev,
-+ "interface %s not supported\n", phy_modes(interface));
- return -EOPNOTSUPP;
- };
- }
-@@ -515,9 +648,14 @@ static void ipq_pcs_link_up(struct phyli
- int index = qpcs_mii->index;
- int ret;
-
-+ /* Configure PCS channel interface clock rate */
-+ ipq_unipcs_link_up_clock_rate_set(qpcs_mii, interface, speed);
-+
-+ /* Configure PCS speed and reset PCS adapter */
- switch (interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_QSGMII:
-+ case PHY_INTERFACE_MODE_PSGMII:
- ret = ipq_pcs_link_up_config_sgmii(qpcs, index,
- neg_mode, speed);
- break;
-@@ -525,6 +663,8 @@ static void ipq_pcs_link_up(struct phyli
- ret = ipq_pcs_link_up_config_usxgmii(qpcs, speed);
- break;
- default:
-+ dev_err(qpcs->dev,
-+ "interface %s not supported\n", phy_modes(interface));
- return;
- }
-
-@@ -735,12 +875,38 @@ static const struct regmap_config ipq_pc
- .fast_io = true,
- };
-
-+/**
-+ * ipq_unipcs_create() - Create Qualcomm IPQ UNIPHY PCS
-+ * @np: Device tree node to the PCS
-+ *
-+ * Description: Create a phylink PCS instance for a PCS node @np.
-+ *
-+ * Return: A pointer to the phylink PCS instance or an error-pointer value.
-+ */
-+struct phylink_pcs *ipq_unipcs_create(struct device_node *np)
-+{
-+ return ipq_pcs_get(np);
-+}
-+EXPORT_SYMBOL(ipq_unipcs_create);
-+
-+/**
-+ * ipq_unipcs_destroy() - Destroy Qualcomm IPQ UNIPHY PCS
-+ * @pcs: PCS instance
-+ *
-+ * Description: Destroy a phylink PCS instance.
-+ */
-+void ipq_unipcs_destroy(struct phylink_pcs *pcs)
-+{
-+ ipq_pcs_put(pcs);
-+}
-+EXPORT_SYMBOL(ipq_unipcs_destroy);
-+
- static int ipq9574_pcs_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
- struct ipq_pcs *qpcs;
- struct clk *clk;
-- int ret;
-+ int i, ret;
-
- qpcs = devm_kzalloc(dev, sizeof(*qpcs), GFP_KERNEL);
- if (!qpcs)
-@@ -762,11 +928,23 @@ static int ipq9574_pcs_probe(struct plat
- if (IS_ERR(clk))
- return dev_err_probe(dev, PTR_ERR(clk),
- "Failed to enable SYS clock\n");
-+ clk_set_rate(clk, 24000000);
-
- clk = devm_clk_get_enabled(dev, "ahb");
- if (IS_ERR(clk))
- return dev_err_probe(dev, PTR_ERR(clk),
- "Failed to enable AHB clock\n");
-+ clk_set_rate(clk, 100000000);
-+
-+ for (i = 0; i < PCS_RESET_MAX; i++) {
-+ qpcs->reset[i] =
-+ devm_reset_control_get_optional_exclusive(dev,
-+ pcs_reset_name[i]);
-+
-+ if (IS_ERR(qpcs->reset[i]))
-+ dev_err(dev, "Failed to get the reset ID %s\n",
-+ pcs_reset_name[i]);
-+ }
-
- ret = ipq_pcs_clk_register(qpcs);
- if (ret)
---- /dev/null
-+++ b/include/linux/pcs/pcs-qcom-ipq-uniphy.h
-@@ -0,0 +1,13 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+/*
-+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
-+ *
-+ */
-+
-+#ifndef __LINUX_PCS_QCOM_IPQ_UNIPHY_H
-+#define __LINUX_PCS_QCOM_IPQ_UNIPHY_H
-+
-+struct phylink_pcs *ipq_unipcs_create(struct device_node *np);
-+void ipq_unipcs_destroy(struct phylink_pcs *pcs);
-+
-+#endif /* __LINUX_PCS_QCOM_IPQ_UNIPHY_H */
diff --git a/target/linux/qualcommbe/patches-6.12/0322-arm64-dts-qcom-ipq9574-add-PCS-uniphy-nodes.patch b/target/linux/qualcommbe/patches-6.12/0322-arm64-dts-qcom-ipq9574-add-PCS-uniphy-nodes.patch
index 29c20a240a..8196ff601c 100644
--- a/target/linux/qualcommbe/patches-6.12/0322-arm64-dts-qcom-ipq9574-add-PCS-uniphy-nodes.patch
+++ b/target/linux/qualcommbe/patches-6.12/0322-arm64-dts-qcom-ipq9574-add-PCS-uniphy-nodes.patch
@@ -1,4 +1,4 @@
-From 8c02b6438167e1b73b908040c4ec3d4877c16f83 Mon Sep 17 00:00:00 2001
+From d6f184181b076cbb54f152994f5bc73ce524a67e Mon Sep 17 00:00:00 2001
From: Alexandru Gagniuc <mr.nuke.me at gmail.com>
Date: Sun, 11 May 2025 18:21:00 -0500
Subject: [PATCH] arm64: dts: qcom: ipq9574: add PCS uniphy nodes
@@ -11,8 +11,8 @@ feed back to the NSSCC node.
Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
---
- arch/arm64/boot/dts/qcom/ipq9574.dtsi | 116 ++++++++++++++++++++++++--
- 1 file changed, 110 insertions(+), 6 deletions(-)
+ arch/arm64/boot/dts/qcom/ipq9574.dtsi | 100 ++++++++++++++++++++++++--
+ 1 file changed, 94 insertions(+), 6 deletions(-)
--- a/arch/arm64/boot/dts/qcom/ipq9574.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq9574.dtsi
@@ -43,7 +43,7 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
<&gcc GCC_NSSCC_CLK>;
clock-names = "xo",
"nss_1200",
-@@ -1269,6 +1270,109 @@
+@@ -1269,6 +1270,93 @@
#reset-cells = <1>;
#interconnect-cells = <1>;
};
@@ -57,13 +57,7 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ <&gcc GCC_UNIPHY0_AHB_CLK>;
+ clock-names = "sys",
+ "ahb";
-+ resets = <&gcc GCC_UNIPHY0_SYS_RESET>,
-+ <&gcc GCC_UNIPHY0_AHB_RESET>,
-+ <&gcc GCC_UNIPHY0_XPCS_RESET>;
-+ reset-names = "sys",
-+ "ahb",
-+ "xpcs";
-+
++ resets = <&gcc GCC_UNIPHY0_XPCS_RESET>;
+ #clock-cells = <1>;
+
+ pcs0_ch0: pcs-mii at 0 {
@@ -108,12 +102,7 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ <&gcc GCC_UNIPHY1_AHB_CLK>;
+ clock-names = "sys",
+ "ahb";
-+ resets = <&gcc GCC_UNIPHY1_SYS_RESET>,
-+ <&gcc GCC_UNIPHY1_AHB_RESET>,
-+ <&gcc GCC_UNIPHY1_XPCS_RESET>;
-+ reset-names = "sys",
-+ "ahb",
-+ "xpcs";
++ resets = <&gcc GCC_UNIPHY1_XPCS_RESET>;
+ #clock-cells = <1>;
+
+ pcs1_ch0: pcs-mii at 0 {
@@ -134,12 +123,7 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ <&gcc GCC_UNIPHY2_AHB_CLK>;
+ clock-names = "sys",
+ "ahb";
-+ resets = <&gcc GCC_UNIPHY2_SYS_RESET>,
-+ <&gcc GCC_UNIPHY2_AHB_RESET>,
-+ <&gcc GCC_UNIPHY2_XPCS_RESET>;
-+ reset-names = "sys",
-+ "ahb",
-+ "xpcs";
++ resets = <&gcc GCC_UNIPHY2_XPCS_RESET>;
+ #clock-cells = <1>;
+
+ pcs2_ch0: pcs-mii at 0 {
diff --git a/target/linux/qualcommbe/patches-6.12/0361-net-pcs-Add-10GBASER-interface-mode-support-to-IPQ-U.patch b/target/linux/qualcommbe/patches-6.12/0361-net-pcs-Add-10GBASER-interface-mode-support-to-IPQ-U.patch
index 157f5b62c6..5bdf3e9299 100644
--- a/target/linux/qualcommbe/patches-6.12/0361-net-pcs-Add-10GBASER-interface-mode-support-to-IPQ-U.patch
+++ b/target/linux/qualcommbe/patches-6.12/0361-net-pcs-Add-10GBASER-interface-mode-support-to-IPQ-U.patch
@@ -1,4 +1,4 @@
-From e770b36f0353fd11c4628360fe412acb7f02f346 Mon Sep 17 00:00:00 2001
+From 432c2a2da1e0f4a8e2c0fea191361832a7f90f36 Mon Sep 17 00:00:00 2001
From: Lei Wei <quic_leiwei at quicinc.com>
Date: Wed, 6 Mar 2024 17:40:52 +0800
Subject: [PATCH] net: pcs: Add 10GBASER interface mode support to IPQ UNIPHY
@@ -9,40 +9,41 @@ Subject: [PATCH] net: pcs: Add 10GBASER interface mode support to IPQ UNIPHY
Change-Id: Ifc3c3bb23811807a9b34e88771aab2c830c2327c
Signed-off-by: Lei Wei <quic_leiwei at quicinc.com>
Alex G: Use regmap to read/write registers
+ Remove xpcs_reset deassert logic (to be implemented later)
Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
---
- drivers/net/pcs/pcs-qcom-ipq9574.c | 57 ++++++++++++++++++++++++++++++
- 1 file changed, 57 insertions(+)
+ drivers/net/pcs/pcs-qcom-ipq9574.c | 47 ++++++++++++++++++++++++++++++
+ 1 file changed, 47 insertions(+)
--- a/drivers/net/pcs/pcs-qcom-ipq9574.c
+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
-@@ -60,6 +60,9 @@
+@@ -55,6 +55,9 @@
FIELD_PREP(GENMASK(9, 2), \
FIELD_GET(XPCS_INDIRECT_ADDR_L, reg)))
-+#define XPCS_10GBASER_STS 0x30020
-+#define XPCS_10GBASER_LINK_STS BIT(12)
++#define XPCS_KR_STS 0x30020
++#define XPCS_KR_LINK_STS BIT(12)
+
#define XPCS_DIG_CTRL 0x38000
#define XPCS_USXG_ADPT_RESET BIT(10)
#define XPCS_USXG_EN BIT(9)
-@@ -229,6 +232,28 @@ static void ipq_pcs_get_state_usxgmii(st
+@@ -196,6 +199,28 @@ static void ipq_pcs_get_state_usxgmii(st
state->duplex = DUPLEX_FULL;
}
-+static void ipq_unipcs_get_state_10gbaser(struct ipq_pcs *qpcs,
-+ struct phylink_link_state *state)
++static void ipq_pcs_get_state_10gbaser(struct ipq_pcs *qpcs,
++ struct phylink_link_state *state)
+{
+ unsigned int val;
+ int ret;
+
-+ ret = regmap_read(qpcs->regmap, XPCS_10GBASER_STS, &val);
++ ret = regmap_read(qpcs->regmap, XPCS_KR_STS, &val);
+ if (ret) {
+ state->link = 0;
+ return;
+ }
+
-+ state->link = !!(val & XPCS_10GBASER_LINK_STS);
++ state->link = !!(val & XPCS_KR_LINK_STS);
+
+ if (!state->link)
+ return;
@@ -55,49 +56,31 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
static int ipq_pcs_config_mode(struct ipq_pcs *qpcs,
phy_interface_t interface)
{
-@@ -251,6 +276,7 @@ static int ipq_pcs_config_mode(struct ip
- val = PCS_MODE_PSGMII;
+@@ -212,6 +237,7 @@ static int ipq_pcs_config_mode(struct ip
+ val = PCS_MODE_QSGMII;
break;
case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_10GBASER:
val = PCS_MODE_XPCS;
rate = 312500000;
break;
-@@ -355,6 +381,25 @@ static int ipq_pcs_config_usxgmii(struct
+@@ -311,6 +337,15 @@ static int ipq_pcs_config_usxgmii(struct
return regmap_set_bits(qpcs->regmap, XPCS_MII_CTRL, XPCS_MII_AN_EN);
}
-+static int ipq_unipcs_config_10gbaser(struct ipq_pcs *qpcs,
-+ phy_interface_t interface)
++static int ipq_pcs_config_10gbaser(struct ipq_pcs *qpcs)
+{
-+ int ret;
-+
-+ if (qpcs->interface != interface) {
-+ ret = ipq_pcs_config_mode(qpcs, interface);
-+ if (ret)
-+ return ret;
-+
-+ /* Deassert XPCS */
-+ reset_control_deassert(qpcs->reset[XPCS_RESET]);
-+
-+ qpcs->interface = interface;
-+ }
++ /* Configure 10GBASER mode if required */
++ if (qpcs->interface == PHY_INTERFACE_MODE_10GBASER)
++ return 0;
+
-+ return 0;
++ return ipq_pcs_config_mode(qpcs, PHY_INTERFACE_MODE_10GBASER);
+}
+
- static unsigned long ipq_unipcs_clock_rate_get_gmii(int speed)
- {
- unsigned long rate = 0;
-@@ -421,6 +466,7 @@ ipq_unipcs_link_up_clock_rate_set(struct
- rate = ipq_unipcs_clock_rate_get_gmii(speed);
- break;
- case PHY_INTERFACE_MODE_USXGMII:
-+ case PHY_INTERFACE_MODE_10GBASER:
- rate = ipq_unipcs_clock_rate_get_xgmii(speed);
- break;
- default:
-@@ -528,6 +574,7 @@ static int ipq_pcs_validate(struct phyli
+ static int ipq_pcs_link_up_config_sgmii(struct ipq_pcs *qpcs,
+ int index,
+ unsigned int neg_mode,
+@@ -399,6 +434,7 @@ static int ipq_pcs_validate(struct phyli
switch (state->interface) {
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_QSGMII:
@@ -105,44 +88,45 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
return 0;
case PHY_INTERFACE_MODE_USXGMII:
/* USXGMII only supports full duplex mode */
-@@ -546,6 +593,7 @@ static unsigned int ipq_pcs_inband_caps(
- case PHY_INTERFACE_MODE_SGMII:
+@@ -418,6 +454,8 @@ static unsigned int ipq_pcs_inband_caps(
case PHY_INTERFACE_MODE_QSGMII:
case PHY_INTERFACE_MODE_USXGMII:
-+ case PHY_INTERFACE_MODE_10GBASER:
return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
++ case PHY_INTERFACE_MODE_10GBASER:
++ return LINK_INBAND_DISABLE;
default:
return 0;
-@@ -602,6 +650,9 @@ static void ipq_pcs_get_state(struct phy
+ }
+@@ -472,6 +510,9 @@ static void ipq_pcs_get_state(struct phy
case PHY_INTERFACE_MODE_USXGMII:
ipq_pcs_get_state_usxgmii(qpcs, state);
break;
+ case PHY_INTERFACE_MODE_10GBASER:
-+ ipq_unipcs_get_state_10gbaser(qpcs, state);
++ ipq_pcs_get_state_10gbaser(qpcs, state);
+ break;
default:
break;
}
-@@ -631,6 +682,8 @@ static int ipq_pcs_config(struct phylink
+@@ -500,6 +541,8 @@ static int ipq_pcs_config(struct phylink
return ipq_pcs_config_sgmii(qpcs, index, neg_mode, interface);
case PHY_INTERFACE_MODE_USXGMII:
return ipq_pcs_config_usxgmii(qpcs);
+ case PHY_INTERFACE_MODE_10GBASER:
-+ return ipq_unipcs_config_10gbaser(qpcs, interface);
++ return ipq_pcs_config_10gbaser(qpcs);
default:
- dev_err(qpcs->dev,
- "interface %s not supported\n", phy_modes(interface));
-@@ -662,6 +715,9 @@ static void ipq_pcs_link_up(struct phyli
+ return -EOPNOTSUPP;
+ };
+@@ -524,6 +567,9 @@ static void ipq_pcs_link_up(struct phyli
case PHY_INTERFACE_MODE_USXGMII:
ret = ipq_pcs_link_up_config_usxgmii(qpcs, speed);
break;
+ case PHY_INTERFACE_MODE_10GBASER:
+ /* Nothing to do here */
-+ break;
++ return;
default:
- dev_err(qpcs->dev,
- "interface %s not supported\n", phy_modes(interface));
-@@ -730,6 +786,7 @@ static unsigned long ipq_pcs_clk_rate_ge
+ return;
+ }
+@@ -603,6 +649,7 @@ static unsigned long ipq_pcs_clk_rate_ge
{
switch (qpcs->interface) {
case PHY_INTERFACE_MODE_USXGMII:
diff --git a/target/linux/qualcommbe/patches-6.12/0362-net-pcs-Add-2500BASEX-interface-mode-support-to-IPQ-.patch b/target/linux/qualcommbe/patches-6.12/0362-net-pcs-Add-2500BASEX-interface-mode-support-to-IPQ-.patch
index dff74f0224..fbdebec13a 100644
--- a/target/linux/qualcommbe/patches-6.12/0362-net-pcs-Add-2500BASEX-interface-mode-support-to-IPQ-.patch
+++ b/target/linux/qualcommbe/patches-6.12/0362-net-pcs-Add-2500BASEX-interface-mode-support-to-IPQ-.patch
@@ -1,4 +1,4 @@
-From a2e687df29e457621616d5d769688e6c972f9ac6 Mon Sep 17 00:00:00 2001
+From 0d3a93e3a5544daec59d8f10ac5ccab39849536e Mon Sep 17 00:00:00 2001
From: Lei Wei <quic_leiwei at quicinc.com>
Date: Tue, 2 Apr 2024 18:28:42 +0800
Subject: [PATCH] net: pcs: Add 2500BASEX interface mode support to IPQ UNIPHY
@@ -12,33 +12,33 @@ connects with a 2.5G SFP module.
Change-Id: I3fe61113c1b3685debc20659736a9488216a029d
Signed-off-by: Lei Wei <quic_leiwei at quicinc.com>
Alex G: use regmap to read/write registers
+ 's/ipq_unipcs/ipq_pcs/' in function names as suggested by Luo Jie
Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
---
- drivers/net/pcs/pcs-qcom-ipq9574.c | 95 ++++++++++++++++++++++++++++++
- 1 file changed, 95 insertions(+)
+ drivers/net/pcs/pcs-qcom-ipq9574.c | 67 ++++++++++++++++++++++++++++++
+ 1 file changed, 67 insertions(+)
--- a/drivers/net/pcs/pcs-qcom-ipq9574.c
+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
-@@ -29,6 +29,7 @@
+@@ -26,6 +26,7 @@
+ #define PCS_MODE_SEL_MASK GENMASK(12, 8)
#define PCS_MODE_SGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x4)
#define PCS_MODE_QSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x1)
- #define PCS_MODE_PSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x2)
-+#define PCS_MODE_SGMII_PLUS FIELD_PREP(PCS_MODE_SEL_MASK, 0x8)
++#define PCS_MODE_2500BASEX FIELD_PREP(PCS_MODE_SEL_MASK, 0x8)
#define PCS_MODE_XPCS FIELD_PREP(PCS_MODE_SEL_MASK, 0x10)
#define PCS_MII_CTRL(x) (0x480 + 0x18 * (x))
-@@ -188,6 +189,30 @@ static void ipq_pcs_get_state_sgmii(stru
- state->pause |= MLO_PAUSE_RX;
+@@ -155,6 +156,29 @@ static void ipq_pcs_get_state_sgmii(stru
+ state->duplex = DUPLEX_HALF;
}
-+static void ipq_unipcs_get_state_2500basex(struct ipq_pcs *qpcs,
-+ int index,
-+ struct phylink_link_state *state)
++static void ipq_pcs_get_state_2500basex(struct ipq_pcs *qpcs,
++ struct phylink_link_state *state)
+{
-+ unsigned int val;
++ unsigned int val;
+ int ret;
+
-+ ret = regmap_read(qpcs->regmap, PCS_MII_STS(index), &val);
++ ret = regmap_read(qpcs->regmap, PCS_MII_STS(0), &val);
+ if (ret) {
+ state->link = 0;
+ return;
@@ -58,99 +58,57 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
static void ipq_pcs_get_state_usxgmii(struct ipq_pcs *qpcs,
struct phylink_link_state *state)
{
-@@ -272,6 +297,10 @@ static int ipq_pcs_config_mode(struct ip
+@@ -236,6 +260,10 @@ static int ipq_pcs_config_mode(struct ip
case PHY_INTERFACE_MODE_QSGMII:
val = PCS_MODE_QSGMII;
break;
+ case PHY_INTERFACE_MODE_2500BASEX:
-+ val = PCS_MODE_SGMII_PLUS;
++ val = PCS_MODE_2500BASEX;
+ rate = 312500000;
+ break;
- case PHY_INTERFACE_MODE_PSGMII:
- val = PCS_MODE_PSGMII;
- break;
-@@ -355,6 +384,22 @@ static int ipq_pcs_config_sgmii(struct i
+ case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_10GBASER:
+ val = PCS_MODE_XPCS;
+@@ -314,6 +342,15 @@ static int ipq_pcs_config_sgmii(struct i
PCS_MII_CTRL(index), PCS_MII_FORCE_MODE);
}
-+static int ipq_unipcs_config_2500basex(struct ipq_pcs *qpcs,
-+ phy_interface_t interface)
++static int ipq_pcs_config_2500basex(struct ipq_pcs *qpcs)
+{
-+ int ret;
-+
-+ if (qpcs->interface != interface) {
-+ ret = ipq_pcs_config_mode(qpcs, interface);
-+ if (ret)
-+ return ret;
-+
-+ qpcs->interface = interface;
-+ }
++ /* Configure PCS for 2500BASEX mode if required */
++ if (qpcs->interface == PHY_INTERFACE_MODE_2500BASEX)
++ return 0;
+
-+ return 0;
++ return ipq_pcs_config_mode(qpcs, PHY_INTERFACE_MODE_2500BASEX);
+}
+
static int ipq_pcs_config_usxgmii(struct ipq_pcs *qpcs)
{
int ret;
-@@ -421,6 +466,21 @@ static unsigned long ipq_unipcs_clock_ra
- return rate;
- }
-
-+static unsigned long ipq_unipcs_clock_rate_get_gmiiplus(int speed)
-+{
-+ unsigned long rate = 0;
-+
-+ switch (speed) {
-+ case SPEED_2500:
-+ rate = 312500000;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return rate;
-+}
-+
- static unsigned long ipq_unipcs_clock_rate_get_xgmii(int speed)
- {
- unsigned long rate = 0;
-@@ -465,6 +525,9 @@ ipq_unipcs_link_up_clock_rate_set(struct
- case PHY_INTERFACE_MODE_PSGMII:
- rate = ipq_unipcs_clock_rate_get_gmii(speed);
- break;
-+ case PHY_INTERFACE_MODE_2500BASEX:
-+ rate = ipq_unipcs_clock_rate_get_gmiiplus(speed);
-+ break;
- case PHY_INTERFACE_MODE_USXGMII:
- case PHY_INTERFACE_MODE_10GBASER:
- rate = ipq_unipcs_clock_rate_get_xgmii(speed);
-@@ -528,6 +591,25 @@ static int ipq_pcs_link_up_config_sgmii(
+@@ -388,6 +425,22 @@ static int ipq_pcs_link_up_config_sgmii(
PCS_MII_CTRL(index), PCS_MII_ADPT_RESET);
}
-+static int ipq_unipcs_link_up_config_2500basex(struct ipq_pcs *qpcs,
-+ int index,
-+ int speed)
++static int ipq_pcs_link_up_config_2500basex(struct ipq_pcs *qpcs, int speed)
+{
-+ unsigned int val;
+ int ret;
+
-+ /* 2500BASEX do not support autoneg and do not need to
-+ * configure PCS speed, only reset PCS adapter here.
++ /* 2500BASEX does not support autoneg and does not need to
++ * configure PCS speed. Only reset PCS adapter here.
+ */
+ ret = regmap_clear_bits(qpcs->regmap,
-+ PCS_MII_CTRL(index), PCS_MII_ADPT_RESET);
++ PCS_MII_CTRL(0), PCS_MII_ADPT_RESET);
+ if (ret)
+ return ret;
+
+ return regmap_set_bits(qpcs->regmap,
-+ PCS_MII_CTRL(index), PCS_MII_ADPT_RESET);
++ PCS_MII_CTRL(0), PCS_MII_ADPT_RESET);
+}
+
static int ipq_pcs_link_up_config_usxgmii(struct ipq_pcs *qpcs, int speed)
{
unsigned int val;
-@@ -576,6 +658,10 @@ static int ipq_pcs_validate(struct phyli
+@@ -436,6 +489,10 @@ static int ipq_pcs_validate(struct phyli
case PHY_INTERFACE_MODE_QSGMII:
case PHY_INTERFACE_MODE_10GBASER:
return 0;
@@ -161,36 +119,44 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
case PHY_INTERFACE_MODE_USXGMII:
/* USXGMII only supports full duplex mode */
phylink_clear(supported, 100baseT_Half);
-@@ -647,6 +733,9 @@ static void ipq_pcs_get_state(struct phy
- case PHY_INTERFACE_MODE_PSGMII:
+@@ -454,6 +511,7 @@ static unsigned int ipq_pcs_inband_caps(
+ case PHY_INTERFACE_MODE_QSGMII:
+ case PHY_INTERFACE_MODE_USXGMII:
+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
++ case PHY_INTERFACE_MODE_2500BASEX:
+ case PHY_INTERFACE_MODE_10GBASER:
+ return LINK_INBAND_DISABLE;
+ default:
+@@ -507,6 +565,9 @@ static void ipq_pcs_get_state(struct phy
+ case PHY_INTERFACE_MODE_QSGMII:
ipq_pcs_get_state_sgmii(qpcs, index, state);
break;
+ case PHY_INTERFACE_MODE_2500BASEX:
-+ ipq_unipcs_get_state_2500basex(qpcs, index, state);
++ ipq_pcs_get_state_2500basex(qpcs, state);
+ break;
case PHY_INTERFACE_MODE_USXGMII:
ipq_pcs_get_state_usxgmii(qpcs, state);
break;
-@@ -680,6 +769,8 @@ static int ipq_pcs_config(struct phylink
+@@ -539,6 +600,8 @@ static int ipq_pcs_config(struct phylink
+ case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_QSGMII:
- case PHY_INTERFACE_MODE_PSGMII:
return ipq_pcs_config_sgmii(qpcs, index, neg_mode, interface);
+ case PHY_INTERFACE_MODE_2500BASEX:
-+ return ipq_unipcs_config_2500basex(qpcs, interface);
++ return ipq_pcs_config_2500basex(qpcs);
case PHY_INTERFACE_MODE_USXGMII:
return ipq_pcs_config_usxgmii(qpcs);
case PHY_INTERFACE_MODE_10GBASER:
-@@ -712,6 +803,9 @@ static void ipq_pcs_link_up(struct phyli
+@@ -564,6 +627,9 @@ static void ipq_pcs_link_up(struct phyli
ret = ipq_pcs_link_up_config_sgmii(qpcs, index,
neg_mode, speed);
break;
+ case PHY_INTERFACE_MODE_2500BASEX:
-+ ret = ipq_unipcs_link_up_config_2500basex(qpcs, index, speed);
++ ret = ipq_pcs_link_up_config_2500basex(qpcs, speed);
+ break;
case PHY_INTERFACE_MODE_USXGMII:
ret = ipq_pcs_link_up_config_usxgmii(qpcs, speed);
break;
-@@ -785,6 +879,7 @@ static int ipq_pcs_create_miis(struct ip
+@@ -648,6 +714,7 @@ static int ipq_pcs_create_miis(struct ip
static unsigned long ipq_pcs_clk_rate_get(struct ipq_pcs *qpcs)
{
switch (qpcs->interface) {
diff --git a/target/linux/qualcommbe/patches-6.12/0363-net-pcs-Add-1000BASEX-interface-mode-support-to-IPQ-.patch b/target/linux/qualcommbe/patches-6.12/0363-net-pcs-Add-1000BASEX-interface-mode-support-to-IPQ-.patch
index 9c6bfabc45..37aa60d8ff 100644
--- a/target/linux/qualcommbe/patches-6.12/0363-net-pcs-Add-1000BASEX-interface-mode-support-to-IPQ-.patch
+++ b/target/linux/qualcommbe/patches-6.12/0363-net-pcs-Add-1000BASEX-interface-mode-support-to-IPQ-.patch
@@ -1,4 +1,4 @@
-From 07f9bb8eb006e9664d651089a1f422d045e093e3 Mon Sep 17 00:00:00 2001
+From d82953614a4f09dd7479e1d3904351ff85d1d088 Mon Sep 17 00:00:00 2001
From: Lei Wei <quic_leiwei at quicinc.com>
Date: Tue, 9 Apr 2024 01:07:22 +0800
Subject: [PATCH] net: pcs: Add 1000BASEX interface mode support to IPQ UNIPHY
@@ -10,70 +10,75 @@ Change-Id: Ied7298de3c1ecba74e6457a07fdd6b3ceab79728
Signed-off-by: Lei Wei <quic_leiwei at quicinc.com>
Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
---
- drivers/net/pcs/pcs-qcom-ipq9574.c | 19 +++++++++++++++++--
- 1 file changed, 17 insertions(+), 2 deletions(-)
+ drivers/net/pcs/pcs-qcom-ipq9574.c | 21 ++++++++++++++++++---
+ 1 file changed, 18 insertions(+), 3 deletions(-)
--- a/drivers/net/pcs/pcs-qcom-ipq9574.c
+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
-@@ -31,6 +31,9 @@
- #define PCS_MODE_PSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x2)
- #define PCS_MODE_SGMII_PLUS FIELD_PREP(PCS_MODE_SEL_MASK, 0x8)
+@@ -28,6 +28,9 @@
+ #define PCS_MODE_QSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x1)
+ #define PCS_MODE_2500BASEX FIELD_PREP(PCS_MODE_SEL_MASK, 0x8)
#define PCS_MODE_XPCS FIELD_PREP(PCS_MODE_SEL_MASK, 0x10)
-+#define PCS_MODE_SGMII_CTRL_MASK GENMASK(6, 4)
-+#define PCS_MODE_SGMII_CTRL_1000BASEX FIELD_PREP(PCS_MODE_SGMII_CTRL_MASK, \
++#define PCS_MODE_SGMII_MODE_MASK GENMASK(6, 4)
++#define PCS_MODE_SGMII_MODE_1000BASEX FIELD_PREP(PCS_MODE_SGMII_MODE_MASK, \
+ 0x0)
#define PCS_MII_CTRL(x) (0x480 + 0x18 * (x))
#define PCS_MII_ADPT_RESET BIT(11)
-@@ -283,7 +286,7 @@ static int ipq_pcs_config_mode(struct ip
+@@ -249,10 +252,11 @@ static int ipq_pcs_config_mode(struct ip
phy_interface_t interface)
{
unsigned long rate = 125000000;
- unsigned int val;
-+ unsigned int val, mask = PCS_MODE_SEL_MASK;
++ unsigned int val, mask;
int ret;
- /* Assert XPCS reset */
-@@ -297,6 +300,10 @@ static int ipq_pcs_config_mode(struct ip
+ /* Configure PCS interface mode */
++ mask = PCS_MODE_SEL_MASK;
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ val = PCS_MODE_SGMII;
+@@ -260,6 +264,10 @@ static int ipq_pcs_config_mode(struct ip
case PHY_INTERFACE_MODE_QSGMII:
val = PCS_MODE_QSGMII;
break;
+ case PHY_INTERFACE_MODE_1000BASEX:
-+ mask |= PCS_MODE_SGMII_CTRL_MASK;
-+ val = PCS_MODE_SGMII | PCS_MODE_SGMII_CTRL_1000BASEX;
++ mask |= PCS_MODE_SGMII_MODE_MASK;
++ val = PCS_MODE_SGMII | PCS_MODE_SGMII_MODE_1000BASEX;
+ break;
case PHY_INTERFACE_MODE_2500BASEX:
- val = PCS_MODE_SGMII_PLUS;
+ val = PCS_MODE_2500BASEX;
rate = 312500000;
-@@ -316,7 +323,7 @@ static int ipq_pcs_config_mode(struct ip
+@@ -273,8 +281,7 @@ static int ipq_pcs_config_mode(struct ip
+ return -EOPNOTSUPP;
}
- ret = regmap_update_bits(qpcs->regmap, PCS_MODE_CTRL,
+- ret = regmap_update_bits(qpcs->regmap, PCS_MODE_CTRL,
- PCS_MODE_SEL_MASK, val);
-+ mask, val);
++ ret = regmap_update_bits(qpcs->regmap, PCS_MODE_CTRL, mask, val);
if (ret)
return ret;
-@@ -523,6 +530,7 @@ ipq_unipcs_link_up_clock_rate_set(struct
+@@ -487,6 +494,7 @@ static int ipq_pcs_validate(struct phyli
+ switch (state->interface) {
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_QSGMII:
- case PHY_INTERFACE_MODE_PSGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
- rate = ipq_unipcs_clock_rate_get_gmii(speed);
- break;
+ case PHY_INTERFACE_MODE_10GBASER:
+ return 0;
case PHY_INTERFACE_MODE_2500BASEX:
-@@ -657,6 +665,7 @@ static int ipq_pcs_validate(struct phyli
+@@ -509,6 +517,7 @@ static unsigned int ipq_pcs_inband_caps(
+ switch (interface) {
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_QSGMII:
- case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_1000BASEX:
- return 0;
+ case PHY_INTERFACE_MODE_USXGMII:
+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
case PHY_INTERFACE_MODE_2500BASEX:
- /* In-band autoneg is not supported for 2500BASEX */
-@@ -731,6 +740,10 @@ static void ipq_pcs_get_state(struct phy
+@@ -563,6 +572,10 @@ static void ipq_pcs_get_state(struct phy
+ switch (state->interface) {
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_QSGMII:
- case PHY_INTERFACE_MODE_PSGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ /* SGMII and 1000BASEX in-band autoneg word format are decoded
+ * by PCS hardware and both placed to the same status register.
@@ -81,18 +86,18 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
ipq_pcs_get_state_sgmii(qpcs, index, state);
break;
case PHY_INTERFACE_MODE_2500BASEX:
-@@ -768,6 +781,7 @@ static int ipq_pcs_config(struct phylink
+@@ -599,6 +612,7 @@ static int ipq_pcs_config(struct phylink
+ switch (interface) {
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_QSGMII:
- case PHY_INTERFACE_MODE_PSGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
return ipq_pcs_config_sgmii(qpcs, index, neg_mode, interface);
case PHY_INTERFACE_MODE_2500BASEX:
- return ipq_unipcs_config_2500basex(qpcs, interface);
-@@ -800,6 +814,7 @@ static void ipq_pcs_link_up(struct phyli
+ return ipq_pcs_config_2500basex(qpcs);
+@@ -624,6 +638,7 @@ static void ipq_pcs_link_up(struct phyli
+ switch (interface) {
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_QSGMII:
- case PHY_INTERFACE_MODE_PSGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
ret = ipq_pcs_link_up_config_sgmii(qpcs, index,
neg_mode, speed);
diff --git a/target/linux/qualcommbe/patches-6.12/0364-net-pcs-Add-10G_QXGMII-interface-mode-support-to-IPQ.patch b/target/linux/qualcommbe/patches-6.12/0364-net-pcs-Add-10G_QXGMII-interface-mode-support-to-IPQ.patch
index 03fa4dffef..2563ac8396 100644
--- a/target/linux/qualcommbe/patches-6.12/0364-net-pcs-Add-10G_QXGMII-interface-mode-support-to-IPQ.patch
+++ b/target/linux/qualcommbe/patches-6.12/0364-net-pcs-Add-10G_QXGMII-interface-mode-support-to-IPQ.patch
@@ -1,4 +1,4 @@
-From 77462c0d74e51a24408062b93c3fcc0256909d33 Mon Sep 17 00:00:00 2001
+From fc26c6f6c69149ce87c88d6878ae929b2a138063 Mon Sep 17 00:00:00 2001
From: Lei Wei <quic_leiwei at quicinc.com>
Date: Mon, 15 Apr 2024 11:06:02 +0800
Subject: [PATCH] net: pcs: Add 10G_QXGMII interface mode support to IPQ UNIPHY
@@ -11,14 +11,14 @@ Change-Id: If3dc92a07ac3e51f7c9473fb05fa0668617916fb
Signed-off-by: Lei Wei <quic_leiwei at quicinc.com>
Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
---
- drivers/net/pcs/pcs-qcom-ipq9574.c | 112 +++++++++++++++++++++++------
- 1 file changed, 91 insertions(+), 21 deletions(-)
+ drivers/net/pcs/pcs-qcom-ipq9574.c | 109 +++++++++++++++++++++++------
+ 1 file changed, 87 insertions(+), 22 deletions(-)
--- a/drivers/net/pcs/pcs-qcom-ipq9574.c
+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
-@@ -53,6 +53,9 @@
- #define PCS_MII_STS_PAUSE_TX_EN BIT(1)
- #define PCS_MII_STS_PAUSE_RX_EN BIT(0)
+@@ -48,6 +48,9 @@
+ #define PCS_MII_STS_SPEED_100 1
+ #define PCS_MII_STS_SPEED_1000 2
+#define PCS_QP_USXG_OPTION 0x584
+#define PCS_QP_USXG_GMII_SRC_XPCS BIT(0)
@@ -26,8 +26,8 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
#define PCS_PLL_RESET 0x780
#define PCS_ANA_SW_RESET BIT(6)
-@@ -68,10 +71,22 @@
- #define XPCS_10GBASER_LINK_STS BIT(12)
+@@ -63,10 +66,23 @@
+ #define XPCS_KR_LINK_STS BIT(12)
#define XPCS_DIG_CTRL 0x38000
+#define XPCS_SOFT_RESET BIT(15)
@@ -41,82 +41,89 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+#define XPCS_DIG_STS 0x3800a
+#define XPCS_DIG_STS_AM_COUNT GENMASK(14, 0)
+
-+#define XPCS_CHANNEL_DIG_CTRL(x) (0x1a8000 + 0x10000 * ((x) - 1))
-+#define XPCS_CHANNEL_USXG_ADPT_RESET BIT(5)
++/* DIG control for MII1 - MII3 */
++#define XPCS_MII1_DIG_CTRL(x) (0x1a8000 + 0x10000 * ((x) - 1))
++#define XPCS_MII1_USXG_ADPT_RESET BIT(5)
+
#define XPCS_MII_CTRL 0x1f0000
-+#define XPCS_CHANNEL_MII_CTRL(x) (0x1a0000 + 0x10000 * ((x) - 1))
++#define XPCS_MII1_CTRL(x) (0x1a0000 + 0x10000 * ((x) - 1))
#define XPCS_MII_AN_EN BIT(12)
#define XPCS_DUPLEX_FULL BIT(8)
#define XPCS_SPEED_MASK (BIT(13) | BIT(6) | BIT(5))
-@@ -83,9 +98,11 @@
+@@ -78,9 +94,11 @@
#define XPCS_SPEED_10 0
#define XPCS_MII_AN_CTRL 0x1f8001
-+#define XPCS_CHANNEL_MII_AN_CTRL(x) (0x1a8001 + 0x10000 * ((x) - 1))
++#define XPCS_MII1_AN_CTRL(x) (0x1a8001 + 0x10000 * ((x) - 1))
#define XPCS_MII_AN_8BIT BIT(8)
#define XPCS_MII_AN_INTR_STS 0x1f8002
-+#define XPCS_CHANNEL_MII_AN_INTR_STS(x) (0x1a8002 + 0x10000 * ((x) - 1))
++#define XPCS_MII1_AN_INTR_STS(x) (0x1a8002 + 0x10000 * ((x) - 1))
#define XPCS_USXG_AN_LINK_STS BIT(14)
#define XPCS_USXG_AN_SPEED_MASK GENMASK(12, 10)
#define XPCS_USXG_AN_SPEED_10 0
-@@ -95,6 +112,10 @@
+@@ -90,6 +108,10 @@
#define XPCS_USXG_AN_SPEED_5000 5
#define XPCS_USXG_AN_SPEED_10000 3
+#define XPCS_XAUI_MODE_CTRL 0x1f8004
-+#define XPCS_CHANNEL_XAUI_MODE_CTRL(x) (0x1a8004 + 0x10000 * ((x) - 1))
++#define XPCS_MII1_XAUI_MODE_CTRL(x) (0x1a8004 + 0x10000 * ((x) - 1))
+#define XPCS_TX_IPG_CHECK_DIS BIT(0)
+
/* Per PCS MII private data */
struct ipq_pcs_mii {
struct ipq_pcs *qpcs;
-@@ -217,12 +238,16 @@ static void ipq_unipcs_get_state_2500bas
+@@ -182,13 +204,14 @@ static void ipq_pcs_get_state_2500basex(
+ state->pause |= MLO_PAUSE_TXRX_MASK;
}
- static void ipq_pcs_get_state_usxgmii(struct ipq_pcs *qpcs,
-+ int index,
+-static void ipq_pcs_get_state_usxgmii(struct ipq_pcs *qpcs,
++static void ipq_pcs_get_state_usxgmii(struct ipq_pcs *qpcs, int index,
struct phylink_link_state *state)
{
- unsigned int val;
-- int ret;
-+ int ret, reg;
-+
-+ reg = (index == 0) ? XPCS_MII_AN_INTR_STS :
-+ XPCS_CHANNEL_MII_AN_INTR_STS(index);
+- unsigned int val;
++ unsigned int reg, val;
+ int ret;
- ret = regmap_read(qpcs->regmap, XPCS_MII_AN_INTR_STS, &val);
++ reg = (index == 0) ? XPCS_MII_AN_INTR_STS : XPCS_MII1_AN_INTR_STS(index);
+ ret = regmap_read(qpcs->regmap, reg, &val);
if (ret) {
state->link = 0;
return;
-@@ -316,6 +341,14 @@ static int ipq_pcs_config_mode(struct ip
- val = PCS_MODE_XPCS;
+@@ -273,6 +296,7 @@ static int ipq_pcs_config_mode(struct ip
rate = 312500000;
break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_10G_QXGMII:
-+ val = PCS_MODE_XPCS;
-+ rate = 312500000;
+ case PHY_INTERFACE_MODE_10GBASER:
+ val = PCS_MODE_XPCS;
+ rate = 312500000;
+@@ -285,6 +309,13 @@ static int ipq_pcs_config_mode(struct ip
+ if (ret)
+ return ret;
+
++ if (interface == PHY_INTERFACE_MODE_10G_QXGMII) {
+ ret = regmap_set_bits(qpcs->regmap, PCS_QP_USXG_OPTION,
+ PCS_QP_USXG_GMII_SRC_XPCS);
+ if (ret)
+ return ret;
-+ break;
- default:
- dev_err(qpcs->dev,
- "interface %s not supported\n", phy_modes(interface));
-@@ -407,30 +440,55 @@ static int ipq_unipcs_config_2500basex(s
- return 0;
++ }
++
+ /* PCS PLL reset */
+ ret = regmap_clear_bits(qpcs->regmap, PCS_PLL_RESET, PCS_ANA_SW_RESET);
+ if (ret)
+@@ -358,27 +389,51 @@ static int ipq_pcs_config_2500basex(stru
+ return ipq_pcs_config_mode(qpcs, PHY_INTERFACE_MODE_2500BASEX);
}
-static int ipq_pcs_config_usxgmii(struct ipq_pcs *qpcs)
+static int ipq_pcs_config_usxgmii(struct ipq_pcs *qpcs,
-+ int index,
-+ phy_interface_t interface)
++ int index,
++ phy_interface_t interface)
{
-- int ret;
-+ int ret, reg;
++ unsigned int reg;
+ int ret;
/* Configure the XPCS for USXGMII mode if required */
- if (qpcs->interface == PHY_INTERFACE_MODE_USXGMII)
@@ -129,87 +136,66 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ ret = ipq_pcs_config_mode(qpcs, interface);
+ if (ret)
+ return ret;
-+ }
-
-- /* Deassert XPCS and configure XPCS USXGMII */
-+ /* Deassert XPCS and configure XPCS USXGMII or 10G_QXGMII */
- reset_control_deassert(qpcs->reset[XPCS_RESET]);
-
- ret = regmap_set_bits(qpcs->regmap, XPCS_DIG_CTRL, XPCS_USXG_EN);
- if (ret)
- return ret;
-- ret = regmap_set_bits(qpcs->regmap, XPCS_MII_AN_CTRL, XPCS_MII_AN_8BIT);
-+ if (interface == PHY_INTERFACE_MODE_10G_QXGMII) {
-+ regmap_update_bits(qpcs->regmap, XPCS_KR_CTRL,
-+ XPCS_USXG_MODE_MASK, XPCS_10G_QXGMII_MODE);
+- ret = regmap_set_bits(qpcs->regmap, XPCS_DIG_CTRL, XPCS_USXG_EN);
+- if (ret)
+- return ret;
++ if (interface == PHY_INTERFACE_MODE_10G_QXGMII) {
++ ret = regmap_update_bits(qpcs->regmap, XPCS_KR_CTRL,
++ XPCS_USXG_MODE_MASK, XPCS_10G_QXGMII_MODE);
++ if (ret)
++ return ret;
+
-+ /* Set Alignment Marker Interval */
-+ regmap_update_bits(qpcs->regmap, XPCS_DIG_STS,
-+ XPCS_DIG_STS_AM_COUNT, 0x6018);
++ /* Set Alignment Marker Interval value as 0x6018 */
++ ret = regmap_update_bits(qpcs->regmap, XPCS_DIG_STS,
++ XPCS_DIG_STS_AM_COUNT, 0x6018);
++ if (ret)
++ return ret;
+
-+ regmap_set_bits(qpcs->regmap, XPCS_DIG_CTRL, XPCS_SOFT_RESET);
++ ret = regmap_set_bits(qpcs->regmap, XPCS_DIG_CTRL, XPCS_SOFT_RESET);
++ if (ret)
++ return ret;
+ }
+
-+ qpcs->interface = interface;
-+
+ /* Disable Tx IPG check for 10G_QXGMII */
+ if (interface == PHY_INTERFACE_MODE_10G_QXGMII) {
-+ reg = (index == 0) ? XPCS_XAUI_MODE_CTRL :
-+ XPCS_CHANNEL_XAUI_MODE_CTRL(index);
-+
-+ regmap_set_bits(qpcs->regmap, reg, XPCS_TX_IPG_CHECK_DIS);
++ reg = (index == 0) ? XPCS_XAUI_MODE_CTRL : XPCS_MII1_XAUI_MODE_CTRL(index);
++ ret = regmap_set_bits(qpcs->regmap, reg, XPCS_TX_IPG_CHECK_DIS);
++ if (ret)
++ return ret;
+ }
-+
-+ /* Enable autoneg */
-+ reg = (index == 0) ? XPCS_MII_AN_CTRL : XPCS_CHANNEL_MII_AN_CTRL(index);
+
+- ret = regmap_set_bits(qpcs->regmap, XPCS_MII_AN_CTRL, XPCS_MII_AN_8BIT);
++ reg = (index == 0) ? XPCS_MII_AN_CTRL : XPCS_MII1_AN_CTRL(index);
+ ret = regmap_set_bits(qpcs->regmap, reg, XPCS_MII_AN_8BIT);
if (ret)
return ret;
- return regmap_set_bits(qpcs->regmap, XPCS_MII_CTRL, XPCS_MII_AN_EN);
-+ reg = (index == 0) ? XPCS_MII_CTRL : XPCS_CHANNEL_MII_CTRL(index);
++ reg = (index == 0) ? XPCS_MII_CTRL : XPCS_MII1_CTRL(index);
+ return regmap_set_bits(qpcs->regmap, reg, XPCS_MII_AN_EN);
}
- static int ipq_unipcs_config_10gbaser(struct ipq_pcs *qpcs,
-@@ -538,6 +596,7 @@ ipq_unipcs_link_up_clock_rate_set(struct
- break;
- case PHY_INTERFACE_MODE_USXGMII:
- case PHY_INTERFACE_MODE_10GBASER:
-+ case PHY_INTERFACE_MODE_10G_QXGMII:
- rate = ipq_unipcs_clock_rate_get_xgmii(speed);
- break;
- default:
-@@ -603,7 +662,6 @@ static int ipq_unipcs_link_up_config_250
- int index,
- int speed)
- {
-- unsigned int val;
- int ret;
-
- /* 2500BASEX do not support autoneg and do not need to
-@@ -618,10 +676,12 @@ static int ipq_unipcs_link_up_config_250
- PCS_MII_CTRL(index), PCS_MII_ADPT_RESET);
+ static int ipq_pcs_config_10gbaser(struct ipq_pcs *qpcs)
+@@ -448,9 +503,10 @@ static int ipq_pcs_link_up_config_2500ba
+ PCS_MII_CTRL(0), PCS_MII_ADPT_RESET);
}
-static int ipq_pcs_link_up_config_usxgmii(struct ipq_pcs *qpcs, int speed)
+static int ipq_pcs_link_up_config_usxgmii(struct ipq_pcs *qpcs,
-+ int channel,
-+ int speed)
++ int index, int speed)
{
- unsigned int val;
-- int ret;
-+ int ret, reg;
+- unsigned int val;
++ unsigned int reg, val;
+ int ret;
switch (speed) {
- case SPEED_10000:
-@@ -648,14 +708,19 @@ static int ipq_pcs_link_up_config_usxgmi
+@@ -478,14 +534,17 @@ static int ipq_pcs_link_up_config_usxgmi
}
/* Configure XPCS speed */
- ret = regmap_update_bits(qpcs->regmap, XPCS_MII_CTRL,
-+ reg = (channel == 0) ? XPCS_MII_CTRL : XPCS_CHANNEL_MII_CTRL(channel);
++ reg = (index == 0) ? XPCS_MII_CTRL : XPCS_MII1_CTRL(index);
+ ret = regmap_update_bits(qpcs->regmap, reg,
XPCS_SPEED_MASK, val | XPCS_DUPLEX_FULL);
if (ret)
@@ -217,25 +203,32 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
/* XPCS adapter reset */
- return regmap_set_bits(qpcs->regmap,
-+ if (channel == 0)
-+ return regmap_set_bits(qpcs->regmap,
- XPCS_DIG_CTRL, XPCS_USXG_ADPT_RESET);
-+ else
-+ return regmap_set_bits(qpcs->regmap, XPCS_CHANNEL_DIG_CTRL(channel),
-+ XPCS_CHANNEL_USXG_ADPT_RESET);
+- XPCS_DIG_CTRL, XPCS_USXG_ADPT_RESET);
++ reg = (index == 0) ? XPCS_DIG_CTRL : XPCS_MII1_DIG_CTRL(index);
++ val = (index == 0) ? XPCS_USXG_ADPT_RESET : XPCS_MII1_USXG_ADPT_RESET;
++ return regmap_set_bits(qpcs->regmap, reg, val);
++
}
static int ipq_pcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
-@@ -671,6 +736,7 @@ static int ipq_pcs_validate(struct phyli
- /* In-band autoneg is not supported for 2500BASEX */
+@@ -502,6 +561,7 @@ static int ipq_pcs_validate(struct phyli
phylink_clear(supported, Autoneg);
return 0;
-+ case PHY_INTERFACE_MODE_10G_QXGMII:
case PHY_INTERFACE_MODE_USXGMII:
++ case PHY_INTERFACE_MODE_10G_QXGMII:
/* USXGMII only supports full duplex mode */
phylink_clear(supported, 100baseT_Half);
-@@ -750,7 +816,8 @@ static void ipq_pcs_get_state(struct phy
- ipq_unipcs_get_state_2500basex(qpcs, index, state);
+ phylink_clear(supported, 10baseT_Half);
+@@ -519,6 +579,7 @@ static unsigned int ipq_pcs_inband_caps(
+ case PHY_INTERFACE_MODE_QSGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_USXGMII:
++ case PHY_INTERFACE_MODE_10G_QXGMII:
+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ case PHY_INTERFACE_MODE_10GBASER:
+@@ -582,7 +643,8 @@ static void ipq_pcs_get_state(struct phy
+ ipq_pcs_get_state_2500basex(qpcs, state);
break;
case PHY_INTERFACE_MODE_USXGMII:
- ipq_pcs_get_state_usxgmii(qpcs, state);
@@ -243,20 +236,19 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ ipq_pcs_get_state_usxgmii(qpcs, index, state);
break;
case PHY_INTERFACE_MODE_10GBASER:
- ipq_unipcs_get_state_10gbaser(qpcs, state);
-@@ -786,7 +853,9 @@ static int ipq_pcs_config(struct phylink
+ ipq_pcs_get_state_10gbaser(qpcs, state);
+@@ -617,7 +679,8 @@ static int ipq_pcs_config(struct phylink
case PHY_INTERFACE_MODE_2500BASEX:
- return ipq_unipcs_config_2500basex(qpcs, interface);
+ return ipq_pcs_config_2500basex(qpcs);
case PHY_INTERFACE_MODE_USXGMII:
- return ipq_pcs_config_usxgmii(qpcs);
+ case PHY_INTERFACE_MODE_10G_QXGMII:
-+ return ipq_pcs_config_usxgmii(qpcs, index,
-+ interface);
++ return ipq_pcs_config_usxgmii(qpcs, index, interface);
case PHY_INTERFACE_MODE_10GBASER:
- return ipq_unipcs_config_10gbaser(qpcs, interface);
+ return ipq_pcs_config_10gbaser(qpcs);
default:
-@@ -822,7 +891,8 @@ static void ipq_pcs_link_up(struct phyli
- ret = ipq_unipcs_link_up_config_2500basex(qpcs, index, speed);
+@@ -646,7 +709,8 @@ static void ipq_pcs_link_up(struct phyli
+ ret = ipq_pcs_link_up_config_2500basex(qpcs, speed);
break;
case PHY_INTERFACE_MODE_USXGMII:
- ret = ipq_pcs_link_up_config_usxgmii(qpcs, speed);
@@ -265,3 +257,11 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
break;
case PHY_INTERFACE_MODE_10GBASER:
/* Nothing to do here */
+@@ -731,6 +795,7 @@ static unsigned long ipq_pcs_clk_rate_ge
+ switch (qpcs->interface) {
+ case PHY_INTERFACE_MODE_2500BASEX:
+ case PHY_INTERFACE_MODE_USXGMII:
++ case PHY_INTERFACE_MODE_10G_QXGMII:
+ case PHY_INTERFACE_MODE_10GBASER:
+ return 312500000;
+ default:
diff --git a/target/linux/qualcommbe/patches-6.12/0365-net-pcs-ipq-uniphy-control-MISC2-register-for-2.5G-s.patch b/target/linux/qualcommbe/patches-6.12/0365-net-pcs-ipq-uniphy-control-MISC2-register-for-2.5G-s.patch
index b34dd837ab..6ec8f2634e 100644
--- a/target/linux/qualcommbe/patches-6.12/0365-net-pcs-ipq-uniphy-control-MISC2-register-for-2.5G-s.patch
+++ b/target/linux/qualcommbe/patches-6.12/0365-net-pcs-ipq-uniphy-control-MISC2-register-for-2.5G-s.patch
@@ -1,8 +1,7 @@
-From 930203b9bb94dc4ea9342f1ce176851918758ed7 Mon Sep 17 00:00:00 2001
+From 87da3bbd25eb0a17e2c698120528e76c26b326d0 Mon Sep 17 00:00:00 2001
From: Mantas Pucka <mantas at 8devices.com>
Date: Mon, 2 Jun 2025 17:18:13 +0300
-Subject: [PATCH] net: pcs: ipq-uniphy: control MISC2 register for 2.5G
- support
+Subject: [PATCH] net: pcs: ipq-uniphy: control MISC2 register for 2.5G support
When 2500base-x mode is enabled MISC2 regsister needs to have different
value than for other 1G modes.
@@ -14,7 +13,7 @@ Signed-off-by: Mantas Pucka <mantas at 8devices.com>
--- a/drivers/net/pcs/pcs-qcom-ipq9574.c
+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
-@@ -24,6 +24,11 @@
+@@ -22,6 +22,11 @@
#define PCS_CALIBRATION 0x1e0
#define PCS_CALIBRATION_DONE BIT(7)
@@ -26,16 +25,16 @@ Signed-off-by: Mantas Pucka <mantas at 8devices.com>
#define PCS_MODE_CTRL 0x46c
#define PCS_MODE_SEL_MASK GENMASK(12, 8)
#define PCS_MODE_SGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x4)
-@@ -311,7 +316,7 @@ static int ipq_pcs_config_mode(struct ip
+@@ -275,7 +280,7 @@ static int ipq_pcs_config_mode(struct ip
phy_interface_t interface)
{
unsigned long rate = 125000000;
-- unsigned int val, mask = PCS_MODE_SEL_MASK;
-+ unsigned int val, misc2 = 0, mask = PCS_MODE_SEL_MASK;
+- unsigned int val, mask;
++ unsigned int val, mask, misc2 = 0;
int ret;
- /* Assert XPCS reset */
-@@ -321,6 +326,7 @@ static int ipq_pcs_config_mode(struct ip
+ /* Configure PCS interface mode */
+@@ -283,6 +288,7 @@ static int ipq_pcs_config_mode(struct ip
switch (interface) {
case PHY_INTERFACE_MODE_SGMII:
val = PCS_MODE_SGMII;
@@ -43,30 +42,29 @@ Signed-off-by: Mantas Pucka <mantas at 8devices.com>
break;
case PHY_INTERFACE_MODE_QSGMII:
val = PCS_MODE_QSGMII;
-@@ -328,10 +334,12 @@ static int ipq_pcs_config_mode(struct ip
+@@ -290,9 +296,11 @@ static int ipq_pcs_config_mode(struct ip
case PHY_INTERFACE_MODE_1000BASEX:
- mask |= PCS_MODE_SGMII_CTRL_MASK;
- val = PCS_MODE_SGMII | PCS_MODE_SGMII_CTRL_1000BASEX;
+ mask |= PCS_MODE_SGMII_MODE_MASK;
+ val = PCS_MODE_SGMII | PCS_MODE_SGMII_MODE_1000BASEX;
+ misc2 = PCS_MISC2_MODE_SGMII;
break;
case PHY_INTERFACE_MODE_2500BASEX:
- val = PCS_MODE_SGMII_PLUS;
- rate = 312500000;
+ val = PCS_MODE_2500BASEX;
+ misc2 = PCS_MISC2_MODE_SGMII_PLUS;
+ rate = 312500000;
break;
- case PHY_INTERFACE_MODE_PSGMII:
- val = PCS_MODE_PSGMII;
-@@ -360,6 +368,13 @@ static int ipq_pcs_config_mode(struct ip
- if (ret)
- return ret;
-
+ case PHY_INTERFACE_MODE_USXGMII:
+@@ -315,6 +323,13 @@ static int ipq_pcs_config_mode(struct ip
+ if (ret)
+ return ret;
+ }
++
+ if (misc2) {
+ ret = regmap_update_bits(qpcs->regmap, PCS_MISC2,
+ PCS_MISC2_MODE_MASK, misc2);
+ if (ret)
+ return ret;
+ }
-+
+
/* PCS PLL reset */
ret = regmap_clear_bits(qpcs->regmap, PCS_PLL_RESET, PCS_ANA_SW_RESET);
- if (ret)
diff --git a/target/linux/qualcommbe/patches-6.12/0366-net-pcs-ipq-uniphy-keep-autoneg-enabled-in-SGMII-mod.patch b/target/linux/qualcommbe/patches-6.12/0366-net-pcs-ipq-uniphy-keep-autoneg-enabled-in-SGMII-mod.patch
deleted file mode 100644
index 58e2be35f4..0000000000
--- a/target/linux/qualcommbe/patches-6.12/0366-net-pcs-ipq-uniphy-keep-autoneg-enabled-in-SGMII-mod.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From ccdfd293f9e948f0f62ac4e9924d72539a4e81ee Mon Sep 17 00:00:00 2001
-From: Mantas Pucka <mantas at 8devices.com>
-Date: Mon, 2 Jun 2025 17:19:45 +0300
-Subject: [PATCH] net: pcs: ipq-uniphy: keep autoneg enabled in SGMII mode
-
-For PHYs that don't use in-band-status (e.g. 2.5G PHY swiching between
-SGMII and 2500base-x), SGMII autoneg still must be enabled. Only mode
-that should use forced speed is 1000base-x
-
-Signed-off-by: Mantas Pucka <mantas at 8devices.com>
----
- drivers/net/pcs/pcs-qcom-ipq9574.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/pcs/pcs-qcom-ipq9574.c
-+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
-@@ -431,7 +431,7 @@ static int ipq_pcs_config_sgmii(struct i
- /* Nothing to do here as in-band autoneg mode is enabled
- * by default for each PCS MII port.
- */
-- if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
-+ if (interface != PHY_INTERFACE_MODE_1000BASEX)
- return 0;
-
- /* Set force speed mode */
diff --git a/target/linux/qualcommbe/patches-6.12/0367-net-pcs-ipq-uniphy-fix-USXGMII-link-up-failure.patch b/target/linux/qualcommbe/patches-6.12/0367-net-pcs-ipq-uniphy-fix-USXGMII-link-up-failure.patch
index 980b8d0379..b02782e7b3 100644
--- a/target/linux/qualcommbe/patches-6.12/0367-net-pcs-ipq-uniphy-fix-USXGMII-link-up-failure.patch
+++ b/target/linux/qualcommbe/patches-6.12/0367-net-pcs-ipq-uniphy-fix-USXGMII-link-up-failure.patch
@@ -1,4 +1,4 @@
-From 0cff1d9bb695bdc0ad7bad234b92eddf849ce88f Mon Sep 17 00:00:00 2001
+From bedf56b46ae53c4abb21eebb3e1d5a7483926dda Mon Sep 17 00:00:00 2001
From: Mantas Pucka <mantas at 8devices.com>
Date: Mon, 2 Jun 2025 17:20:58 +0300
Subject: [PATCH] net: pcs: ipq-uniphy: fix USXGMII link-up failure
@@ -13,7 +13,7 @@ Signed-off-by: Mantas Pucka <mantas at 8devices.com>
--- a/drivers/net/pcs/pcs-qcom-ipq9574.c
+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
-@@ -380,7 +380,7 @@ static int ipq_pcs_config_mode(struct ip
+@@ -336,7 +336,7 @@ static int ipq_pcs_config_mode(struct ip
if (ret)
return ret;
diff --git a/target/linux/qualcommbe/patches-6.12/0368-net-pcs-qcom-ipq9574-Update-IPQ9574-PCS-driver.patch b/target/linux/qualcommbe/patches-6.12/0368-net-pcs-qcom-ipq9574-Update-IPQ9574-PCS-driver.patch
new file mode 100644
index 0000000000..63a523ae1c
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0368-net-pcs-qcom-ipq9574-Update-IPQ9574-PCS-driver.patch
@@ -0,0 +1,282 @@
+From b4e07a8a3ec3dc5f676238987556e2aff0b14028 Mon Sep 17 00:00:00 2001
+From: Lei Wei <quic_leiwei at quicinc.com>
+Date: Mon, 29 Jan 2024 11:39:36 +0800
+Subject: [PATCH] net: pcs: qcom-ipq9574: Update IPQ9574 PCS driver
+
+Keep the PCS driver synced with the latest version posted to the kernel
+community and add the XPCS reset support.
+
+Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+---
+ .../bindings/net/pcs/qcom,ipq9574-pcs.yaml | 7 ++
+ drivers/net/pcs/pcs-qcom-ipq9574.c | 68 +++++++++++++++----
+ 2 files changed, 63 insertions(+), 12 deletions(-)
+
+--- a/Documentation/devicetree/bindings/net/pcs/qcom,ipq9574-pcs.yaml
++++ b/Documentation/devicetree/bindings/net/pcs/qcom,ipq9574-pcs.yaml
+@@ -98,6 +98,10 @@ properties:
+ - const: sys
+ - const: ahb
+
++ resets:
++ maxItems: 1
++ description: XPCS reset
++
+ '#clock-cells':
+ const: 1
+ description: See include/dt-bindings/net/qcom,ipq9574-pcs.h for constants
+@@ -137,6 +141,7 @@ required:
+ - '#size-cells'
+ - clocks
+ - clock-names
++ - resets
+ - '#clock-cells'
+
+ additionalProperties: false
+@@ -144,6 +149,7 @@ additionalProperties: false
+ examples:
+ - |
+ #include <dt-bindings/clock/qcom,ipq9574-gcc.h>
++ #include <dt-bindings/reset/qcom,ipq9574-gcc.h>
+
+ ethernet-pcs at 7a00000 {
+ compatible = "qcom,ipq9574-pcs";
+@@ -154,6 +160,7 @@ examples:
+ <&gcc GCC_UNIPHY0_AHB_CLK>;
+ clock-names = "sys",
+ "ahb";
++ resets = <&gcc GCC_UNIPHY0_XPCS_RESET>;
+ #clock-cells = <1>;
+
+ pcs-mii at 0 {
+--- a/drivers/net/pcs/pcs-qcom-ipq9574.c
++++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
+@@ -13,6 +13,7 @@
+ #include <linux/phylink.h>
+ #include <linux/platform_device.h>
+ #include <linux/regmap.h>
++#include <linux/reset.h>
+
+ #include <dt-bindings/net/qcom,ipq9574-pcs.h>
+
+@@ -31,9 +32,12 @@
+ #define PCS_MODE_SEL_MASK GENMASK(12, 8)
+ #define PCS_MODE_SGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x4)
+ #define PCS_MODE_QSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x1)
++#define PCS_MODE_PSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x2)
+ #define PCS_MODE_2500BASEX FIELD_PREP(PCS_MODE_SEL_MASK, 0x8)
+ #define PCS_MODE_XPCS FIELD_PREP(PCS_MODE_SEL_MASK, 0x10)
+ #define PCS_MODE_SGMII_MODE_MASK GENMASK(6, 4)
++#define PCS_MODE_SGMII_MODE_MAC FIELD_PREP(PCS_MODE_SGMII_MODE_MASK, \
++ 0x2)
+ #define PCS_MODE_SGMII_MODE_1000BASEX FIELD_PREP(PCS_MODE_SGMII_MODE_MASK, \
+ 0x0)
+
+@@ -52,6 +56,8 @@
+ #define PCS_MII_STS_SPEED_10 0
+ #define PCS_MII_STS_SPEED_100 1
+ #define PCS_MII_STS_SPEED_1000 2
++#define PCS_MII_STS_PAUSE_TX_EN BIT(1)
++#define PCS_MII_STS_PAUSE_RX_EN BIT(0)
+
+ #define PCS_QP_USXG_OPTION 0x584
+ #define PCS_QP_USXG_GMII_SRC_XPCS BIT(0)
+@@ -142,6 +148,7 @@ struct ipq_pcs {
+ struct clk_hw tx_hw;
+
+ struct ipq_pcs_mii *qpcs_mii[PCS_MAX_MII_NRS];
++ struct reset_control *xpcs_rstc;
+ };
+
+ #define phylink_pcs_to_qpcs_mii(_pcs) \
+@@ -184,6 +191,11 @@ static void ipq_pcs_get_state_sgmii(stru
+ state->duplex = DUPLEX_FULL;
+ else
+ state->duplex = DUPLEX_HALF;
++
++ if (val & PCS_MII_STS_PAUSE_TX_EN)
++ state->pause |= MLO_PAUSE_TX;
++ if (val & PCS_MII_STS_PAUSE_RX_EN)
++ state->pause |= MLO_PAUSE_RX;
+ }
+
+ static void ipq_pcs_get_state_2500basex(struct ipq_pcs *qpcs,
+@@ -198,7 +210,6 @@ static void ipq_pcs_get_state_2500basex(
+ return;
+ }
+
+-
+ state->link = !!(val & PCS_MII_LINK_STS);
+
+ if (!state->link)
+@@ -281,17 +292,27 @@ static int ipq_pcs_config_mode(struct ip
+ {
+ unsigned long rate = 125000000;
+ unsigned int val, mask, misc2 = 0;
++ bool xpcs_mode = false;
+ int ret;
+
++ /* Assert XPCS reset */
++ reset_control_assert(qpcs->xpcs_rstc);
++
+ /* Configure PCS interface mode */
+ mask = PCS_MODE_SEL_MASK;
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+- val = PCS_MODE_SGMII;
++ mask |= PCS_MODE_SGMII_MODE_MASK;
++ val = PCS_MODE_SGMII | PCS_MODE_SGMII_MODE_MAC;
+ misc2 = PCS_MISC2_MODE_SGMII;
+ break;
+ case PHY_INTERFACE_MODE_QSGMII:
+- val = PCS_MODE_QSGMII;
++ mask |= PCS_MODE_SGMII_MODE_MASK;
++ val = PCS_MODE_QSGMII | PCS_MODE_SGMII_MODE_MAC;
++ break;
++ case PHY_INTERFACE_MODE_PSGMII:
++ mask |= PCS_MODE_SGMII_MODE_MASK;
++ val = PCS_MODE_PSGMII | PCS_MODE_SGMII_MODE_MAC;
+ break;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ mask |= PCS_MODE_SGMII_MODE_MASK;
+@@ -308,6 +329,7 @@ static int ipq_pcs_config_mode(struct ip
+ case PHY_INTERFACE_MODE_10GBASER:
+ val = PCS_MODE_XPCS;
+ rate = 312500000;
++ xpcs_mode = true;
+ break;
+ default:
+ return -EOPNOTSUPP;
+@@ -367,6 +389,10 @@ static int ipq_pcs_config_mode(struct ip
+ return ret;
+ }
+
++ /* Deassert XPCS */
++ if (xpcs_mode)
++ reset_control_deassert(qpcs->xpcs_rstc);
++
+ return 0;
+ }
+
+@@ -384,15 +410,13 @@ static int ipq_pcs_config_sgmii(struct i
+ return ret;
+ }
+
+- /* Nothing to do here as in-band autoneg mode is enabled
+- * by default for each PCS MII port.
+- */
++ /* Set AN mode or force mode */
+ if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
+- return 0;
+-
+- /* Set force speed mode */
+- return regmap_set_bits(qpcs->regmap,
+- PCS_MII_CTRL(index), PCS_MII_FORCE_MODE);
++ return regmap_clear_bits(qpcs->regmap,
++ PCS_MII_CTRL(index), PCS_MII_FORCE_MODE);
++ else
++ return regmap_set_bits(qpcs->regmap,
++ PCS_MII_CTRL(index), PCS_MII_FORCE_MODE);
+ }
+
+ static int ipq_pcs_config_2500basex(struct ipq_pcs *qpcs)
+@@ -417,6 +441,10 @@ static int ipq_pcs_config_usxgmii(struct
+ if (ret)
+ return ret;
+
++ ret = regmap_set_bits(qpcs->regmap, XPCS_DIG_CTRL, XPCS_USXG_EN);
++ if (ret)
++ return ret;
++
+ if (interface == PHY_INTERFACE_MODE_10G_QXGMII) {
+ ret = regmap_update_bits(qpcs->regmap, XPCS_KR_CTRL,
+ XPCS_USXG_MODE_MASK, XPCS_10G_QXGMII_MODE);
+@@ -432,6 +460,7 @@ static int ipq_pcs_config_usxgmii(struct
+ ret = regmap_set_bits(qpcs->regmap, XPCS_DIG_CTRL, XPCS_SOFT_RESET);
+ if (ret)
+ return ret;
++ }
+ }
+
+ /* Disable Tx IPG check for 10G_QXGMII */
+@@ -559,7 +588,6 @@ static int ipq_pcs_link_up_config_usxgmi
+ reg = (index == 0) ? XPCS_DIG_CTRL : XPCS_MII1_DIG_CTRL(index);
+ val = (index == 0) ? XPCS_USXG_ADPT_RESET : XPCS_MII1_USXG_ADPT_RESET;
+ return regmap_set_bits(qpcs->regmap, reg, val);
+-
+ }
+
+ static int ipq_pcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
+@@ -568,6 +596,7 @@ static int ipq_pcs_validate(struct phyli
+ switch (state->interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
++ case PHY_INTERFACE_MODE_PSGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_10GBASER:
+ return 0;
+@@ -592,6 +621,7 @@ static unsigned int ipq_pcs_inband_caps(
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
++ case PHY_INTERFACE_MODE_PSGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_10G_QXGMII:
+@@ -648,6 +678,7 @@ static void ipq_pcs_get_state(struct phy
+ switch (state->interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
++ case PHY_INTERFACE_MODE_PSGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ /* SGMII and 1000BASEX in-band autoneg word format are decoded
+ * by PCS hardware and both placed to the same status register.
+@@ -689,6 +720,7 @@ static int ipq_pcs_config(struct phylink
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
++ case PHY_INTERFACE_MODE_PSGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ return ipq_pcs_config_sgmii(qpcs, index, neg_mode, interface);
+ case PHY_INTERFACE_MODE_2500BASEX:
+@@ -703,6 +735,11 @@ static int ipq_pcs_config(struct phylink
+ };
+ }
+
++static void ipq_pcs_an_restart(struct phylink_pcs *pcs)
++{
++ /* Currently not used */
++}
++
+ static void ipq_pcs_link_up(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ phy_interface_t interface,
+@@ -716,6 +753,7 @@ static void ipq_pcs_link_up(struct phyli
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
++ case PHY_INTERFACE_MODE_PSGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ ret = ipq_pcs_link_up_config_sgmii(qpcs, index,
+ neg_mode, speed);
+@@ -746,6 +784,7 @@ static const struct phylink_pcs_ops ipq_
+ .pcs_disable = ipq_pcs_disable,
+ .pcs_get_state = ipq_pcs_get_state,
+ .pcs_config = ipq_pcs_config,
++ .pcs_an_restart = ipq_pcs_an_restart,
+ .pcs_link_up = ipq_pcs_link_up,
+ };
+
+@@ -990,6 +1029,11 @@ static int ipq9574_pcs_probe(struct plat
+ return dev_err_probe(dev, PTR_ERR(clk),
+ "Failed to enable AHB clock\n");
+
++ qpcs->xpcs_rstc = devm_reset_control_get_optional(dev, NULL);
++ if (IS_ERR_OR_NULL(qpcs->xpcs_rstc))
++ return dev_err_probe(dev, PTR_ERR(qpcs->xpcs_rstc),
++ "Failed to get XPCS reset\n");
++
+ ret = ipq_pcs_clk_register(qpcs);
+ if (ret)
+ return ret;
More information about the lede-commits
mailing list