blob: c2acab27838d5f2b678dd332e0bc2f5a5706a882 [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
developer1251a932023-05-08 22:22:51 +0800147int mtk_sgmii_need_powerdown(struct mtk_sgmii_pcs *mpcs)
148{
149 u32 val;
150
151 /* need to power down sgmii if link down */
152 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
153 if (!(val & SGMII_LINK_STATYS))
154 return true;
155
156 return false;
157}
158
developer4e8a3fd2023-04-10 18:05:44 +0800159void mtk_sgmii_setup_phya_gen1(struct mtk_sgmii_pcs *mpcs)
developerfd40db22021-04-29 10:08:25 +0800160{
developer4e8a3fd2023-04-10 18:05:44 +0800161 if (!mpcs->regmap_pextp)
developer089e8852022-09-28 14:43:46 +0800162 return;
163
developer95169b62023-05-12 17:58:58 +0800164 /* Setup operation mode */
developer4e8a3fd2023-04-10 18:05:44 +0800165 regmap_update_bits(mpcs->regmap_pextp, 0x9024, GENMASK(31, 0),
166 0x00D9071C);
167 regmap_update_bits(mpcs->regmap_pextp, 0x2020, GENMASK(31, 0),
168 0xAA8585AA);
169 regmap_update_bits(mpcs->regmap_pextp, 0x2030, GENMASK(31, 0),
170 0x0C020207);
171 regmap_update_bits(mpcs->regmap_pextp, 0x2034, GENMASK(31, 0),
172 0x0E05050F);
173 regmap_update_bits(mpcs->regmap_pextp, 0x2040, GENMASK(31, 0),
174 0x00200032);
175 regmap_update_bits(mpcs->regmap_pextp, 0x50F0, GENMASK(31, 0),
176 0x00C014BA);
177 regmap_update_bits(mpcs->regmap_pextp, 0x50E0, GENMASK(31, 0),
178 0x3777C12B);
179 regmap_update_bits(mpcs->regmap_pextp, 0x506C, GENMASK(31, 0),
180 0x005F9CFF);
181 regmap_update_bits(mpcs->regmap_pextp, 0x5070, GENMASK(31, 0),
182 0x9D9DFAFA);
183 regmap_update_bits(mpcs->regmap_pextp, 0x5074, GENMASK(31, 0),
184 0x27273F3F);
185 regmap_update_bits(mpcs->regmap_pextp, 0x5078, GENMASK(31, 0),
186 0xA7883C68);
187 regmap_update_bits(mpcs->regmap_pextp, 0x507C, GENMASK(31, 0),
188 0x11661166);
189 regmap_update_bits(mpcs->regmap_pextp, 0x5080, GENMASK(31, 0),
190 0x0E000EAF);
191 regmap_update_bits(mpcs->regmap_pextp, 0x5084, GENMASK(31, 0),
192 0x08080E0D);
193 regmap_update_bits(mpcs->regmap_pextp, 0x5088, GENMASK(31, 0),
194 0x02030B09);
195 regmap_update_bits(mpcs->regmap_pextp, 0x50E4, GENMASK(31, 0),
196 0x0C0C0000);
197 regmap_update_bits(mpcs->regmap_pextp, 0x50E8, GENMASK(31, 0),
198 0x04040000);
199 regmap_update_bits(mpcs->regmap_pextp, 0x50EC, GENMASK(31, 0),
200 0x0F0F0606);
201 regmap_update_bits(mpcs->regmap_pextp, 0x50A8, GENMASK(31, 0),
202 0x506E8C8C);
203 regmap_update_bits(mpcs->regmap_pextp, 0x6004, GENMASK(31, 0),
204 0x18190000);
205 regmap_update_bits(mpcs->regmap_pextp, 0x00F8, GENMASK(31, 0),
206 0x00FA32FA);
developer95169b62023-05-12 17:58:58 +0800207 /* Force SGDT_OUT off and select PCS */
developer4e8a3fd2023-04-10 18:05:44 +0800208 regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
209 0x80201F21);
developer95169b62023-05-12 17:58:58 +0800210 /* Force GLB_CKDET_OUT */
developer4e8a3fd2023-04-10 18:05:44 +0800211 regmap_update_bits(mpcs->regmap_pextp, 0x0030, GENMASK(31, 0),
212 0x00050C00);
developer95169b62023-05-12 17:58:58 +0800213 /* Force AEQ on */
developer4e8a3fd2023-04-10 18:05:44 +0800214 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
215 0x02002800);
developer089e8852022-09-28 14:43:46 +0800216 ndelay(1020);
developer95169b62023-05-12 17:58:58 +0800217 /* Setup DA default value */
developer4e8a3fd2023-04-10 18:05:44 +0800218 regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
219 0x00000020);
220 regmap_update_bits(mpcs->regmap_pextp, 0x3028, GENMASK(31, 0),
221 0x00008A01);
222 regmap_update_bits(mpcs->regmap_pextp, 0x302C, GENMASK(31, 0),
223 0x0000A884);
224 regmap_update_bits(mpcs->regmap_pextp, 0x3024, GENMASK(31, 0),
225 0x00083002);
226 regmap_update_bits(mpcs->regmap_pextp, 0x3010, GENMASK(31, 0),
227 0x00011110);
228 regmap_update_bits(mpcs->regmap_pextp, 0x3048, GENMASK(31, 0),
229 0x40704000);
230 regmap_update_bits(mpcs->regmap_pextp, 0x3064, GENMASK(31, 0),
231 0x0000C000);
232 regmap_update_bits(mpcs->regmap_pextp, 0x3050, GENMASK(31, 0),
233 0xA8000000);
234 regmap_update_bits(mpcs->regmap_pextp, 0x3054, GENMASK(31, 0),
235 0x000000AA);
236 regmap_update_bits(mpcs->regmap_pextp, 0x306C, GENMASK(31, 0),
237 0x20200F00);
238 regmap_update_bits(mpcs->regmap_pextp, 0xA060, GENMASK(31, 0),
239 0x00050000);
240 regmap_update_bits(mpcs->regmap_pextp, 0x90D0, GENMASK(31, 0),
241 0x00000007);
developer95169b62023-05-12 17:58:58 +0800242 /* Release reset */
developer4e8a3fd2023-04-10 18:05:44 +0800243 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
244 0x0200E800);
developer089e8852022-09-28 14:43:46 +0800245 udelay(150);
developer95169b62023-05-12 17:58:58 +0800246 /* Switch to P0 */
developer4e8a3fd2023-04-10 18:05:44 +0800247 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
248 0x0200C111);
developer089e8852022-09-28 14:43:46 +0800249 ndelay(1020);
developer4e8a3fd2023-04-10 18:05:44 +0800250 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
251 0x0200C101);
developer089e8852022-09-28 14:43:46 +0800252 udelay(15);
developer95169b62023-05-12 17:58:58 +0800253 /* Switch to Gen2 */
developer4e8a3fd2023-04-10 18:05:44 +0800254 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
255 0x0201C111);
developer089e8852022-09-28 14:43:46 +0800256 ndelay(1020);
developer4e8a3fd2023-04-10 18:05:44 +0800257 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
258 0x0201C101);
developer089e8852022-09-28 14:43:46 +0800259 udelay(100);
developer4e8a3fd2023-04-10 18:05:44 +0800260 regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
261 0x00000030);
262 regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
263 0x80201F01);
264 regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
265 0x30000000);
developer089e8852022-09-28 14:43:46 +0800266 udelay(400);
267}
268
developer4e8a3fd2023-04-10 18:05:44 +0800269void mtk_sgmii_setup_phya_gen2(struct mtk_sgmii_pcs *mpcs)
developer089e8852022-09-28 14:43:46 +0800270{
developer4e8a3fd2023-04-10 18:05:44 +0800271 if (!mpcs->regmap_pextp)
developer089e8852022-09-28 14:43:46 +0800272 return;
273
developer95169b62023-05-12 17:58:58 +0800274 /* Setup operation mode */
developer4e8a3fd2023-04-10 18:05:44 +0800275 regmap_update_bits(mpcs->regmap_pextp, 0x9024, GENMASK(31, 0),
276 0x00D9071C);
277 regmap_update_bits(mpcs->regmap_pextp, 0x2020, GENMASK(31, 0),
278 0xAA8585AA);
279 regmap_update_bits(mpcs->regmap_pextp, 0x2030, GENMASK(31, 0),
280 0x0C020707);
281 regmap_update_bits(mpcs->regmap_pextp, 0x2034, GENMASK(31, 0),
282 0x0E050F0F);
283 regmap_update_bits(mpcs->regmap_pextp, 0x2040, GENMASK(31, 0),
284 0x00140032);
285 regmap_update_bits(mpcs->regmap_pextp, 0x50F0, GENMASK(31, 0),
286 0x00C014AA);
287 regmap_update_bits(mpcs->regmap_pextp, 0x50E0, GENMASK(31, 0),
288 0x3777C12B);
289 regmap_update_bits(mpcs->regmap_pextp, 0x506C, GENMASK(31, 0),
290 0x005F9CFF);
291 regmap_update_bits(mpcs->regmap_pextp, 0x5070, GENMASK(31, 0),
292 0x9D9DFAFA);
293 regmap_update_bits(mpcs->regmap_pextp, 0x5074, GENMASK(31, 0),
294 0x27273F3F);
295 regmap_update_bits(mpcs->regmap_pextp, 0x5078, GENMASK(31, 0),
296 0xA7883C68);
297 regmap_update_bits(mpcs->regmap_pextp, 0x507C, GENMASK(31, 0),
298 0x11661166);
299 regmap_update_bits(mpcs->regmap_pextp, 0x5080, GENMASK(31, 0),
300 0x0E000AAF);
301 regmap_update_bits(mpcs->regmap_pextp, 0x5084, GENMASK(31, 0),
302 0x08080D0D);
303 regmap_update_bits(mpcs->regmap_pextp, 0x5088, GENMASK(31, 0),
304 0x02030909);
305 regmap_update_bits(mpcs->regmap_pextp, 0x50E4, GENMASK(31, 0),
306 0x0C0C0000);
307 regmap_update_bits(mpcs->regmap_pextp, 0x50E8, GENMASK(31, 0),
308 0x04040000);
309 regmap_update_bits(mpcs->regmap_pextp, 0x50EC, GENMASK(31, 0),
310 0x0F0F0C06);
311 regmap_update_bits(mpcs->regmap_pextp, 0x50A8, GENMASK(31, 0),
312 0x506E8C8C);
313 regmap_update_bits(mpcs->regmap_pextp, 0x6004, GENMASK(31, 0),
314 0x18190000);
315 regmap_update_bits(mpcs->regmap_pextp, 0x00F8, GENMASK(31, 0),
316 0x009C329C);
developer95169b62023-05-12 17:58:58 +0800317 /* Force SGDT_OUT off and select PCS */
developer4e8a3fd2023-04-10 18:05:44 +0800318 regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
319 0x80201F21);
developer95169b62023-05-12 17:58:58 +0800320 /* Force GLB_CKDET_OUT */
developer4e8a3fd2023-04-10 18:05:44 +0800321 regmap_update_bits(mpcs->regmap_pextp, 0x0030, GENMASK(31, 0),
322 0x00050C00);
developer95169b62023-05-12 17:58:58 +0800323 /* Force AEQ on */
developer4e8a3fd2023-04-10 18:05:44 +0800324 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
325 0x02002800);
developer089e8852022-09-28 14:43:46 +0800326 ndelay(1020);
developer95169b62023-05-12 17:58:58 +0800327 /* Setup DA default value */
developer4e8a3fd2023-04-10 18:05:44 +0800328 regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
329 0x00000020);
330 regmap_update_bits(mpcs->regmap_pextp, 0x3028, GENMASK(31, 0),
331 0x00008A01);
332 regmap_update_bits(mpcs->regmap_pextp, 0x302C, GENMASK(31, 0),
333 0x0000A884);
334 regmap_update_bits(mpcs->regmap_pextp, 0x3024, GENMASK(31, 0),
335 0x00083002);
336 regmap_update_bits(mpcs->regmap_pextp, 0x3010, GENMASK(31, 0),
337 0x00011110);
338 regmap_update_bits(mpcs->regmap_pextp, 0x3048, GENMASK(31, 0),
339 0x40704000);
340 regmap_update_bits(mpcs->regmap_pextp, 0x3050, GENMASK(31, 0),
341 0xA8000000);
342 regmap_update_bits(mpcs->regmap_pextp, 0x3054, GENMASK(31, 0),
343 0x000000AA);
344 regmap_update_bits(mpcs->regmap_pextp, 0x306C, GENMASK(31, 0),
345 0x22000F00);
346 regmap_update_bits(mpcs->regmap_pextp, 0xA060, GENMASK(31, 0),
347 0x00050000);
348 regmap_update_bits(mpcs->regmap_pextp, 0x90D0, GENMASK(31, 0),
349 0x00000005);
developer95169b62023-05-12 17:58:58 +0800350 /* Release reset */
developer4e8a3fd2023-04-10 18:05:44 +0800351 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
352 0x0200E800);
developer089e8852022-09-28 14:43:46 +0800353 udelay(150);
developer95169b62023-05-12 17:58:58 +0800354 /* Switch to P0 */
developer4e8a3fd2023-04-10 18:05:44 +0800355 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
356 0x0200C111);
developer089e8852022-09-28 14:43:46 +0800357 ndelay(1020);
developer4e8a3fd2023-04-10 18:05:44 +0800358 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
359 0x0200C101);
developer089e8852022-09-28 14:43:46 +0800360 udelay(15);
developer95169b62023-05-12 17:58:58 +0800361 /* Switch to Gen2 */
developer4e8a3fd2023-04-10 18:05:44 +0800362 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
363 0x0201C111);
developer089e8852022-09-28 14:43:46 +0800364 ndelay(1020);
developer4e8a3fd2023-04-10 18:05:44 +0800365 regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
366 0x0201C101);
developer089e8852022-09-28 14:43:46 +0800367 udelay(100);
developer4e8a3fd2023-04-10 18:05:44 +0800368 regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
369 0x00000030);
370 regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
371 0x80201F01);
372 regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
373 0x30000000);
developer089e8852022-09-28 14:43:46 +0800374 udelay(400);
375}
376
developer38afb1a2023-04-17 09:57:27 +0800377static void mtk_sgmii_pcs_get_state(struct phylink_pcs *pcs,
378 struct phylink_link_state *state)
developer089e8852022-09-28 14:43:46 +0800379{
developer38afb1a2023-04-17 09:57:27 +0800380 struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
381 unsigned int bm, adv, rgc3, sgm_mode;
developerfd40db22021-04-29 10:08:25 +0800382
developer38afb1a2023-04-17 09:57:27 +0800383 state->interface = mpcs->interface;
developer2fbee452022-08-12 13:58:20 +0800384
developer38afb1a2023-04-17 09:57:27 +0800385 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm);
386 if (bm & SGMII_AN_ENABLE) {
387 regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv);
developerfd40db22021-04-29 10:08:25 +0800388
developer38afb1a2023-04-17 09:57:27 +0800389 phylink_mii_c22_pcs_decode_state(state,
390 FIELD_GET(SGMII_BMSR, bm),
391 FIELD_GET(SGMII_LPA, adv));
392 } else {
393 state->link = !!(bm & SGMII_LINK_STATYS);
developerf8ac94a2021-07-29 16:40:01 +0800394
developer38afb1a2023-04-17 09:57:27 +0800395 regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &sgm_mode);
developer089e8852022-09-28 14:43:46 +0800396
developer38afb1a2023-04-17 09:57:27 +0800397 switch (sgm_mode & SGMII_SPEED_MASK) {
398 case SGMII_SPEED_10:
399 state->speed = SPEED_10;
400 break;
401 case SGMII_SPEED_100:
402 state->speed = SPEED_100;
403 break;
404 case SGMII_SPEED_1000:
405 regmap_read(mpcs->regmap, mpcs->ana_rgc3, &rgc3);
406 rgc3 = FIELD_GET(RG_PHY_SPEED_3_125G, rgc3);
407 state->speed = rgc3 ? SPEED_2500 : SPEED_1000;
408 break;
409 }
developerfd40db22021-04-29 10:08:25 +0800410
developer38afb1a2023-04-17 09:57:27 +0800411 if (sgm_mode & SGMII_DUPLEX_HALF)
412 state->duplex = DUPLEX_HALF;
413 else
414 state->duplex = DUPLEX_FULL;
415 }
developerfd40db22021-04-29 10:08:25 +0800416}
417
developer38afb1a2023-04-17 09:57:27 +0800418static int mtk_sgmii_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
419 phy_interface_t interface,
420 const unsigned long *advertising,
421 bool permit_pause_to_mac)
developerfd40db22021-04-29 10:08:25 +0800422{
developer38afb1a2023-04-17 09:57:27 +0800423 struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
developer4e8a3fd2023-04-10 18:05:44 +0800424 struct mtk_eth *eth = mpcs->eth;
developer38afb1a2023-04-17 09:57:27 +0800425 unsigned int rgc3, sgm_mode = 0, bmcr = 0, speed = 0;
426 bool mode_changed = false, changed;
427 int advertise, link_timer;
developerfd40db22021-04-29 10:08:25 +0800428
developer38afb1a2023-04-17 09:57:27 +0800429 advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
430 advertising);
431 if (advertise < 0)
432 return advertise;
developerfd40db22021-04-29 10:08:25 +0800433
developer38afb1a2023-04-17 09:57:27 +0800434 /* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and
435 * we assume that fixes it's speed at bitrate = line rate (in
436 * other words, 1000Mbps or 2500Mbps).
437 */
438 if (interface == PHY_INTERFACE_MODE_SGMII) {
439 bmcr = SGMII_AN_ENABLE;
440 sgm_mode = SGMII_IF_MODE_SGMII |
441 SGMII_REMOTE_FAULT_DIS |
442 SGMII_SPEED_DUPLEX_AN;
developer804cd302023-05-11 19:02:14 +0800443 } else if (phylink_autoneg_inband(mode)) {
444 /* 1000base-X or HSGMII with autoneg */
445 if (interface == PHY_INTERFACE_MODE_2500BASEX)
446 return -EINVAL;
447
448 bmcr = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
449 advertising) ? SGMII_AN_ENABLE : 0;
450 if (bmcr)
451 sgm_mode = SGMII_SPEED_DUPLEX_AN;
452 else
453 speed = SGMII_SPEED_1000;
developer38afb1a2023-04-17 09:57:27 +0800454 } else {
455 /* 1000base-X or HSGMII without autoneg */
456 speed = SGMII_SPEED_1000;
457 if (interface == PHY_INTERFACE_MODE_2500BASEX)
458 sgm_mode = SGMII_IF_MODE_SGMII;
459 }
developer2fbee452022-08-12 13:58:20 +0800460
developer1251a932023-05-08 22:22:51 +0800461 if (mpcs->interface != interface ||
462 mtk_sgmii_need_powerdown(mpcs)) {
developer38afb1a2023-04-17 09:57:27 +0800463 link_timer = phylink_get_link_timer_ns(interface);
464 if (link_timer < 0)
465 return link_timer;
developer2b76a9d2022-09-20 14:59:45 +0800466
developercd762f82023-05-03 09:03:39 +0800467 if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
468 mtk_sgmii_xfi_pll_enable(eth->sgmii);
469 mtk_sgmii_reset(eth, mpcs->id);
470 }
471
developer38afb1a2023-04-17 09:57:27 +0800472 /* PHYA power down */
473 regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
474 SGMII_PHYA_PWD, SGMII_PHYA_PWD);
developerfd40db22021-04-29 10:08:25 +0800475
developer38afb1a2023-04-17 09:57:27 +0800476 /* Reset SGMII PCS state */
477 regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0,
478 SGMII_SW_RESET, SGMII_SW_RESET);
developerfd40db22021-04-29 10:08:25 +0800479
developercd762f82023-05-03 09:03:39 +0800480 /* Configure the interface polarity */
481 if (MTK_HAS_FLAGS(mpcs->flags, MTK_SGMII_PN_SWAP))
482 regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
483 SGMII_PN_SWAP_MASK,
484 SGMII_PN_SWAP_TX_RX);
485
developer38afb1a2023-04-17 09:57:27 +0800486 if (interface == PHY_INTERFACE_MODE_2500BASEX)
487 rgc3 = RG_PHY_SPEED_3_125G;
488 else
489 rgc3 = 0;
developerfd40db22021-04-29 10:08:25 +0800490
developer38afb1a2023-04-17 09:57:27 +0800491 /* Configure the underlying interface speed */
492 regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
493 RG_PHY_SPEED_3_125G, rgc3);
developer3d014da2022-05-11 16:29:59 +0800494
developer38afb1a2023-04-17 09:57:27 +0800495 /* Setup the link timer */
496 regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
497 link_timer / 2 / 8);
developer089e8852022-09-28 14:43:46 +0800498
developer38afb1a2023-04-17 09:57:27 +0800499 mpcs->interface = interface;
500 mode_changed = true;
501 }
developerfd40db22021-04-29 10:08:25 +0800502
developer38afb1a2023-04-17 09:57:27 +0800503 /* Update the advertisement, noting whether it has changed */
504 regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE,
505 SGMII_ADVERTISE, advertise, &changed);
developerfd40db22021-04-29 10:08:25 +0800506
developer38afb1a2023-04-17 09:57:27 +0800507 /* Update the sgmsys mode register */
508 regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
509 SGMII_REMOTE_FAULT_DIS | SGMII_DUPLEX_HALF |
510 SGMII_SPEED_MASK | SGMII_SPEED_DUPLEX_AN |
511 SGMII_IF_MODE_SGMII, sgm_mode | speed);
developer4e8a3fd2023-04-10 18:05:44 +0800512
developer38afb1a2023-04-17 09:57:27 +0800513 /* Update the BMCR */
514 regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1,
515 SGMII_AN_ENABLE, bmcr);
developer4e8a3fd2023-04-10 18:05:44 +0800516
developer38afb1a2023-04-17 09:57:27 +0800517 /* Release PHYA power down state */
518 usleep_range(50, 100);
519 regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
developer4e8a3fd2023-04-10 18:05:44 +0800520
developercd762f82023-05-03 09:03:39 +0800521 if (mode_changed) {
522 if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
523 if (interface == PHY_INTERFACE_MODE_2500BASEX)
524 mtk_sgmii_setup_phya_gen2(mpcs);
525 else
526 mtk_sgmii_setup_phya_gen1(mpcs);
527 }
developer4e8a3fd2023-04-10 18:05:44 +0800528 }
developer4e8a3fd2023-04-10 18:05:44 +0800529
developer38afb1a2023-04-17 09:57:27 +0800530 return changed || mode_changed;
developer4e8a3fd2023-04-10 18:05:44 +0800531}
532
533void mtk_sgmii_pcs_restart_an(struct phylink_pcs *pcs)
534{
535 struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
536 unsigned int val = 0;
537
538 if (!mpcs->regmap)
developerfd40db22021-04-29 10:08:25 +0800539 return;
540
developer4e8a3fd2023-04-10 18:05:44 +0800541 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
developerfd40db22021-04-29 10:08:25 +0800542 val |= SGMII_AN_RESTART;
developer4e8a3fd2023-04-10 18:05:44 +0800543 regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
544}
545
546static void mtk_sgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
547 phy_interface_t interface,
548 int speed, int duplex)
549{
550 struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
developer38afb1a2023-04-17 09:57:27 +0800551 unsigned int sgm_mode, val;
developer4e8a3fd2023-04-10 18:05:44 +0800552
developer38afb1a2023-04-17 09:57:27 +0800553 /* If autoneg is enabled, the force speed and duplex
554 * are not useful, so don't go any further.
555 */
556 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
557 if (val & SGMII_AN_ENABLE)
developer4e8a3fd2023-04-10 18:05:44 +0800558 return;
559
developer38afb1a2023-04-17 09:57:27 +0800560 /* SGMII force speed and duplex setting */
561 if (speed == SPEED_10)
562 sgm_mode = SGMII_SPEED_10;
563 else if (speed == SPEED_100)
564 sgm_mode = SGMII_SPEED_100;
565 else
566 sgm_mode = SGMII_SPEED_1000;
567
developer4e8a3fd2023-04-10 18:05:44 +0800568 if (duplex != DUPLEX_FULL)
developer38afb1a2023-04-17 09:57:27 +0800569 sgm_mode |= SGMII_DUPLEX_HALF;
developer4e8a3fd2023-04-10 18:05:44 +0800570
developer38afb1a2023-04-17 09:57:27 +0800571 regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
572 SGMII_DUPLEX_HALF | SGMII_SPEED_MASK,
573 sgm_mode);
developer4e8a3fd2023-04-10 18:05:44 +0800574}
575
576static const struct phylink_pcs_ops mtk_sgmii_pcs_ops = {
577 .pcs_config = mtk_sgmii_pcs_config,
578 .pcs_get_state = mtk_sgmii_pcs_get_state,
579 .pcs_an_restart = mtk_sgmii_pcs_restart_an,
580 .pcs_link_up = mtk_sgmii_pcs_link_up,
581};
582
583int mtk_sgmii_init(struct mtk_eth *eth, struct device_node *r, u32 ana_rgc3)
584{
585 struct mtk_sgmii *ss = eth->sgmii;
586 struct device_node *np;
587 int ret, i;
588
589 for (i = 0; i < MTK_MAX_DEVS; i++) {
590 np = of_parse_phandle(r, "mediatek,sgmiisys", i);
591 if (!np)
592 break;
593
594 ss->pcs[i].id = i;
595 ss->pcs[i].eth = eth;
596 ss->pcs[i].ana_rgc3 = ana_rgc3;
597
598 ss->pcs[i].regmap = syscon_node_to_regmap(np);
599 if (IS_ERR(ss->pcs[i].regmap))
600 return PTR_ERR(ss->pcs[i].regmap);
601
602 ss->pcs[i].flags &= ~(MTK_SGMII_PN_SWAP);
603 if (of_property_read_bool(np, "pn_swap"))
604 ss->pcs[i].flags |= MTK_SGMII_PN_SWAP;
605
606 ss->pcs[i].pcs.ops = &mtk_sgmii_pcs_ops;
607 ss->pcs[i].pcs.poll = true;
608 ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
609
610 of_node_put(np);
611 }
612
613 if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
614 ret = mtk_sgmii_xfi_pextp_init(ss, r);
615 if (ret)
616 return ret;
617
618 ret = mtk_sgmii_xfi_pll_init(ss, r);
619 if (ret)
620 return ret;
621 }
622
623 return 0;
624}
625
626struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id)
627{
628 if (!ss->pcs[id].regmap)
629 return NULL;
630
631 return &ss->pcs[id].pcs;
developerfd40db22021-04-29 10:08:25 +0800632}