mirror of
git://git.openwrt.org/openwrt/openwrt.git
synced 2025-12-07 13:14:00 -05:00
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@gmail.com> Link: https://github.com/openwrt/openwrt/pull/20993 Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
parent
cc6b9ff17b
commit
95bd7a76a1
@ -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@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@quicinc.com>
|
||||
Alex G: remove phylink_pcs .neg_mode boolean
|
||||
Signed-off-by: Alexandru Gagniuc <mr.nuke.me@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@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@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@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@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@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);
|
||||
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
From ffe2a80fb76ccdc1781f817f6bbc9a8aa919816e Mon Sep 17 00:00:00 2001
|
||||
From: Alexandru Gagniuc <mr.nuke.me@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@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);
|
||||
@ -1,82 +0,0 @@
|
||||
From 5b2f02ccca7b9496f0a8da6ade063b82810c75e7 Mon Sep 17 00:00:00 2001
|
||||
From: Alexandru Gagniuc <mr.nuke.me@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@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);
|
||||
@ -1,362 +0,0 @@
|
||||
From 7de372abe7a4b5b380fdbeedd268445f234990c8 Mon Sep 17 00:00:00 2001
|
||||
From: Lei Wei <quic_leiwei@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@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@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 */
|
||||
@ -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@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@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@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@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@0 {
|
||||
@ -108,12 +102,7 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me@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@0 {
|
||||
@ -134,12 +123,7 @@ Signed-off-by: Alexandru Gagniuc <mr.nuke.me@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@0 {
|
||||
|
||||
@ -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@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@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@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@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;
|
||||
+ /* Configure 10GBASER mode if required */
|
||||
+ if (qpcs->interface == PHY_INTERFACE_MODE_10GBASER)
|
||||
+ return 0;
|
||||
+
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+ 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@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:
|
||||
|
||||
@ -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@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@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@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@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;
|
||||
+ /* Configure PCS for 2500BASEX mode if required */
|
||||
+ if (qpcs->interface == PHY_INTERFACE_MODE_2500BASEX)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (qpcs->interface != interface) {
|
||||
+ ret = ipq_pcs_config_mode(qpcs, interface);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ qpcs->interface = interface;
|
||||
+ }
|
||||
+
|
||||
+ 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@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) {
|
||||
|
||||
@ -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@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@quicinc.com>
|
||||
Signed-off-by: Alexandru Gagniuc <mr.nuke.me@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_2500BASEX:
|
||||
@@ -657,6 +665,7 @@ static int ipq_pcs_validate(struct phyli
|
||||
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_2500BASEX:
|
||||
/* In-band autoneg is not supported for 2500BASEX */
|
||||
@@ -731,6 +740,10 @@ static void ipq_pcs_get_state(struct phy
|
||||
@@ -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_1000BASEX:
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
@@ -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@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);
|
||||
|
||||
@ -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@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@quicinc.com>
|
||||
Signed-off-by: Alexandru Gagniuc <mr.nuke.me@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@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@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@gmail.com>
|
||||
+ ret = ipq_pcs_config_mode(qpcs, interface);
|
||||
+ 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);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* 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;
|
||||
+
|
||||
+ ret = regmap_set_bits(qpcs->regmap, XPCS_DIG_CTRL, XPCS_SOFT_RESET);
|
||||
+ 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);
|
||||
+
|
||||
+ /* Set Alignment Marker Interval */
|
||||
+ regmap_update_bits(qpcs->regmap, XPCS_DIG_STS,
|
||||
+ XPCS_DIG_STS_AM_COUNT, 0x6018);
|
||||
+
|
||||
+ regmap_set_bits(qpcs->regmap, XPCS_DIG_CTRL, XPCS_SOFT_RESET);
|
||||
+ }
|
||||
+
|
||||
+ 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@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@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@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:
|
||||
|
||||
@ -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@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@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@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@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)
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
From ccdfd293f9e948f0f62ac4e9924d72539a4e81ee Mon Sep 17 00:00:00 2001
|
||||
From: Mantas Pucka <mantas@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@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 */
|
||||
@ -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@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@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;
|
||||
|
||||
|
||||
@ -0,0 +1,282 @@
|
||||
From b4e07a8a3ec3dc5f676238987556e2aff0b14028 Mon Sep 17 00:00:00 2001
|
||||
From: Lei Wei <quic_leiwei@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@quicinc.com>
|
||||
Signed-off-by: Alexandru Gagniuc <mr.nuke.me@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@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@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;
|
||||
Loading…
Reference in New Issue
Block a user