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>
204 lines
6.3 KiB
Diff
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
|
|
|