openwrt-cghmn-mt300n/target/linux/qualcommbe/patches-6.6/103-13-net-pcs-Add-2500BASEX-interface-mode-support-to-IPQ-.patch
Christian Marangi 93173aee96
qualcommbe: ipq95xx: Add initial support for new target
Add initial support for new target with the initial patch for ethernet
support using pending upstream patches for PCS UNIPHY, PPE and EDMA.

Only initramfs currently working as support for new SPI/NAND
implementation, USB, CPUFreq and other devices is still unfinished and
needs to be evaluated.

Link: https://github.com/openwrt/openwrt/pull/17725
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
2025-01-25 21:24:06 +01:00

204 lines
6.3 KiB
Diff

From fcd1c53b460aa39cfd15f842126af62b27a4fad5 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 13/50] 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>
---
drivers/net/pcs/pcs-qcom-ipq-uniphy.c | 95 +++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
diff --git a/drivers/net/pcs/pcs-qcom-ipq-uniphy.c b/drivers/net/pcs/pcs-qcom-ipq-uniphy.c
index 68a1715531ef..ed9c55a6c0fa 100644
--- a/drivers/net/pcs/pcs-qcom-ipq-uniphy.c
+++ b/drivers/net/pcs/pcs-qcom-ipq-uniphy.c
@@ -25,6 +25,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_MODE_AN_MODE BIT(0)
@@ -282,6 +283,24 @@ static void ipq_unipcs_get_state_sgmii(struct ipq_uniphy_pcs *qunipcs,
state->pause |= MLO_PAUSE_RX;
}
+static void ipq_unipcs_get_state_2500basex(struct ipq_uniphy_pcs *qunipcs,
+ int channel,
+ struct phylink_link_state *state)
+{
+ u32 val;
+
+ val = ipq_unipcs_reg_read32(qunipcs, PCS_CHANNEL_STS(channel));
+
+ state->link = !!(val & PCS_CHANNEL_LINK_STS);
+
+ if (!state->link)
+ return;
+
+ state->speed = SPEED_2500;
+ state->duplex = DUPLEX_FULL;
+ state->pause |= MLO_PAUSE_TXRX_MASK;
+}
+
static void ipq_unipcs_get_state_usxgmii(struct ipq_uniphy_pcs *qunipcs,
struct phylink_link_state *state)
{
@@ -373,6 +392,12 @@ static int ipq_unipcs_config_mode(struct ipq_uniphy_pcs *qunipcs,
PCS_MODE_SEL_MASK | PCS_MODE_AN_MODE,
PCS_MODE_PSGMII);
break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ rate = 312500000;
+ ipq_unipcs_reg_modify32(qunipcs, PCS_MODE_CTRL,
+ PCS_MODE_SEL_MASK,
+ PCS_MODE_SGMII_PLUS);
+ break;
case PHY_INTERFACE_MODE_USXGMII:
case PHY_INTERFACE_MODE_10GBASER:
rate = 312500000;
@@ -450,6 +475,22 @@ static int ipq_unipcs_config_sgmii(struct ipq_uniphy_pcs *qunipcs,
return ret;
}
+static int ipq_unipcs_config_2500basex(struct ipq_uniphy_pcs *qunipcs,
+ phy_interface_t interface)
+{
+ int ret;
+
+ if (qunipcs->interface != interface) {
+ ret = ipq_unipcs_config_mode(qunipcs, interface);
+ if (ret)
+ return ret;
+
+ qunipcs->interface = interface;
+ }
+
+ return 0;
+}
+
static int ipq_unipcs_config_usxgmii(struct ipq_uniphy_pcs *qunipcs,
unsigned int neg_mode,
phy_interface_t interface)
@@ -522,6 +563,21 @@ static unsigned long ipq_unipcs_clock_rate_get_gmii(int speed)
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;
@@ -566,6 +622,9 @@ ipq_unipcs_link_up_clock_rate_set(struct ipq_uniphy_pcs_ch *qunipcs_ch,
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);
@@ -627,6 +686,21 @@ static void ipq_unipcs_link_up_config_sgmii(struct ipq_uniphy_pcs *qunipcs,
PCS_CHANNEL_ADPT_RESET);
}
+static void ipq_unipcs_link_up_config_2500basex(struct ipq_uniphy_pcs *qunipcs,
+ int channel,
+ int speed)
+{
+ /* 2500BASEX do not support autoneg and do not need to
+ * configure PCS speed, only reset PCS adapter here.
+ */
+ ipq_unipcs_reg_modify32(qunipcs, PCS_CHANNEL_CTRL(channel),
+ PCS_CHANNEL_ADPT_RESET,
+ 0);
+ ipq_unipcs_reg_modify32(qunipcs, PCS_CHANNEL_CTRL(channel),
+ PCS_CHANNEL_ADPT_RESET,
+ PCS_CHANNEL_ADPT_RESET);
+}
+
static void ipq_unipcs_link_up_config_usxgmii(struct ipq_uniphy_pcs *qunipcs,
int speed)
{
@@ -669,6 +743,17 @@ static void ipq_unipcs_link_up_config_usxgmii(struct ipq_uniphy_pcs *qunipcs,
XPCS_USXG_ADPT_RESET);
}
+static int ipq_unipcs_validate(struct phylink_pcs *pcs,
+ unsigned long *supported,
+ const struct phylink_link_state *state)
+{
+ /* In-band autoneg is not supported for 2500BASEX */
+ if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
+ phylink_clear(supported, Autoneg);
+
+ return 0;
+}
+
static void ipq_unipcs_get_state(struct phylink_pcs *pcs,
struct phylink_link_state *state)
{
@@ -682,6 +767,9 @@ static void ipq_unipcs_get_state(struct phylink_pcs *pcs,
case PHY_INTERFACE_MODE_PSGMII:
ipq_unipcs_get_state_sgmii(qunipcs, channel, state);
break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ ipq_unipcs_get_state_2500basex(qunipcs, channel, state);
+ break;
case PHY_INTERFACE_MODE_USXGMII:
ipq_unipcs_get_state_usxgmii(qunipcs, state);
break;
@@ -716,6 +804,8 @@ static int ipq_unipcs_config(struct phylink_pcs *pcs,
case PHY_INTERFACE_MODE_PSGMII:
return ipq_unipcs_config_sgmii(qunipcs, channel,
neg_mode, interface);
+ case PHY_INTERFACE_MODE_2500BASEX:
+ return ipq_unipcs_config_2500basex(qunipcs, interface);
case PHY_INTERFACE_MODE_USXGMII:
return ipq_unipcs_config_usxgmii(qunipcs,
neg_mode, interface);
@@ -748,6 +838,10 @@ static void ipq_unipcs_link_up(struct phylink_pcs *pcs,
ipq_unipcs_link_up_config_sgmii(qunipcs, channel,
neg_mode, speed);
break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ ipq_unipcs_link_up_config_2500basex(qunipcs,
+ channel, speed);
+ break;
case PHY_INTERFACE_MODE_USXGMII:
ipq_unipcs_link_up_config_usxgmii(qunipcs, speed);
break;
@@ -761,6 +855,7 @@ static void ipq_unipcs_link_up(struct phylink_pcs *pcs,
}
static const struct phylink_pcs_ops ipq_unipcs_phylink_ops = {
+ .pcs_validate = ipq_unipcs_validate,
.pcs_get_state = ipq_unipcs_get_state,
.pcs_config = ipq_unipcs_config,
.pcs_link_up = ipq_unipcs_link_up,
--
2.45.2