Files
openwrt/target/linux/qualcommbe/patches-6.12/0364-net-pcs-Add-10G_QXGMII-interface-mode-support-to-IPQ.patch
Alexandru Gagniuc 95bd7a76a1 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>
2025-11-30 16:51:12 +01:00

268 lines
8.6 KiB
Diff

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
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 | 109 +++++++++++++++++++++++------
1 file changed, 87 insertions(+), 22 deletions(-)
--- a/drivers/net/pcs/pcs-qcom-ipq9574.c
+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
@@ -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)
+
#define PCS_PLL_RESET 0x780
#define PCS_ANA_SW_RESET BIT(6)
@@ -63,10 +66,23 @@
#define XPCS_KR_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)
+
+/* 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_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))
@@ -78,9 +94,11 @@
#define XPCS_SPEED_10 0
#define XPCS_MII_AN_CTRL 0x1f8001
+#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_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
@@ -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_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;
@@ -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,
+static void ipq_pcs_get_state_usxgmii(struct ipq_pcs *qpcs, int index,
struct phylink_link_state *state)
{
- 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;
@@ -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:
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;
+ }
+
/* 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)
{
+ unsigned int reg;
int ret;
/* 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;
- 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;
+ }
+
+ /* Disable Tx IPG check for 10G_QXGMII */
+ if (interface == PHY_INTERFACE_MODE_10G_QXGMII) {
+ 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;
+ }
- 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_MII1_CTRL(index);
+ return regmap_set_bits(qpcs->regmap, reg, XPCS_MII_AN_EN);
}
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 index, int speed)
{
- unsigned int val;
+ unsigned int reg, val;
int ret;
switch (speed) {
@@ -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 = (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)
return ret;
/* XPCS adapter reset */
- return regmap_set_bits(qpcs->regmap,
- 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,
@@ -502,6 +561,7 @@ static int ipq_pcs_validate(struct phyli
phylink_clear(supported, Autoneg);
return 0;
case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_10G_QXGMII:
/* USXGMII only supports full duplex mode */
phylink_clear(supported, 100baseT_Half);
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);
+ case PHY_INTERFACE_MODE_10G_QXGMII:
+ ipq_pcs_get_state_usxgmii(qpcs, index, state);
break;
case PHY_INTERFACE_MODE_10GBASER:
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_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);
case PHY_INTERFACE_MODE_10GBASER:
return ipq_pcs_config_10gbaser(qpcs);
default:
@@ -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);
+ case PHY_INTERFACE_MODE_10G_QXGMII:
+ ret = ipq_pcs_link_up_config_usxgmii(qpcs, index, speed);
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: