1 From fcd1c53b460aa39cfd15f842126af62b27a4fad5 Mon Sep 17 00:00:00 2001
2 From: Lei Wei <quic_leiwei@quicinc.com>
3 Date: Tue, 2 Apr 2024 18:28:42 +0800
4 Subject: [PATCH 13/50] net: pcs: Add 2500BASEX interface mode support to IPQ
7 2500BASEX mode is used when PCS connects with QCA8386 switch in a fixed
8 2500M link. It is also used when PCS connectes with QCA8081 PHY which
9 works at 2500M link speed. In addition, it can be also used when PCS
10 connects with a 2.5G SFP module.
12 Change-Id: I3fe61113c1b3685debc20659736a9488216a029d
13 Signed-off-by: Lei Wei <quic_leiwei@quicinc.com>
15 drivers/net/pcs/pcs-qcom-ipq-uniphy.c | 95 +++++++++++++++++++++++++++
16 1 file changed, 95 insertions(+)
18 diff --git a/drivers/net/pcs/pcs-qcom-ipq-uniphy.c b/drivers/net/pcs/pcs-qcom-ipq-uniphy.c
19 index 68a1715531ef..ed9c55a6c0fa 100644
20 --- a/drivers/net/pcs/pcs-qcom-ipq-uniphy.c
21 +++ b/drivers/net/pcs/pcs-qcom-ipq-uniphy.c
23 #define PCS_MODE_SGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x4)
24 #define PCS_MODE_QSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x1)
25 #define PCS_MODE_PSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x2)
26 +#define PCS_MODE_SGMII_PLUS FIELD_PREP(PCS_MODE_SEL_MASK, 0x8)
27 #define PCS_MODE_XPCS FIELD_PREP(PCS_MODE_SEL_MASK, 0x10)
28 #define PCS_MODE_AN_MODE BIT(0)
30 @@ -282,6 +283,24 @@ static void ipq_unipcs_get_state_sgmii(struct ipq_uniphy_pcs *qunipcs,
31 state->pause |= MLO_PAUSE_RX;
34 +static void ipq_unipcs_get_state_2500basex(struct ipq_uniphy_pcs *qunipcs,
36 + struct phylink_link_state *state)
40 + val = ipq_unipcs_reg_read32(qunipcs, PCS_CHANNEL_STS(channel));
42 + state->link = !!(val & PCS_CHANNEL_LINK_STS);
47 + state->speed = SPEED_2500;
48 + state->duplex = DUPLEX_FULL;
49 + state->pause |= MLO_PAUSE_TXRX_MASK;
52 static void ipq_unipcs_get_state_usxgmii(struct ipq_uniphy_pcs *qunipcs,
53 struct phylink_link_state *state)
55 @@ -373,6 +392,12 @@ static int ipq_unipcs_config_mode(struct ipq_uniphy_pcs *qunipcs,
56 PCS_MODE_SEL_MASK | PCS_MODE_AN_MODE,
59 + case PHY_INTERFACE_MODE_2500BASEX:
61 + ipq_unipcs_reg_modify32(qunipcs, PCS_MODE_CTRL,
63 + PCS_MODE_SGMII_PLUS);
65 case PHY_INTERFACE_MODE_USXGMII:
66 case PHY_INTERFACE_MODE_10GBASER:
68 @@ -450,6 +475,22 @@ static int ipq_unipcs_config_sgmii(struct ipq_uniphy_pcs *qunipcs,
72 +static int ipq_unipcs_config_2500basex(struct ipq_uniphy_pcs *qunipcs,
73 + phy_interface_t interface)
77 + if (qunipcs->interface != interface) {
78 + ret = ipq_unipcs_config_mode(qunipcs, interface);
82 + qunipcs->interface = interface;
88 static int ipq_unipcs_config_usxgmii(struct ipq_uniphy_pcs *qunipcs,
89 unsigned int neg_mode,
90 phy_interface_t interface)
91 @@ -522,6 +563,21 @@ static unsigned long ipq_unipcs_clock_rate_get_gmii(int speed)
95 +static unsigned long ipq_unipcs_clock_rate_get_gmiiplus(int speed)
97 + unsigned long rate = 0;
110 static unsigned long ipq_unipcs_clock_rate_get_xgmii(int speed)
112 unsigned long rate = 0;
113 @@ -566,6 +622,9 @@ ipq_unipcs_link_up_clock_rate_set(struct ipq_uniphy_pcs_ch *qunipcs_ch,
114 case PHY_INTERFACE_MODE_PSGMII:
115 rate = ipq_unipcs_clock_rate_get_gmii(speed);
117 + case PHY_INTERFACE_MODE_2500BASEX:
118 + rate = ipq_unipcs_clock_rate_get_gmiiplus(speed);
120 case PHY_INTERFACE_MODE_USXGMII:
121 case PHY_INTERFACE_MODE_10GBASER:
122 rate = ipq_unipcs_clock_rate_get_xgmii(speed);
123 @@ -627,6 +686,21 @@ static void ipq_unipcs_link_up_config_sgmii(struct ipq_uniphy_pcs *qunipcs,
124 PCS_CHANNEL_ADPT_RESET);
127 +static void ipq_unipcs_link_up_config_2500basex(struct ipq_uniphy_pcs *qunipcs,
131 + /* 2500BASEX do not support autoneg and do not need to
132 + * configure PCS speed, only reset PCS adapter here.
134 + ipq_unipcs_reg_modify32(qunipcs, PCS_CHANNEL_CTRL(channel),
135 + PCS_CHANNEL_ADPT_RESET,
137 + ipq_unipcs_reg_modify32(qunipcs, PCS_CHANNEL_CTRL(channel),
138 + PCS_CHANNEL_ADPT_RESET,
139 + PCS_CHANNEL_ADPT_RESET);
142 static void ipq_unipcs_link_up_config_usxgmii(struct ipq_uniphy_pcs *qunipcs,
145 @@ -669,6 +743,17 @@ static void ipq_unipcs_link_up_config_usxgmii(struct ipq_uniphy_pcs *qunipcs,
146 XPCS_USXG_ADPT_RESET);
149 +static int ipq_unipcs_validate(struct phylink_pcs *pcs,
150 + unsigned long *supported,
151 + const struct phylink_link_state *state)
153 + /* In-band autoneg is not supported for 2500BASEX */
154 + if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
155 + phylink_clear(supported, Autoneg);
160 static void ipq_unipcs_get_state(struct phylink_pcs *pcs,
161 struct phylink_link_state *state)
163 @@ -682,6 +767,9 @@ static void ipq_unipcs_get_state(struct phylink_pcs *pcs,
164 case PHY_INTERFACE_MODE_PSGMII:
165 ipq_unipcs_get_state_sgmii(qunipcs, channel, state);
167 + case PHY_INTERFACE_MODE_2500BASEX:
168 + ipq_unipcs_get_state_2500basex(qunipcs, channel, state);
170 case PHY_INTERFACE_MODE_USXGMII:
171 ipq_unipcs_get_state_usxgmii(qunipcs, state);
173 @@ -716,6 +804,8 @@ static int ipq_unipcs_config(struct phylink_pcs *pcs,
174 case PHY_INTERFACE_MODE_PSGMII:
175 return ipq_unipcs_config_sgmii(qunipcs, channel,
176 neg_mode, interface);
177 + case PHY_INTERFACE_MODE_2500BASEX:
178 + return ipq_unipcs_config_2500basex(qunipcs, interface);
179 case PHY_INTERFACE_MODE_USXGMII:
180 return ipq_unipcs_config_usxgmii(qunipcs,
181 neg_mode, interface);
182 @@ -748,6 +838,10 @@ static void ipq_unipcs_link_up(struct phylink_pcs *pcs,
183 ipq_unipcs_link_up_config_sgmii(qunipcs, channel,
186 + case PHY_INTERFACE_MODE_2500BASEX:
187 + ipq_unipcs_link_up_config_2500basex(qunipcs,
190 case PHY_INTERFACE_MODE_USXGMII:
191 ipq_unipcs_link_up_config_usxgmii(qunipcs, speed);
193 @@ -761,6 +855,7 @@ static void ipq_unipcs_link_up(struct phylink_pcs *pcs,
196 static const struct phylink_pcs_ops ipq_unipcs_phylink_ops = {
197 + .pcs_validate = ipq_unipcs_validate,
198 .pcs_get_state = ipq_unipcs_get_state,
199 .pcs_config = ipq_unipcs_config,
200 .pcs_link_up = ipq_unipcs_link_up,