qualcommbe: v6.12: enable 2.5G and 10G phylink modes in pcs-qcom-ipq9574
The PCS driver in the 6.12 patchset is the v5 submission (see link below). It solves a number of issues and crashes with teh pcs driver from the 6.6 patchset. However, this new driver is missing support for "10gbase-r", "10g-qxgmii", and 1000/2500base-x modes. Port these modes to the 6.12 patchset. "2500base-x" in particular seems to be needed to establish a 2.5G link on phy-mode="usxgmii"; Link: https://lore.kernel.org/lkml/20250207-ipq_pcs_6-14_rc1-v5-0-be2ebec32921@quicinc.com/ Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com> Link: https://github.com/openwrt/openwrt/pull/18796 Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
parent
3d6c36e327
commit
22dc34e8c1
4 changed files with 677 additions and 0 deletions
|
@ -0,0 +1,127 @@
|
|||
From e770b36f0353fd11c4628360fe412acb7f02f346 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
|
||||
PCS driver
|
||||
|
||||
10GBASER mode is used when PCS connects with a 10G SFP module.
|
||||
|
||||
Change-Id: Ifc3c3bb23811807a9b34e88771aab2c830c2327c
|
||||
Signed-off-by: Lei Wei <quic_leiwei@quicinc.com>
|
||||
Alex G: Use regmap to read/write registers
|
||||
Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
|
||||
---
|
||||
drivers/net/pcs/pcs-qcom-ipq9574.c | 53 ++++++++++++++++++++++++++++++
|
||||
1 file changed, 53 insertions(+)
|
||||
|
||||
--- a/drivers/net/pcs/pcs-qcom-ipq9574.c
|
||||
+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
|
||||
@@ -60,6 +60,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_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
|
||||
state->duplex = DUPLEX_FULL;
|
||||
}
|
||||
|
||||
+static void ipq_unipcs_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);
|
||||
+ if (ret) {
|
||||
+ state->link = 0;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ state->link = !!(val & XPCS_10GBASER_LINK_STS);
|
||||
+
|
||||
+ if (!state->link)
|
||||
+ return;
|
||||
+
|
||||
+ state->speed = SPEED_10000;
|
||||
+ state->duplex = DUPLEX_FULL;
|
||||
+ state->pause |= MLO_PAUSE_TXRX_MASK;
|
||||
+}
|
||||
+
|
||||
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;
|
||||
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
|
||||
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)
|
||||
+{
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
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:
|
||||
@@ -602,6 +648,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);
|
||||
+ break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -631,6 +680,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);
|
||||
default:
|
||||
dev_err(qpcs->dev,
|
||||
"interface %s not supported\n", phy_modes(interface));
|
||||
@@ -662,6 +713,8 @@ 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:
|
||||
+ break;
|
||||
default:
|
||||
dev_err(qpcs->dev,
|
||||
"interface %s not supported\n", phy_modes(interface));
|
|
@ -0,0 +1,192 @@
|
|||
From a2e687df29e457621616d5d769688e6c972f9ac6 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
|
||||
PCS driver
|
||||
|
||||
2500BASEX mode is used when PCS connects with QCA8386 switch in a fixed
|
||||
2500M link. It is also used when PCS connectes with QCA8081 PHY which
|
||||
works at 2500M link speed. In addition, it can be also used when PCS
|
||||
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
|
||||
Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
|
||||
---
|
||||
drivers/net/pcs/pcs-qcom-ipq9574.c | 94 ++++++++++++++++++++++++++++++
|
||||
1 file changed, 94 insertions(+)
|
||||
|
||||
--- a/drivers/net/pcs/pcs-qcom-ipq9574.c
|
||||
+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
|
||||
@@ -29,6 +29,7 @@
|
||||
#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_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;
|
||||
}
|
||||
|
||||
+static void ipq_unipcs_get_state_2500basex(struct ipq_pcs *qpcs,
|
||||
+ int index,
|
||||
+ struct phylink_link_state *state)
|
||||
+{
|
||||
+ unsigned int val;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = regmap_read(qpcs->regmap, PCS_MII_STS(index), &val);
|
||||
+ if (ret) {
|
||||
+ state->link = 0;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ state->link = !!(val & PCS_MII_LINK_STS);
|
||||
+
|
||||
+ if (!state->link)
|
||||
+ return;
|
||||
+
|
||||
+ state->speed = SPEED_2500;
|
||||
+ state->duplex = DUPLEX_FULL;
|
||||
+ state->pause |= MLO_PAUSE_TXRX_MASK;
|
||||
+}
|
||||
+
|
||||
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
|
||||
case PHY_INTERFACE_MODE_QSGMII:
|
||||
val = PCS_MODE_QSGMII;
|
||||
break;
|
||||
+ case PHY_INTERFACE_MODE_2500BASEX:
|
||||
+ val = PCS_MODE_SGMII_PLUS;
|
||||
+ 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
|
||||
PCS_MII_CTRL(index), PCS_MII_FORCE_MODE);
|
||||
}
|
||||
|
||||
+static int ipq_unipcs_config_2500basex(struct ipq_pcs *qpcs,
|
||||
+ phy_interface_t interface)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ if (qpcs->interface != interface) {
|
||||
+ ret = ipq_pcs_config_mode(qpcs, interface);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ qpcs->interface = interface;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
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(
|
||||
PCS_MII_CTRL(index), PCS_MII_ADPT_RESET);
|
||||
}
|
||||
|
||||
+static int ipq_unipcs_link_up_config_2500basex(struct ipq_pcs *qpcs,
|
||||
+ int index,
|
||||
+ 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.
|
||||
+ */
|
||||
+ ret = regmap_clear_bits(qpcs->regmap,
|
||||
+ PCS_MII_CTRL(index), PCS_MII_ADPT_RESET);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return regmap_set_bits(qpcs->regmap,
|
||||
+ PCS_MII_CTRL(index), PCS_MII_ADPT_RESET);
|
||||
+}
|
||||
+
|
||||
static int ipq_pcs_link_up_config_usxgmii(struct ipq_pcs *qpcs, int speed)
|
||||
{
|
||||
unsigned int val;
|
||||
@@ -575,6 +657,10 @@ static int ipq_pcs_validate(struct phyli
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_QSGMII:
|
||||
return 0;
|
||||
+ case PHY_INTERFACE_MODE_2500BASEX:
|
||||
+ /* In-band autoneg is not supported for 2500BASEX */
|
||||
+ phylink_clear(supported, Autoneg);
|
||||
+ return 0;
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
/* USXGMII only supports full duplex mode */
|
||||
phylink_clear(supported, 100baseT_Half);
|
||||
@@ -645,6 +731,9 @@ static void ipq_pcs_get_state(struct phy
|
||||
case PHY_INTERFACE_MODE_PSGMII:
|
||||
ipq_pcs_get_state_sgmii(qpcs, index, state);
|
||||
break;
|
||||
+ case PHY_INTERFACE_MODE_2500BASEX:
|
||||
+ ipq_unipcs_get_state_2500basex(qpcs, index, state);
|
||||
+ break;
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
ipq_pcs_get_state_usxgmii(qpcs, state);
|
||||
break;
|
||||
@@ -678,6 +767,8 @@ static int ipq_pcs_config(struct phylink
|
||||
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);
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
return ipq_pcs_config_usxgmii(qpcs);
|
||||
case PHY_INTERFACE_MODE_10GBASER:
|
||||
@@ -710,6 +801,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);
|
||||
+ break;
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
ret = ipq_pcs_link_up_config_usxgmii(qpcs, speed);
|
||||
break;
|
|
@ -0,0 +1,91 @@
|
|||
From 07f9bb8eb006e9664d651089a1f422d045e093e3 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
|
||||
PCS driver
|
||||
|
||||
1000BASEX is used when PCS connects with a 1G SFP module.
|
||||
|
||||
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 | 18 ++++++++++++++++--
|
||||
1 file changed, 16 insertions(+), 2 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)
|
||||
#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, \
|
||||
+ 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
|
||||
phy_interface_t interface)
|
||||
{
|
||||
unsigned long rate = 125000000;
|
||||
- unsigned int val;
|
||||
+ unsigned int val, mask = PCS_MODE_SEL_MASK;
|
||||
int ret;
|
||||
|
||||
/* Assert XPCS reset */
|
||||
@@ -297,6 +300,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;
|
||||
+ break;
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
val = PCS_MODE_SGMII_PLUS;
|
||||
rate = 312500000;
|
||||
@@ -316,7 +323,7 @@ static int ipq_pcs_config_mode(struct ip
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(qpcs->regmap, PCS_MODE_CTRL,
|
||||
- PCS_MODE_SEL_MASK, val);
|
||||
+ mask, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -523,6 +530,7 @@ ipq_unipcs_link_up_clock_rate_set(struct
|
||||
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:
|
||||
@@ -729,6 +737,10 @@ static void ipq_pcs_get_state(struct phy
|
||||
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.
|
||||
+ */
|
||||
ipq_pcs_get_state_sgmii(qpcs, index, state);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
@@ -766,6 +778,7 @@ static int ipq_pcs_config(struct phylink
|
||||
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);
|
||||
@@ -798,6 +811,7 @@ static void ipq_pcs_link_up(struct phyli
|
||||
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);
|
||||
break;
|
|
@ -0,0 +1,267 @@
|
|||
From 77462c0d74e51a24408062b93c3fcc0256909d33 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
|
||||
PCS driver
|
||||
|
||||
10G_QXGMII is used when PCS connectes with QCA8084 four ports
|
||||
2.5G PHYs.
|
||||
|
||||
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(-)
|
||||
|
||||
--- 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)
|
||||
|
||||
+#define PCS_QP_USXG_OPTION 0x584
|
||||
+#define PCS_QP_USXG_GMII_SRC_XPCS BIT(0)
|
||||
+
|
||||
#define PCS_PLL_RESET 0x780
|
||||
#define PCS_ANA_SW_RESET BIT(6)
|
||||
|
||||
@@ -68,10 +71,22 @@
|
||||
#define XPCS_10GBASER_LINK_STS BIT(12)
|
||||
|
||||
#define XPCS_DIG_CTRL 0x38000
|
||||
+#define XPCS_SOFT_RESET BIT(15)
|
||||
#define XPCS_USXG_ADPT_RESET BIT(10)
|
||||
#define XPCS_USXG_EN BIT(9)
|
||||
|
||||
+#define XPCS_KR_CTRL 0x38007
|
||||
+#define XPCS_USXG_MODE_MASK GENMASK(12, 10)
|
||||
+#define XPCS_10G_QXGMII_MODE FIELD_PREP(XPCS_USXG_MODE_MASK, 0x5)
|
||||
+
|
||||
+#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)
|
||||
+
|
||||
#define XPCS_MII_CTRL 0x1f0000
|
||||
+#define XPCS_CHANNEL_MII_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 @@
|
||||
#define XPCS_SPEED_10 0
|
||||
|
||||
#define XPCS_MII_AN_CTRL 0x1f8001
|
||||
+#define XPCS_CHANNEL_MII_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_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 @@
|
||||
#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_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
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
- ret = regmap_read(qpcs->regmap, XPCS_MII_AN_INTR_STS, &val);
|
||||
+ 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;
|
||||
rate = 312500000;
|
||||
break;
|
||||
+ case PHY_INTERFACE_MODE_10G_QXGMII:
|
||||
+ val = PCS_MODE_XPCS;
|
||||
+ rate = 312500000;
|
||||
+ 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;
|
||||
}
|
||||
|
||||
-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 ret;
|
||||
+ int ret, reg;
|
||||
|
||||
/* Configure the XPCS for USXGMII mode if required */
|
||||
- if (qpcs->interface == PHY_INTERFACE_MODE_USXGMII)
|
||||
- return 0;
|
||||
-
|
||||
- ret = ipq_pcs_config_mode(qpcs, PHY_INTERFACE_MODE_USXGMII);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
+ if (qpcs->interface != interface) {
|
||||
+ 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);
|
||||
+
|
||||
+ /* 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);
|
||||
+ }
|
||||
+
|
||||
+ /* Enable autoneg */
|
||||
+ reg = (index == 0) ? XPCS_MII_AN_CTRL : XPCS_CHANNEL_MII_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);
|
||||
+ 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_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)
|
||||
{
|
||||
unsigned int val;
|
||||
- int ret;
|
||||
+ int ret, reg;
|
||||
|
||||
switch (speed) {
|
||||
case SPEED_10000:
|
||||
@@ -648,14 +708,19 @@ 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);
|
||||
+ ret = regmap_update_bits(qpcs->regmap, reg,
|
||||
XPCS_SPEED_MASK, val | XPCS_DUPLEX_FULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
static int ipq_pcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
|
||||
@@ -669,6 +734,7 @@ static int ipq_pcs_validate(struct phyli
|
||||
/* In-band autoneg is not supported for 2500BASEX */
|
||||
phylink_clear(supported, Autoneg);
|
||||
return 0;
|
||||
+ case PHY_INTERFACE_MODE_10G_QXGMII:
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
/* USXGMII only supports full duplex mode */
|
||||
phylink_clear(supported, 100baseT_Half);
|
||||
@@ -747,7 +813,8 @@ static void ipq_pcs_get_state(struct phy
|
||||
ipq_unipcs_get_state_2500basex(qpcs, index, state);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
- ipq_pcs_get_state_usxgmii(qpcs, state);
|
||||
+ case PHY_INTERFACE_MODE_10G_QXGMII:
|
||||
+ ipq_pcs_get_state_usxgmii(qpcs, index, state);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_10GBASER:
|
||||
ipq_unipcs_get_state_10gbaser(qpcs, state);
|
||||
@@ -783,7 +850,9 @@ static int ipq_pcs_config(struct phylink
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
return ipq_unipcs_config_2500basex(qpcs, interface);
|
||||
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);
|
||||
case PHY_INTERFACE_MODE_10GBASER:
|
||||
return ipq_unipcs_config_10gbaser(qpcs, interface);
|
||||
default:
|
||||
@@ -819,7 +888,8 @@ static void ipq_pcs_link_up(struct phyli
|
||||
ret = ipq_unipcs_link_up_config_2500basex(qpcs, index, speed);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
- ret = ipq_pcs_link_up_config_usxgmii(qpcs, speed);
|
||||
+ case PHY_INTERFACE_MODE_10G_QXGMII:
|
||||
+ ret = ipq_pcs_link_up_config_usxgmii(qpcs, index, speed);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_10GBASER:
|
||||
break;
|
Loading…
Reference in a new issue