blob: 282fd30f53561f61787c0913de05967a37a3bfe8 [file] [log] [blame]
developerfd40db22021-04-29 10:08:25 +08001// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2018-2019 MediaTek Inc.
3
4/* A library for MediaTek SGMII circuit
5 *
6 * Author: Sean Wang <sean.wang@mediatek.com>
7 *
8 */
9
10#include <linux/mfd/syscon.h>
11#include <linux/of.h>
developer38afb1a2023-04-17 09:57:27 +080012#include <linux/phylink.h>
developerfd40db22021-04-29 10:08:25 +080013#include <linux/regmap.h>
14
15#include "mtk_eth_soc.h"
16
developer4e8a3fd2023-04-10 18:05:44 +080017static struct mtk_sgmii_pcs *pcs_to_mtk_sgmii_pcs(struct phylink_pcs *pcs)
18{
19 return container_of(pcs, struct mtk_sgmii_pcs, pcs);
20}
21
22static int mtk_sgmii_xfi_pextp_init(struct mtk_sgmii *ss, struct device_node *r)
developerfd40db22021-04-29 10:08:25 +080023{
24 struct device_node *np;
25 int i;
26
developerfd40db22021-04-29 10:08:25 +080027 for (i = 0; i < MTK_MAX_DEVS; i++) {
developer4e8a3fd2023-04-10 18:05:44 +080028 np = of_parse_phandle(r, "mediatek,xfi_pextp", i);
developerfd40db22021-04-29 10:08:25 +080029 if (!np)
30 break;
31
developer4e8a3fd2023-04-10 18:05:44 +080032 ss->pcs[i].regmap_pextp = syscon_node_to_regmap(np);
33 if (IS_ERR(ss->pcs[i].regmap_pextp))
34 return PTR_ERR(ss->pcs[i].regmap_pextp);
developerf8ac94a2021-07-29 16:40:01 +080035
developer4e8a3fd2023-04-10 18:05:44 +080036 of_node_put(np);
developerfd40db22021-04-29 10:08:25 +080037 }
38
39 return 0;
40}
41
developer4e8a3fd2023-04-10 18:05:44 +080042static int mtk_sgmii_xfi_pll_init(struct mtk_sgmii *ss, struct device_node *r)
43{
44 struct device_node *np;
45
46 np = of_parse_phandle(r, "mediatek,xfi_pll", 0);
47 if (!np)
48 return -1;
49
50 ss->pll = syscon_node_to_regmap(np);
51 if (IS_ERR(ss->pll))
52 return PTR_ERR(ss->pll);
53
54 of_node_put(np);
55
56 return 0;
57}
58
59static int mtk_sgmii_xfi_pll_enable(struct mtk_sgmii *ss)
developer024387a2022-12-07 22:18:27 +080060{
developer024387a2022-12-07 22:18:27 +080061 u32 val = 0;
62
developer4e8a3fd2023-04-10 18:05:44 +080063 if (!ss->pll)
64 return -EINVAL;
65
66 /* Add software workaround for USXGMII PLL TCL issue */
67 regmap_write(ss->pll, XFI_PLL_ANA_GLB8, RG_XFI_PLL_ANA_SWWA);
68
69 regmap_read(ss->pll, XFI_PLL_DIG_GLB8, &val);
70 val |= RG_XFI_PLL_EN;
71 regmap_write(ss->pll, XFI_PLL_DIG_GLB8, val);
72
73 return 0;
74}
75
76void mtk_sgmii_reset(struct mtk_eth *eth, int id)
77{
78 u32 val = 0;
79
80 if (!eth->toprgu)
developer024387a2022-12-07 22:18:27 +080081 return;
82
developer4e8a3fd2023-04-10 18:05:44 +080083 switch (id) {
84 case 0:
developer024387a2022-12-07 22:18:27 +080085 /* Enable software reset */
86 regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
developer4e8a3fd2023-04-10 18:05:44 +080087 val |= SWSYSRST_XFI_PEXPT0_GRST |
88 SWSYSRST_SGMII0_GRST;
developer024387a2022-12-07 22:18:27 +080089 regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
90
91 /* Assert SGMII reset */
92 regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
93 val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) |
developer4e8a3fd2023-04-10 18:05:44 +080094 SWSYSRST_XFI_PEXPT0_GRST |
95 SWSYSRST_SGMII0_GRST;
developer024387a2022-12-07 22:18:27 +080096 regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
97
98 udelay(100);
99
100 /* De-assert SGMII reset */
101 regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
102 val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88);
developer4e8a3fd2023-04-10 18:05:44 +0800103 val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
104 SWSYSRST_SGMII0_GRST);
developer024387a2022-12-07 22:18:27 +0800105 regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
106
107 /* Disable software reset */
108 regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
developer4e8a3fd2023-04-10 18:05:44 +0800109 val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
110 SWSYSRST_SGMII0_GRST);
developer024387a2022-12-07 22:18:27 +0800111 regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
112 break;
developer4e8a3fd2023-04-10 18:05:44 +0800113 case 1:
114 /* Enable software reset */
developer024387a2022-12-07 22:18:27 +0800115 regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
developer4e8a3fd2023-04-10 18:05:44 +0800116 val |= SWSYSRST_XFI_PEXPT1_GRST |
117 SWSYSRST_SGMII1_GRST;
developer024387a2022-12-07 22:18:27 +0800118 regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
119
120 /* Assert SGMII reset */
121 regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
122 val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) |
developer4e8a3fd2023-04-10 18:05:44 +0800123 SWSYSRST_XFI_PEXPT1_GRST |
124 SWSYSRST_SGMII1_GRST;
developer024387a2022-12-07 22:18:27 +0800125 regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
126
127 udelay(100);
128
129 /* De-assert SGMII reset */
130 regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
131 val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88);
developer4e8a3fd2023-04-10 18:05:44 +0800132 val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
133 SWSYSRST_SGMII1_GRST);
developer024387a2022-12-07 22:18:27 +0800134 regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
135
136 /* Disable software reset */
137 regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
developer4e8a3fd2023-04-10 18:05:44 +0800138 val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
139 SWSYSRST_SGMII1_GRST);
developer024387a2022-12-07 22:18:27 +0800140 regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
141 break;
142 }
143
144 mdelay(1);
145}
146
developer4e8a3fd2023-04-10 18:05:44 +0800147void mtk_sgmii_setup_phya_gen1(struct mtk_sgmii_pcs *mpcs)
developerfd40db22021-04-29 10:08:25 +0800148{
developer4e8a3fd2023-04-10 18:05:44 +0800149 if (!mpcs->regmap_pextp)
developer089e8852022-09-28 14:43:46 +0800150 return;
151
developer4e8a3fd2023-04-10 18:05:44 +0800152 regmap_update_bits(mpcs->regmap_pextp, 0x9024, GENMASK(31, 0),
153 0x00D9071C);
154 regmap_update_bits(mpcs->regmap_pextp, 0x2020, GENMASK(31, 0),
155 0xAA8585AA);
156 regmap_update_bits(mpcs->regmap_pextp, 0x2030, GENMASK(31, 0),
157 0x0C020207);
158 regmap_update_bits(mpcs->regmap_pextp, 0x2034, GENMASK(31, 0),
159 0x0E05050F);
160 regmap_update_bits(mpcs->regmap_pextp, 0x2040, GENMASK(31, 0),
161 0x00200032);
162 regmap_update_bits(mpcs->regmap_pextp, 0x50F0, GENMASK(31, 0),
163 0x00C014BA);
164 regmap_update_bits(mpcs->regmap_pextp, 0x50E0, GENMASK(31, 0),
165 0x3777C12B);
166 regmap_update_bits(mpcs->regmap_pextp, 0x506C, GENMASK(31, 0),
167 0x005F9CFF);
168 regmap_update_bits(mpcs->regmap_pextp, 0x5070, GENMASK(31, 0),
169 0x9D9DFAFA);
170 regmap_update_bits(mpcs->regmap_pextp, 0x5074, GENMASK(31, 0),
171 0x27273F3F);
172 regmap_update_bits(mpcs->regmap_pextp, 0x5078, GENMASK(31, 0),
173 0xA7883C68);
174 regmap_update_bits(mpcs->regmap_pextp, 0x507C, GENMASK(31, 0),
175 0x11661166);
176 regmap_update_bits(mpcs->regmap_pextp, 0x5080, GENMASK(31, 0),
177 0x0E000EAF);
178 regmap_update_bits(mpcs->regmap_pextp, 0x5084, GENMASK(31, 0),
179 0x08080E0D);
180 regmap_update_bits(mpcs->regmap_pextp, 0x5088, GENMASK(31, 0),
181 0x02030B09);
182 regmap_update_bits(mpcs->regmap_pextp, 0x50E4, GENMASK(31, 0),
183 0x0C0C0000);
184 regmap_update_bits(mpcs->regmap_pextp, 0x50E8, GENMASK(31, 0),
185 0x04040000);
186 regmap_update_bits(mpcs->regmap_pextp, 0x50EC, GENMASK(31, 0),
187 0x0F0F0606);
188 regmap_update_bits(mpcs->regmap_pextp, 0x50A8, GENMASK(31, 0),
189 0x506E8C8C);
190 regmap_update_bits(mpcs->regmap_pextp, 0x6004, GENMASK(31, 0),
191 0x18190000);
192 regmap_update_bits(mpcs->regmap_pextp, 0x00F8, GENMASK(31, 0),
193 0x00FA32FA);
194 regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
195 0x80201F21);
196 regmap_update_bits(mpcs->regmap_pextp, 0x0030, GENMASK(31, 0),
197 0x00050C00);
198 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
199 0x02002800);
developer089e8852022-09-28 14:43:46 +0800200 ndelay(1020);
developer4e8a3fd2023-04-10 18:05:44 +0800201 regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
202 0x00000020);
203 regmap_update_bits(mpcs->regmap_pextp, 0x3028, GENMASK(31, 0),
204 0x00008A01);
205 regmap_update_bits(mpcs->regmap_pextp, 0x302C, GENMASK(31, 0),
206 0x0000A884);
207 regmap_update_bits(mpcs->regmap_pextp, 0x3024, GENMASK(31, 0),
208 0x00083002);
209 regmap_update_bits(mpcs->regmap_pextp, 0x3010, GENMASK(31, 0),
210 0x00011110);
211 regmap_update_bits(mpcs->regmap_pextp, 0x3048, GENMASK(31, 0),
212 0x40704000);
213 regmap_update_bits(mpcs->regmap_pextp, 0x3064, GENMASK(31, 0),
214 0x0000C000);
215 regmap_update_bits(mpcs->regmap_pextp, 0x3050, GENMASK(31, 0),
216 0xA8000000);
217 regmap_update_bits(mpcs->regmap_pextp, 0x3054, GENMASK(31, 0),
218 0x000000AA);
219 regmap_update_bits(mpcs->regmap_pextp, 0x306C, GENMASK(31, 0),
220 0x20200F00);
221 regmap_update_bits(mpcs->regmap_pextp, 0xA060, GENMASK(31, 0),
222 0x00050000);
223 regmap_update_bits(mpcs->regmap_pextp, 0x90D0, GENMASK(31, 0),
224 0x00000007);
225 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
226 0x0200E800);
developer089e8852022-09-28 14:43:46 +0800227 udelay(150);
developer4e8a3fd2023-04-10 18:05:44 +0800228 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
229 0x0200C111);
developer089e8852022-09-28 14:43:46 +0800230 ndelay(1020);
developer4e8a3fd2023-04-10 18:05:44 +0800231 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
232 0x0200C101);
developer089e8852022-09-28 14:43:46 +0800233 udelay(15);
developer4e8a3fd2023-04-10 18:05:44 +0800234 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
235 0x0201C111);
developer089e8852022-09-28 14:43:46 +0800236 ndelay(1020);
developer4e8a3fd2023-04-10 18:05:44 +0800237 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
238 0x0201C101);
developer089e8852022-09-28 14:43:46 +0800239 udelay(100);
developer4e8a3fd2023-04-10 18:05:44 +0800240 regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
241 0x00000030);
242 regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
243 0x80201F01);
244 regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
245 0x30000000);
developer089e8852022-09-28 14:43:46 +0800246 udelay(400);
247}
248
developer4e8a3fd2023-04-10 18:05:44 +0800249void mtk_sgmii_setup_phya_gen2(struct mtk_sgmii_pcs *mpcs)
developer089e8852022-09-28 14:43:46 +0800250{
developer4e8a3fd2023-04-10 18:05:44 +0800251 if (!mpcs->regmap_pextp)
developer089e8852022-09-28 14:43:46 +0800252 return;
253
developer4e8a3fd2023-04-10 18:05:44 +0800254 regmap_update_bits(mpcs->regmap_pextp, 0x9024, GENMASK(31, 0),
255 0x00D9071C);
256 regmap_update_bits(mpcs->regmap_pextp, 0x2020, GENMASK(31, 0),
257 0xAA8585AA);
258 regmap_update_bits(mpcs->regmap_pextp, 0x2030, GENMASK(31, 0),
259 0x0C020707);
260 regmap_update_bits(mpcs->regmap_pextp, 0x2034, GENMASK(31, 0),
261 0x0E050F0F);
262 regmap_update_bits(mpcs->regmap_pextp, 0x2040, GENMASK(31, 0),
263 0x00140032);
264 regmap_update_bits(mpcs->regmap_pextp, 0x50F0, GENMASK(31, 0),
265 0x00C014AA);
266 regmap_update_bits(mpcs->regmap_pextp, 0x50E0, GENMASK(31, 0),
267 0x3777C12B);
268 regmap_update_bits(mpcs->regmap_pextp, 0x506C, GENMASK(31, 0),
269 0x005F9CFF);
270 regmap_update_bits(mpcs->regmap_pextp, 0x5070, GENMASK(31, 0),
271 0x9D9DFAFA);
272 regmap_update_bits(mpcs->regmap_pextp, 0x5074, GENMASK(31, 0),
273 0x27273F3F);
274 regmap_update_bits(mpcs->regmap_pextp, 0x5078, GENMASK(31, 0),
275 0xA7883C68);
276 regmap_update_bits(mpcs->regmap_pextp, 0x507C, GENMASK(31, 0),
277 0x11661166);
278 regmap_update_bits(mpcs->regmap_pextp, 0x5080, GENMASK(31, 0),
279 0x0E000AAF);
280 regmap_update_bits(mpcs->regmap_pextp, 0x5084, GENMASK(31, 0),
281 0x08080D0D);
282 regmap_update_bits(mpcs->regmap_pextp, 0x5088, GENMASK(31, 0),
283 0x02030909);
284 regmap_update_bits(mpcs->regmap_pextp, 0x50E4, GENMASK(31, 0),
285 0x0C0C0000);
286 regmap_update_bits(mpcs->regmap_pextp, 0x50E8, GENMASK(31, 0),
287 0x04040000);
288 regmap_update_bits(mpcs->regmap_pextp, 0x50EC, GENMASK(31, 0),
289 0x0F0F0C06);
290 regmap_update_bits(mpcs->regmap_pextp, 0x50A8, GENMASK(31, 0),
291 0x506E8C8C);
292 regmap_update_bits(mpcs->regmap_pextp, 0x6004, GENMASK(31, 0),
293 0x18190000);
294 regmap_update_bits(mpcs->regmap_pextp, 0x00F8, GENMASK(31, 0),
295 0x009C329C);
296 regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
297 0x80201F21);
298 regmap_update_bits(mpcs->regmap_pextp, 0x0030, GENMASK(31, 0),
299 0x00050C00);
300 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
301 0x02002800);
developer089e8852022-09-28 14:43:46 +0800302 ndelay(1020);
developer4e8a3fd2023-04-10 18:05:44 +0800303 regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
304 0x00000020);
305 regmap_update_bits(mpcs->regmap_pextp, 0x3028, GENMASK(31, 0),
306 0x00008A01);
307 regmap_update_bits(mpcs->regmap_pextp, 0x302C, GENMASK(31, 0),
308 0x0000A884);
309 regmap_update_bits(mpcs->regmap_pextp, 0x3024, GENMASK(31, 0),
310 0x00083002);
311 regmap_update_bits(mpcs->regmap_pextp, 0x3010, GENMASK(31, 0),
312 0x00011110);
313 regmap_update_bits(mpcs->regmap_pextp, 0x3048, GENMASK(31, 0),
314 0x40704000);
315 regmap_update_bits(mpcs->regmap_pextp, 0x3050, GENMASK(31, 0),
316 0xA8000000);
317 regmap_update_bits(mpcs->regmap_pextp, 0x3054, GENMASK(31, 0),
318 0x000000AA);
319 regmap_update_bits(mpcs->regmap_pextp, 0x306C, GENMASK(31, 0),
320 0x22000F00);
321 regmap_update_bits(mpcs->regmap_pextp, 0xA060, GENMASK(31, 0),
322 0x00050000);
323 regmap_update_bits(mpcs->regmap_pextp, 0x90D0, GENMASK(31, 0),
324 0x00000005);
325 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
326 0x0200E800);
developer089e8852022-09-28 14:43:46 +0800327 udelay(150);
developer4e8a3fd2023-04-10 18:05:44 +0800328 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
329 0x0200C111);
developer089e8852022-09-28 14:43:46 +0800330 ndelay(1020);
developer4e8a3fd2023-04-10 18:05:44 +0800331 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
332 0x0200C101);
developer089e8852022-09-28 14:43:46 +0800333 udelay(15);
developer4e8a3fd2023-04-10 18:05:44 +0800334 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
335 0x0201C111);
developer089e8852022-09-28 14:43:46 +0800336 ndelay(1020);
developer4e8a3fd2023-04-10 18:05:44 +0800337 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
338 0x0201C101);
developer089e8852022-09-28 14:43:46 +0800339 udelay(100);
developer4e8a3fd2023-04-10 18:05:44 +0800340 regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
341 0x00000030);
342 regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
343 0x80201F01);
344 regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
345 0x30000000);
developer089e8852022-09-28 14:43:46 +0800346 udelay(400);
347}
348
developer38afb1a2023-04-17 09:57:27 +0800349static void mtk_sgmii_pcs_get_state(struct phylink_pcs *pcs,
350 struct phylink_link_state *state)
developer089e8852022-09-28 14:43:46 +0800351{
developer38afb1a2023-04-17 09:57:27 +0800352 struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
353 unsigned int bm, adv, rgc3, sgm_mode;
developerfd40db22021-04-29 10:08:25 +0800354
developer38afb1a2023-04-17 09:57:27 +0800355 state->interface = mpcs->interface;
developer2fbee452022-08-12 13:58:20 +0800356
developer38afb1a2023-04-17 09:57:27 +0800357 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm);
358 if (bm & SGMII_AN_ENABLE) {
359 regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv);
developerfd40db22021-04-29 10:08:25 +0800360
developer38afb1a2023-04-17 09:57:27 +0800361 phylink_mii_c22_pcs_decode_state(state,
362 FIELD_GET(SGMII_BMSR, bm),
363 FIELD_GET(SGMII_LPA, adv));
364 } else {
365 state->link = !!(bm & SGMII_LINK_STATYS);
developerf8ac94a2021-07-29 16:40:01 +0800366
developer38afb1a2023-04-17 09:57:27 +0800367 regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &sgm_mode);
developer089e8852022-09-28 14:43:46 +0800368
developer38afb1a2023-04-17 09:57:27 +0800369 switch (sgm_mode & SGMII_SPEED_MASK) {
370 case SGMII_SPEED_10:
371 state->speed = SPEED_10;
372 break;
373 case SGMII_SPEED_100:
374 state->speed = SPEED_100;
375 break;
376 case SGMII_SPEED_1000:
377 regmap_read(mpcs->regmap, mpcs->ana_rgc3, &rgc3);
378 rgc3 = FIELD_GET(RG_PHY_SPEED_3_125G, rgc3);
379 state->speed = rgc3 ? SPEED_2500 : SPEED_1000;
380 break;
381 }
developerfd40db22021-04-29 10:08:25 +0800382
developer38afb1a2023-04-17 09:57:27 +0800383 if (sgm_mode & SGMII_DUPLEX_HALF)
384 state->duplex = DUPLEX_HALF;
385 else
386 state->duplex = DUPLEX_FULL;
387 }
developerfd40db22021-04-29 10:08:25 +0800388}
389
developer38afb1a2023-04-17 09:57:27 +0800390static int mtk_sgmii_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
391 phy_interface_t interface,
392 const unsigned long *advertising,
393 bool permit_pause_to_mac)
developerfd40db22021-04-29 10:08:25 +0800394{
developer38afb1a2023-04-17 09:57:27 +0800395 struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
developer4e8a3fd2023-04-10 18:05:44 +0800396 struct mtk_eth *eth = mpcs->eth;
developer38afb1a2023-04-17 09:57:27 +0800397 unsigned int rgc3, sgm_mode = 0, bmcr = 0, speed = 0;
398 bool mode_changed = false, changed;
399 int advertise, link_timer;
developerfd40db22021-04-29 10:08:25 +0800400
developer38afb1a2023-04-17 09:57:27 +0800401 advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
402 advertising);
403 if (advertise < 0)
404 return advertise;
developerfd40db22021-04-29 10:08:25 +0800405
developer024387a2022-12-07 22:18:27 +0800406 if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
developer4e8a3fd2023-04-10 18:05:44 +0800407 mtk_sgmii_xfi_pll_enable(eth->sgmii);
408 mtk_sgmii_reset(eth, mpcs->id);
developer024387a2022-12-07 22:18:27 +0800409 }
developer089e8852022-09-28 14:43:46 +0800410
developer38afb1a2023-04-17 09:57:27 +0800411 /* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and
412 * we assume that fixes it's speed at bitrate = line rate (in
413 * other words, 1000Mbps or 2500Mbps).
414 */
415 if (interface == PHY_INTERFACE_MODE_SGMII) {
416 bmcr = SGMII_AN_ENABLE;
417 sgm_mode = SGMII_IF_MODE_SGMII |
418 SGMII_REMOTE_FAULT_DIS |
419 SGMII_SPEED_DUPLEX_AN;
420 } else {
421 /* 1000base-X or HSGMII without autoneg */
422 speed = SGMII_SPEED_1000;
423 if (interface == PHY_INTERFACE_MODE_2500BASEX)
424 sgm_mode = SGMII_IF_MODE_SGMII;
425 }
developer2fbee452022-08-12 13:58:20 +0800426
developer38afb1a2023-04-17 09:57:27 +0800427 if (mpcs->interface != interface) {
428 link_timer = phylink_get_link_timer_ns(interface);
429 if (link_timer < 0)
430 return link_timer;
developer2b76a9d2022-09-20 14:59:45 +0800431
developer38afb1a2023-04-17 09:57:27 +0800432 /* PHYA power down */
433 regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
434 SGMII_PHYA_PWD, SGMII_PHYA_PWD);
developerfd40db22021-04-29 10:08:25 +0800435
developer38afb1a2023-04-17 09:57:27 +0800436 /* Reset SGMII PCS state */
437 regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0,
438 SGMII_SW_RESET, SGMII_SW_RESET);
developerfd40db22021-04-29 10:08:25 +0800439
developer38afb1a2023-04-17 09:57:27 +0800440 if (interface == PHY_INTERFACE_MODE_2500BASEX)
441 rgc3 = RG_PHY_SPEED_3_125G;
442 else
443 rgc3 = 0;
developerfd40db22021-04-29 10:08:25 +0800444
developer38afb1a2023-04-17 09:57:27 +0800445 /* Configure the underlying interface speed */
446 regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
447 RG_PHY_SPEED_3_125G, rgc3);
developer3d014da2022-05-11 16:29:59 +0800448
developer38afb1a2023-04-17 09:57:27 +0800449 /* Setup the link timer */
450 regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
451 link_timer / 2 / 8);
developer089e8852022-09-28 14:43:46 +0800452
developer38afb1a2023-04-17 09:57:27 +0800453 mpcs->interface = interface;
454 mode_changed = true;
455 }
developerfd40db22021-04-29 10:08:25 +0800456
developer38afb1a2023-04-17 09:57:27 +0800457 /* Update the advertisement, noting whether it has changed */
458 regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE,
459 SGMII_ADVERTISE, advertise, &changed);
developerfd40db22021-04-29 10:08:25 +0800460
developer38afb1a2023-04-17 09:57:27 +0800461 /* Update the sgmsys mode register */
462 regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
463 SGMII_REMOTE_FAULT_DIS | SGMII_DUPLEX_HALF |
464 SGMII_SPEED_MASK | SGMII_SPEED_DUPLEX_AN |
465 SGMII_IF_MODE_SGMII, sgm_mode | speed);
developer4e8a3fd2023-04-10 18:05:44 +0800466
developer38afb1a2023-04-17 09:57:27 +0800467 /* Update the BMCR */
468 regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1,
469 SGMII_AN_ENABLE, bmcr);
developer4e8a3fd2023-04-10 18:05:44 +0800470
developer38afb1a2023-04-17 09:57:27 +0800471 /* Release PHYA power down state */
472 usleep_range(50, 100);
473 regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
developer4e8a3fd2023-04-10 18:05:44 +0800474
developer38afb1a2023-04-17 09:57:27 +0800475 if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
476 if (interface == PHY_INTERFACE_MODE_2500BASEX)
477 mtk_sgmii_setup_phya_gen2(mpcs);
478 else
479 mtk_sgmii_setup_phya_gen1(mpcs);
developer4e8a3fd2023-04-10 18:05:44 +0800480 }
developer4e8a3fd2023-04-10 18:05:44 +0800481
developer38afb1a2023-04-17 09:57:27 +0800482 return changed || mode_changed;
developer4e8a3fd2023-04-10 18:05:44 +0800483}
484
485void mtk_sgmii_pcs_restart_an(struct phylink_pcs *pcs)
486{
487 struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
488 unsigned int val = 0;
489
490 if (!mpcs->regmap)
developerfd40db22021-04-29 10:08:25 +0800491 return;
492
developer4e8a3fd2023-04-10 18:05:44 +0800493 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
developerfd40db22021-04-29 10:08:25 +0800494 val |= SGMII_AN_RESTART;
developer4e8a3fd2023-04-10 18:05:44 +0800495 regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
496}
497
498static void mtk_sgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
499 phy_interface_t interface,
500 int speed, int duplex)
501{
502 struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
developer38afb1a2023-04-17 09:57:27 +0800503 unsigned int sgm_mode, val;
developer4e8a3fd2023-04-10 18:05:44 +0800504
developer38afb1a2023-04-17 09:57:27 +0800505 /* If autoneg is enabled, the force speed and duplex
506 * are not useful, so don't go any further.
507 */
508 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
509 if (val & SGMII_AN_ENABLE)
developer4e8a3fd2023-04-10 18:05:44 +0800510 return;
511
developer38afb1a2023-04-17 09:57:27 +0800512 /* SGMII force speed and duplex setting */
513 if (speed == SPEED_10)
514 sgm_mode = SGMII_SPEED_10;
515 else if (speed == SPEED_100)
516 sgm_mode = SGMII_SPEED_100;
517 else
518 sgm_mode = SGMII_SPEED_1000;
519
developer4e8a3fd2023-04-10 18:05:44 +0800520 if (duplex != DUPLEX_FULL)
developer38afb1a2023-04-17 09:57:27 +0800521 sgm_mode |= SGMII_DUPLEX_HALF;
developer4e8a3fd2023-04-10 18:05:44 +0800522
developer38afb1a2023-04-17 09:57:27 +0800523 regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
524 SGMII_DUPLEX_HALF | SGMII_SPEED_MASK,
525 sgm_mode);
developer4e8a3fd2023-04-10 18:05:44 +0800526}
527
528static const struct phylink_pcs_ops mtk_sgmii_pcs_ops = {
529 .pcs_config = mtk_sgmii_pcs_config,
530 .pcs_get_state = mtk_sgmii_pcs_get_state,
531 .pcs_an_restart = mtk_sgmii_pcs_restart_an,
532 .pcs_link_up = mtk_sgmii_pcs_link_up,
533};
534
535int mtk_sgmii_init(struct mtk_eth *eth, struct device_node *r, u32 ana_rgc3)
536{
537 struct mtk_sgmii *ss = eth->sgmii;
538 struct device_node *np;
539 int ret, i;
540
541 for (i = 0; i < MTK_MAX_DEVS; i++) {
542 np = of_parse_phandle(r, "mediatek,sgmiisys", i);
543 if (!np)
544 break;
545
546 ss->pcs[i].id = i;
547 ss->pcs[i].eth = eth;
548 ss->pcs[i].ana_rgc3 = ana_rgc3;
549
550 ss->pcs[i].regmap = syscon_node_to_regmap(np);
551 if (IS_ERR(ss->pcs[i].regmap))
552 return PTR_ERR(ss->pcs[i].regmap);
553
554 ss->pcs[i].flags &= ~(MTK_SGMII_PN_SWAP);
555 if (of_property_read_bool(np, "pn_swap"))
556 ss->pcs[i].flags |= MTK_SGMII_PN_SWAP;
557
558 ss->pcs[i].pcs.ops = &mtk_sgmii_pcs_ops;
559 ss->pcs[i].pcs.poll = true;
560 ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
561
562 of_node_put(np);
563 }
564
565 if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
566 ret = mtk_sgmii_xfi_pextp_init(ss, r);
567 if (ret)
568 return ret;
569
570 ret = mtk_sgmii_xfi_pll_init(ss, r);
571 if (ret)
572 return ret;
573 }
574
575 return 0;
576}
577
578struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id)
579{
580 if (!ss->pcs[id].regmap)
581 return NULL;
582
583 return &ss->pcs[id].pcs;
developerfd40db22021-04-29 10:08:25 +0800584}