blob: 9aef092270166fde5bf6a749200ef190cdbfcf13 [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
developer38afb1a2023-04-17 09:57:27 +0800406 /* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and
407 * we assume that fixes it's speed at bitrate = line rate (in
408 * other words, 1000Mbps or 2500Mbps).
409 */
410 if (interface == PHY_INTERFACE_MODE_SGMII) {
411 bmcr = SGMII_AN_ENABLE;
412 sgm_mode = SGMII_IF_MODE_SGMII |
413 SGMII_REMOTE_FAULT_DIS |
414 SGMII_SPEED_DUPLEX_AN;
415 } else {
416 /* 1000base-X or HSGMII without autoneg */
417 speed = SGMII_SPEED_1000;
418 if (interface == PHY_INTERFACE_MODE_2500BASEX)
419 sgm_mode = SGMII_IF_MODE_SGMII;
420 }
developer2fbee452022-08-12 13:58:20 +0800421
developer38afb1a2023-04-17 09:57:27 +0800422 if (mpcs->interface != interface) {
423 link_timer = phylink_get_link_timer_ns(interface);
424 if (link_timer < 0)
425 return link_timer;
developer2b76a9d2022-09-20 14:59:45 +0800426
developercd762f82023-05-03 09:03:39 +0800427 if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
428 mtk_sgmii_xfi_pll_enable(eth->sgmii);
429 mtk_sgmii_reset(eth, mpcs->id);
430 }
431
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
developercd762f82023-05-03 09:03:39 +0800440 /* Configure the interface polarity */
441 if (MTK_HAS_FLAGS(mpcs->flags, MTK_SGMII_PN_SWAP))
442 regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
443 SGMII_PN_SWAP_MASK,
444 SGMII_PN_SWAP_TX_RX);
445
developer38afb1a2023-04-17 09:57:27 +0800446 if (interface == PHY_INTERFACE_MODE_2500BASEX)
447 rgc3 = RG_PHY_SPEED_3_125G;
448 else
449 rgc3 = 0;
developerfd40db22021-04-29 10:08:25 +0800450
developer38afb1a2023-04-17 09:57:27 +0800451 /* Configure the underlying interface speed */
452 regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
453 RG_PHY_SPEED_3_125G, rgc3);
developer3d014da2022-05-11 16:29:59 +0800454
developer38afb1a2023-04-17 09:57:27 +0800455 /* Setup the link timer */
456 regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
457 link_timer / 2 / 8);
developer089e8852022-09-28 14:43:46 +0800458
developer38afb1a2023-04-17 09:57:27 +0800459 mpcs->interface = interface;
460 mode_changed = true;
461 }
developerfd40db22021-04-29 10:08:25 +0800462
developer38afb1a2023-04-17 09:57:27 +0800463 /* Update the advertisement, noting whether it has changed */
464 regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE,
465 SGMII_ADVERTISE, advertise, &changed);
developerfd40db22021-04-29 10:08:25 +0800466
developer38afb1a2023-04-17 09:57:27 +0800467 /* Update the sgmsys mode register */
468 regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
469 SGMII_REMOTE_FAULT_DIS | SGMII_DUPLEX_HALF |
470 SGMII_SPEED_MASK | SGMII_SPEED_DUPLEX_AN |
471 SGMII_IF_MODE_SGMII, sgm_mode | speed);
developer4e8a3fd2023-04-10 18:05:44 +0800472
developer38afb1a2023-04-17 09:57:27 +0800473 /* Update the BMCR */
474 regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1,
475 SGMII_AN_ENABLE, bmcr);
developer4e8a3fd2023-04-10 18:05:44 +0800476
developer38afb1a2023-04-17 09:57:27 +0800477 /* Release PHYA power down state */
478 usleep_range(50, 100);
479 regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
developer4e8a3fd2023-04-10 18:05:44 +0800480
developercd762f82023-05-03 09:03:39 +0800481 if (mode_changed) {
482 if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
483 if (interface == PHY_INTERFACE_MODE_2500BASEX)
484 mtk_sgmii_setup_phya_gen2(mpcs);
485 else
486 mtk_sgmii_setup_phya_gen1(mpcs);
487 }
developer4e8a3fd2023-04-10 18:05:44 +0800488 }
developer4e8a3fd2023-04-10 18:05:44 +0800489
developer38afb1a2023-04-17 09:57:27 +0800490 return changed || mode_changed;
developer4e8a3fd2023-04-10 18:05:44 +0800491}
492
493void mtk_sgmii_pcs_restart_an(struct phylink_pcs *pcs)
494{
495 struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
496 unsigned int val = 0;
497
498 if (!mpcs->regmap)
developerfd40db22021-04-29 10:08:25 +0800499 return;
500
developer4e8a3fd2023-04-10 18:05:44 +0800501 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
developerfd40db22021-04-29 10:08:25 +0800502 val |= SGMII_AN_RESTART;
developer4e8a3fd2023-04-10 18:05:44 +0800503 regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
504}
505
506static void mtk_sgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
507 phy_interface_t interface,
508 int speed, int duplex)
509{
510 struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
developer38afb1a2023-04-17 09:57:27 +0800511 unsigned int sgm_mode, val;
developer4e8a3fd2023-04-10 18:05:44 +0800512
developer38afb1a2023-04-17 09:57:27 +0800513 /* If autoneg is enabled, the force speed and duplex
514 * are not useful, so don't go any further.
515 */
516 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
517 if (val & SGMII_AN_ENABLE)
developer4e8a3fd2023-04-10 18:05:44 +0800518 return;
519
developer38afb1a2023-04-17 09:57:27 +0800520 /* SGMII force speed and duplex setting */
521 if (speed == SPEED_10)
522 sgm_mode = SGMII_SPEED_10;
523 else if (speed == SPEED_100)
524 sgm_mode = SGMII_SPEED_100;
525 else
526 sgm_mode = SGMII_SPEED_1000;
527
developer4e8a3fd2023-04-10 18:05:44 +0800528 if (duplex != DUPLEX_FULL)
developer38afb1a2023-04-17 09:57:27 +0800529 sgm_mode |= SGMII_DUPLEX_HALF;
developer4e8a3fd2023-04-10 18:05:44 +0800530
developer38afb1a2023-04-17 09:57:27 +0800531 regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
532 SGMII_DUPLEX_HALF | SGMII_SPEED_MASK,
533 sgm_mode);
developer4e8a3fd2023-04-10 18:05:44 +0800534}
535
536static const struct phylink_pcs_ops mtk_sgmii_pcs_ops = {
537 .pcs_config = mtk_sgmii_pcs_config,
538 .pcs_get_state = mtk_sgmii_pcs_get_state,
539 .pcs_an_restart = mtk_sgmii_pcs_restart_an,
540 .pcs_link_up = mtk_sgmii_pcs_link_up,
541};
542
543int mtk_sgmii_init(struct mtk_eth *eth, struct device_node *r, u32 ana_rgc3)
544{
545 struct mtk_sgmii *ss = eth->sgmii;
546 struct device_node *np;
547 int ret, i;
548
549 for (i = 0; i < MTK_MAX_DEVS; i++) {
550 np = of_parse_phandle(r, "mediatek,sgmiisys", i);
551 if (!np)
552 break;
553
554 ss->pcs[i].id = i;
555 ss->pcs[i].eth = eth;
556 ss->pcs[i].ana_rgc3 = ana_rgc3;
557
558 ss->pcs[i].regmap = syscon_node_to_regmap(np);
559 if (IS_ERR(ss->pcs[i].regmap))
560 return PTR_ERR(ss->pcs[i].regmap);
561
562 ss->pcs[i].flags &= ~(MTK_SGMII_PN_SWAP);
563 if (of_property_read_bool(np, "pn_swap"))
564 ss->pcs[i].flags |= MTK_SGMII_PN_SWAP;
565
566 ss->pcs[i].pcs.ops = &mtk_sgmii_pcs_ops;
567 ss->pcs[i].pcs.poll = true;
568 ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
569
570 of_node_put(np);
571 }
572
573 if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
574 ret = mtk_sgmii_xfi_pextp_init(ss, r);
575 if (ret)
576 return ret;
577
578 ret = mtk_sgmii_xfi_pll_init(ss, r);
579 if (ret)
580 return ret;
581 }
582
583 return 0;
584}
585
586struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id)
587{
588 if (!ss->pcs[id].regmap)
589 return NULL;
590
591 return &ss->pcs[id].pcs;
developerfd40db22021-04-29 10:08:25 +0800592}