From adc1625e7096b4da6802c6c8ef1f398f1670e856 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 | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

--- a/drivers/net/pcs/pcs-qcom-ipq9574.c
+++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
@@ -28,6 +28,9 @@
 #define PCS_MODE_QSGMII			FIELD_PREP(PCS_MODE_SEL_MASK, 0x1)
 #define PCS_MODE_2500BASEX		FIELD_PREP(PCS_MODE_SEL_MASK, 0x8)
 #define PCS_MODE_XPCS			FIELD_PREP(PCS_MODE_SEL_MASK, 0x10)
+#define PCS_MODE_SGMII_MODE_MASK	GENMASK(6, 4)
+#define PCS_MODE_SGMII_MODE_1000BASEX	FIELD_PREP(PCS_MODE_SGMII_MODE_MASK, \
+						   0x0)
 
 #define PCS_MII_CTRL(x)			(0x480 + 0x18 * (x))
 #define PCS_MII_ADPT_RESET		BIT(11)
@@ -249,10 +252,11 @@ static int ipq_pcs_config_mode(struct ip
 			       phy_interface_t interface)
 {
 	unsigned long rate = 125000000;
-	unsigned int val;
+	unsigned int val, mask;
 	int ret;
 
 	/* Configure PCS interface mode */
+	mask = PCS_MODE_SEL_MASK;
 	switch (interface) {
 	case PHY_INTERFACE_MODE_SGMII:
 		val = PCS_MODE_SGMII;
@@ -260,6 +264,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_MODE_MASK;
+		val = PCS_MODE_SGMII | PCS_MODE_SGMII_MODE_1000BASEX;
+		break;
 	case PHY_INTERFACE_MODE_2500BASEX:
 		val = PCS_MODE_2500BASEX;
 		rate = 312500000;
@@ -273,8 +281,7 @@ static int ipq_pcs_config_mode(struct ip
 		return -EOPNOTSUPP;
 	}
 
-	ret = regmap_update_bits(qpcs->regmap, PCS_MODE_CTRL,
-				 PCS_MODE_SEL_MASK, val);
+	ret = regmap_update_bits(qpcs->regmap, PCS_MODE_CTRL, mask, val);
 	if (ret)
 		return ret;
 
@@ -487,6 +494,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_1000BASEX:
 	case PHY_INTERFACE_MODE_10GBASER:
 		return 0;
 	case PHY_INTERFACE_MODE_2500BASEX:
@@ -509,6 +517,7 @@ static unsigned int ipq_pcs_inband_caps(
 	switch (interface) {
 	case PHY_INTERFACE_MODE_SGMII:
 	case PHY_INTERFACE_MODE_QSGMII:
+	case PHY_INTERFACE_MODE_1000BASEX:
 	case PHY_INTERFACE_MODE_USXGMII:
 		return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
 	case PHY_INTERFACE_MODE_2500BASEX:
@@ -563,6 +572,10 @@ static void ipq_pcs_get_state(struct phy
 	switch (state->interface) {
 	case PHY_INTERFACE_MODE_SGMII:
 	case PHY_INTERFACE_MODE_QSGMII:
+	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:
@@ -599,6 +612,7 @@ static int ipq_pcs_config(struct phylink
 	switch (interface) {
 	case PHY_INTERFACE_MODE_SGMII:
 	case PHY_INTERFACE_MODE_QSGMII:
+	case PHY_INTERFACE_MODE_1000BASEX:
 		return ipq_pcs_config_sgmii(qpcs, index, neg_mode, interface);
 	case PHY_INTERFACE_MODE_2500BASEX:
 		return ipq_pcs_config_2500basex(qpcs);
@@ -624,6 +638,7 @@ static void ipq_pcs_link_up(struct phyli
 	switch (interface) {
 	case PHY_INTERFACE_MODE_SGMII:
 	case PHY_INTERFACE_MODE_QSGMII:
+	case PHY_INTERFACE_MODE_1000BASEX:
 		ret = ipq_pcs_link_up_config_sgmii(qpcs, index,
 						   neg_mode, speed);
 		break;
