]> git.ipfire.org Git - thirdparty/openwrt.git/blob
6e75cdfb0bddec17da3c5ec1f48f19692f260f7f
[thirdparty/openwrt.git] /
1 From 77462c0d74e51a24408062b93c3fcc0256909d33 Mon Sep 17 00:00:00 2001
2 From: Lei Wei <quic_leiwei@quicinc.com>
3 Date: Mon, 15 Apr 2024 11:06:02 +0800
4 Subject: [PATCH] net: pcs: Add 10G_QXGMII interface mode support to IPQ UNIPHY
5 PCS driver
6
7 10G_QXGMII is used when PCS connectes with QCA8084 four ports
8 2.5G PHYs.
9
10 Change-Id: If3dc92a07ac3e51f7c9473fb05fa0668617916fb
11 Signed-off-by: Lei Wei <quic_leiwei@quicinc.com>
12 Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
13 ---
14 drivers/net/pcs/pcs-qcom-ipq9574.c | 112 +++++++++++++++++++++++------
15 1 file changed, 91 insertions(+), 21 deletions(-)
16
17 --- a/drivers/net/pcs/pcs-qcom-ipq9574.c
18 +++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
19 @@ -53,6 +53,9 @@
20 #define PCS_MII_STS_PAUSE_TX_EN BIT(1)
21 #define PCS_MII_STS_PAUSE_RX_EN BIT(0)
22
23 +#define PCS_QP_USXG_OPTION 0x584
24 +#define PCS_QP_USXG_GMII_SRC_XPCS BIT(0)
25 +
26 #define PCS_PLL_RESET 0x780
27 #define PCS_ANA_SW_RESET BIT(6)
28
29 @@ -68,10 +71,22 @@
30 #define XPCS_10GBASER_LINK_STS BIT(12)
31
32 #define XPCS_DIG_CTRL 0x38000
33 +#define XPCS_SOFT_RESET BIT(15)
34 #define XPCS_USXG_ADPT_RESET BIT(10)
35 #define XPCS_USXG_EN BIT(9)
36
37 +#define XPCS_KR_CTRL 0x38007
38 +#define XPCS_USXG_MODE_MASK GENMASK(12, 10)
39 +#define XPCS_10G_QXGMII_MODE FIELD_PREP(XPCS_USXG_MODE_MASK, 0x5)
40 +
41 +#define XPCS_DIG_STS 0x3800a
42 +#define XPCS_DIG_STS_AM_COUNT GENMASK(14, 0)
43 +
44 +#define XPCS_CHANNEL_DIG_CTRL(x) (0x1a8000 + 0x10000 * ((x) - 1))
45 +#define XPCS_CHANNEL_USXG_ADPT_RESET BIT(5)
46 +
47 #define XPCS_MII_CTRL 0x1f0000
48 +#define XPCS_CHANNEL_MII_CTRL(x) (0x1a0000 + 0x10000 * ((x) - 1))
49 #define XPCS_MII_AN_EN BIT(12)
50 #define XPCS_DUPLEX_FULL BIT(8)
51 #define XPCS_SPEED_MASK (BIT(13) | BIT(6) | BIT(5))
52 @@ -83,9 +98,11 @@
53 #define XPCS_SPEED_10 0
54
55 #define XPCS_MII_AN_CTRL 0x1f8001
56 +#define XPCS_CHANNEL_MII_AN_CTRL(x) (0x1a8001 + 0x10000 * ((x) - 1))
57 #define XPCS_MII_AN_8BIT BIT(8)
58
59 #define XPCS_MII_AN_INTR_STS 0x1f8002
60 +#define XPCS_CHANNEL_MII_AN_INTR_STS(x) (0x1a8002 + 0x10000 * ((x) - 1))
61 #define XPCS_USXG_AN_LINK_STS BIT(14)
62 #define XPCS_USXG_AN_SPEED_MASK GENMASK(12, 10)
63 #define XPCS_USXG_AN_SPEED_10 0
64 @@ -95,6 +112,10 @@
65 #define XPCS_USXG_AN_SPEED_5000 5
66 #define XPCS_USXG_AN_SPEED_10000 3
67
68 +#define XPCS_XAUI_MODE_CTRL 0x1f8004
69 +#define XPCS_CHANNEL_XAUI_MODE_CTRL(x) (0x1a8004 + 0x10000 * ((x) - 1))
70 +#define XPCS_TX_IPG_CHECK_DIS BIT(0)
71 +
72 /* Per PCS MII private data */
73 struct ipq_pcs_mii {
74 struct ipq_pcs *qpcs;
75 @@ -217,12 +238,16 @@ static void ipq_unipcs_get_state_2500bas
76 }
77
78 static void ipq_pcs_get_state_usxgmii(struct ipq_pcs *qpcs,
79 + int index,
80 struct phylink_link_state *state)
81 {
82 unsigned int val;
83 - int ret;
84 + int ret, reg;
85 +
86 + reg = (index == 0) ? XPCS_MII_AN_INTR_STS :
87 + XPCS_CHANNEL_MII_AN_INTR_STS(index);
88
89 - ret = regmap_read(qpcs->regmap, XPCS_MII_AN_INTR_STS, &val);
90 + ret = regmap_read(qpcs->regmap, reg, &val);
91 if (ret) {
92 state->link = 0;
93 return;
94 @@ -316,6 +341,14 @@ static int ipq_pcs_config_mode(struct ip
95 val = PCS_MODE_XPCS;
96 rate = 312500000;
97 break;
98 + case PHY_INTERFACE_MODE_10G_QXGMII:
99 + val = PCS_MODE_XPCS;
100 + rate = 312500000;
101 + ret = regmap_set_bits(qpcs->regmap, PCS_QP_USXG_OPTION,
102 + PCS_QP_USXG_GMII_SRC_XPCS);
103 + if (ret)
104 + return ret;
105 + break;
106 default:
107 dev_err(qpcs->dev,
108 "interface %s not supported\n", phy_modes(interface));
109 @@ -407,30 +440,55 @@ static int ipq_unipcs_config_2500basex(s
110 return 0;
111 }
112
113 -static int ipq_pcs_config_usxgmii(struct ipq_pcs *qpcs)
114 +static int ipq_pcs_config_usxgmii(struct ipq_pcs *qpcs,
115 + int index,
116 + phy_interface_t interface)
117 {
118 - int ret;
119 + int ret, reg;
120
121 /* Configure the XPCS for USXGMII mode if required */
122 - if (qpcs->interface == PHY_INTERFACE_MODE_USXGMII)
123 - return 0;
124 -
125 - ret = ipq_pcs_config_mode(qpcs, PHY_INTERFACE_MODE_USXGMII);
126 - if (ret)
127 - return ret;
128 + if (qpcs->interface != interface) {
129 + ret = ipq_pcs_config_mode(qpcs, interface);
130 + if (ret)
131 + return ret;
132 + }
133
134 - /* Deassert XPCS and configure XPCS USXGMII */
135 + /* Deassert XPCS and configure XPCS USXGMII or 10G_QXGMII */
136 reset_control_deassert(qpcs->reset[XPCS_RESET]);
137
138 ret = regmap_set_bits(qpcs->regmap, XPCS_DIG_CTRL, XPCS_USXG_EN);
139 if (ret)
140 return ret;
141
142 - ret = regmap_set_bits(qpcs->regmap, XPCS_MII_AN_CTRL, XPCS_MII_AN_8BIT);
143 + if (interface == PHY_INTERFACE_MODE_10G_QXGMII) {
144 + regmap_update_bits(qpcs->regmap, XPCS_KR_CTRL,
145 + XPCS_USXG_MODE_MASK, XPCS_10G_QXGMII_MODE);
146 +
147 + /* Set Alignment Marker Interval */
148 + regmap_update_bits(qpcs->regmap, XPCS_DIG_STS,
149 + XPCS_DIG_STS_AM_COUNT, 0x6018);
150 +
151 + regmap_set_bits(qpcs->regmap, XPCS_DIG_CTRL, XPCS_SOFT_RESET);
152 + }
153 +
154 + qpcs->interface = interface;
155 +
156 + /* Disable Tx IPG check for 10G_QXGMII */
157 + if (interface == PHY_INTERFACE_MODE_10G_QXGMII) {
158 + reg = (index == 0) ? XPCS_XAUI_MODE_CTRL :
159 + XPCS_CHANNEL_XAUI_MODE_CTRL(index);
160 +
161 + regmap_set_bits(qpcs->regmap, reg, XPCS_TX_IPG_CHECK_DIS);
162 + }
163 +
164 + /* Enable autoneg */
165 + reg = (index == 0) ? XPCS_MII_AN_CTRL : XPCS_CHANNEL_MII_AN_CTRL(index);
166 + ret = regmap_set_bits(qpcs->regmap, reg, XPCS_MII_AN_8BIT);
167 if (ret)
168 return ret;
169
170 - return regmap_set_bits(qpcs->regmap, XPCS_MII_CTRL, XPCS_MII_AN_EN);
171 + reg = (index == 0) ? XPCS_MII_CTRL : XPCS_CHANNEL_MII_CTRL(index);
172 + return regmap_set_bits(qpcs->regmap, reg, XPCS_MII_AN_EN);
173 }
174
175 static int ipq_unipcs_config_10gbaser(struct ipq_pcs *qpcs,
176 @@ -538,6 +596,7 @@ ipq_unipcs_link_up_clock_rate_set(struct
177 break;
178 case PHY_INTERFACE_MODE_USXGMII:
179 case PHY_INTERFACE_MODE_10GBASER:
180 + case PHY_INTERFACE_MODE_10G_QXGMII:
181 rate = ipq_unipcs_clock_rate_get_xgmii(speed);
182 break;
183 default:
184 @@ -603,7 +662,6 @@ static int ipq_unipcs_link_up_config_250
185 int index,
186 int speed)
187 {
188 - unsigned int val;
189 int ret;
190
191 /* 2500BASEX do not support autoneg and do not need to
192 @@ -618,10 +676,12 @@ static int ipq_unipcs_link_up_config_250
193 PCS_MII_CTRL(index), PCS_MII_ADPT_RESET);
194 }
195
196 -static int ipq_pcs_link_up_config_usxgmii(struct ipq_pcs *qpcs, int speed)
197 +static int ipq_pcs_link_up_config_usxgmii(struct ipq_pcs *qpcs,
198 + int channel,
199 + int speed)
200 {
201 unsigned int val;
202 - int ret;
203 + int ret, reg;
204
205 switch (speed) {
206 case SPEED_10000:
207 @@ -648,14 +708,19 @@ static int ipq_pcs_link_up_config_usxgmi
208 }
209
210 /* Configure XPCS speed */
211 - ret = regmap_update_bits(qpcs->regmap, XPCS_MII_CTRL,
212 + reg = (channel == 0) ? XPCS_MII_CTRL : XPCS_CHANNEL_MII_CTRL(channel);
213 + ret = regmap_update_bits(qpcs->regmap, reg,
214 XPCS_SPEED_MASK, val | XPCS_DUPLEX_FULL);
215 if (ret)
216 return ret;
217
218 /* XPCS adapter reset */
219 - return regmap_set_bits(qpcs->regmap,
220 + if (channel == 0)
221 + return regmap_set_bits(qpcs->regmap,
222 XPCS_DIG_CTRL, XPCS_USXG_ADPT_RESET);
223 + else
224 + return regmap_set_bits(qpcs->regmap, XPCS_CHANNEL_DIG_CTRL(channel),
225 + XPCS_CHANNEL_USXG_ADPT_RESET);
226 }
227
228 static int ipq_pcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
229 @@ -669,6 +734,7 @@ static int ipq_pcs_validate(struct phyli
230 /* In-band autoneg is not supported for 2500BASEX */
231 phylink_clear(supported, Autoneg);
232 return 0;
233 + case PHY_INTERFACE_MODE_10G_QXGMII:
234 case PHY_INTERFACE_MODE_USXGMII:
235 /* USXGMII only supports full duplex mode */
236 phylink_clear(supported, 100baseT_Half);
237 @@ -747,7 +813,8 @@ static void ipq_pcs_get_state(struct phy
238 ipq_unipcs_get_state_2500basex(qpcs, index, state);
239 break;
240 case PHY_INTERFACE_MODE_USXGMII:
241 - ipq_pcs_get_state_usxgmii(qpcs, state);
242 + case PHY_INTERFACE_MODE_10G_QXGMII:
243 + ipq_pcs_get_state_usxgmii(qpcs, index, state);
244 break;
245 case PHY_INTERFACE_MODE_10GBASER:
246 ipq_unipcs_get_state_10gbaser(qpcs, state);
247 @@ -783,7 +850,9 @@ static int ipq_pcs_config(struct phylink
248 case PHY_INTERFACE_MODE_2500BASEX:
249 return ipq_unipcs_config_2500basex(qpcs, interface);
250 case PHY_INTERFACE_MODE_USXGMII:
251 - return ipq_pcs_config_usxgmii(qpcs);
252 + case PHY_INTERFACE_MODE_10G_QXGMII:
253 + return ipq_pcs_config_usxgmii(qpcs, index,
254 + interface);
255 case PHY_INTERFACE_MODE_10GBASER:
256 return ipq_unipcs_config_10gbaser(qpcs, interface);
257 default:
258 @@ -819,7 +888,8 @@ static void ipq_pcs_link_up(struct phyli
259 ret = ipq_unipcs_link_up_config_2500basex(qpcs, index, speed);
260 break;
261 case PHY_INTERFACE_MODE_USXGMII:
262 - ret = ipq_pcs_link_up_config_usxgmii(qpcs, speed);
263 + case PHY_INTERFACE_MODE_10G_QXGMII:
264 + ret = ipq_pcs_link_up_config_usxgmii(qpcs, index, speed);
265 break;
266 case PHY_INTERFACE_MODE_10GBASER:
267 break;