The original PCS driver did not use the .pcs_validate() in phylink_pcs_ops. The patches for 1000/2500base-x and 10g modes were taken from this old driver, and thus did not bother with .pcs_validate(). Thus, even though these modes are supported, phylink would not enable them. To fix these, list these modes in .pcs_validate(). Also list them in ipq_pcs_clk_rate_get(). While the latter does not appear to change behavior, it does change the clock rates listed under /sys/kernel/debug/clk Co-developed-by: Mantas Pucka <mantas@8devices.com> Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com> Link: https://github.com/openwrt/openwrt/pull/18435 Signed-off-by: Robert Marko <robimarko@gmail.com>
152 lines
4.3 KiB
Diff
152 lines
4.3 KiB
Diff
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 | 57 ++++++++++++++++++++++++++++++
|
|
1 file changed, 57 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:
|
|
@@ -528,6 +574,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_10GBASER:
|
|
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:
|
|
case PHY_INTERFACE_MODE_QSGMII:
|
|
case PHY_INTERFACE_MODE_USXGMII:
|
|
+ case PHY_INTERFACE_MODE_10GBASER:
|
|
return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
|
|
default:
|
|
return 0;
|
|
@@ -602,6 +650,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 +682,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 +715,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;
|
|
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
|
|
{
|
|
switch (qpcs->interface) {
|
|
case PHY_INTERFACE_MODE_USXGMII:
|
|
+ case PHY_INTERFACE_MODE_10GBASER:
|
|
return 312500000;
|
|
default:
|
|
return 125000000;
|