1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018-2019 MediaTek Inc.
3
4 /* A library for configuring path from GMAC/GDM to target PHY
5 *
6 * Author: Sean Wang <sean.wang@mediatek.com>
7 *
8 */
9
10 #include <linux/phy.h>
11 #include <linux/regmap.h>
12
13 #include "mtk_eth_soc.h"
14
15 struct mtk_eth_muxc {
16 const char *name;
17 u64 cap_bit;
18 int (*set_path)(struct mtk_eth *eth, u64 path);
19 };
20
mtk_eth_path_name(u64 path)21 static const char *mtk_eth_path_name(u64 path)
22 {
23 switch (path) {
24 case MTK_ETH_PATH_GMAC1_RGMII:
25 return "gmac1_rgmii";
26 case MTK_ETH_PATH_GMAC1_TRGMII:
27 return "gmac1_trgmii";
28 case MTK_ETH_PATH_GMAC1_SGMII:
29 return "gmac1_sgmii";
30 case MTK_ETH_PATH_GMAC2_RGMII:
31 return "gmac2_rgmii";
32 case MTK_ETH_PATH_GMAC2_SGMII:
33 return "gmac2_sgmii";
34 case MTK_ETH_PATH_GMAC2_2P5GPHY:
35 return "gmac2_2p5gphy";
36 case MTK_ETH_PATH_GMAC2_GEPHY:
37 return "gmac2_gephy";
38 case MTK_ETH_PATH_GDM1_ESW:
39 return "gdm1_esw";
40 default:
41 return "unknown path";
42 }
43 }
44
set_mux_gdm1_to_gmac1_esw(struct mtk_eth * eth,u64 path)45 static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, u64 path)
46 {
47 bool updated = true;
48 u32 mask, set, reg;
49
50 switch (path) {
51 case MTK_ETH_PATH_GMAC1_SGMII:
52 mask = ~(u32)MTK_MUX_TO_ESW;
53 set = 0;
54 break;
55 case MTK_ETH_PATH_GDM1_ESW:
56 mask = ~(u32)MTK_MUX_TO_ESW;
57 set = MTK_MUX_TO_ESW;
58 break;
59 default:
60 updated = false;
61 break;
62 }
63
64 if (mtk_is_netsys_v3_or_greater(eth))
65 reg = MTK_MAC_MISC_V3;
66 else
67 reg = MTK_MAC_MISC;
68
69 if (updated)
70 mtk_m32(eth, mask, set, reg);
71
72 dev_dbg(eth->dev, "path %s in %s updated = %d\n",
73 mtk_eth_path_name(path), __func__, updated);
74
75 return 0;
76 }
77
set_mux_gmac2_gmac0_to_gephy(struct mtk_eth * eth,u64 path)78 static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, u64 path)
79 {
80 unsigned int val = 0;
81 bool updated = true;
82
83 switch (path) {
84 case MTK_ETH_PATH_GMAC2_GEPHY:
85 val = ~(u32)GEPHY_MAC_SEL;
86 break;
87 default:
88 updated = false;
89 break;
90 }
91
92 if (updated)
93 regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val);
94
95 dev_dbg(eth->dev, "path %s in %s updated = %d\n",
96 mtk_eth_path_name(path), __func__, updated);
97
98 return 0;
99 }
100
set_mux_u3_gmac2_to_qphy(struct mtk_eth * eth,u64 path)101 static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path)
102 {
103 unsigned int val = 0, mask = 0, reg = 0;
104 bool updated = true;
105
106 switch (path) {
107 case MTK_ETH_PATH_GMAC2_SGMII:
108 if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) {
109 reg = USB_PHY_SWITCH_REG;
110 val = SGMII_QPHY_SEL;
111 mask = QPHY_SEL_MASK;
112 } else {
113 reg = INFRA_MISC2;
114 val = CO_QPHY_SEL;
115 mask = val;
116 }
117 break;
118 default:
119 updated = false;
120 break;
121 }
122
123 if (updated)
124 regmap_update_bits(eth->infra, reg, mask, val);
125
126 dev_dbg(eth->dev, "path %s in %s updated = %d\n",
127 mtk_eth_path_name(path), __func__, updated);
128
129 return 0;
130 }
131
set_mux_gmac2_to_2p5gphy(struct mtk_eth * eth,u64 path)132 static int set_mux_gmac2_to_2p5gphy(struct mtk_eth *eth, u64 path)
133 {
134 int ret;
135
136 if (path == MTK_ETH_PATH_GMAC2_2P5GPHY) {
137 ret = regmap_clear_bits(eth->ethsys, ETHSYS_SYSCFG0,
138 SYSCFG0_SGMII_GMAC2_V2);
139 if (ret)
140 return ret;
141
142 /* Setup mux to 2p5g PHY */
143 ret = regmap_clear_bits(eth->infra, TOP_MISC_NETSYS_PCS_MUX,
144 MUX_G2_USXGMII_SEL);
145 if (ret)
146 return ret;
147
148 dev_dbg(eth->dev, "path %s in %s updated\n",
149 mtk_eth_path_name(path), __func__);
150 }
151
152 return 0;
153 }
154
set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth * eth,u64 path)155 static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path)
156 {
157 unsigned int val = 0;
158 bool updated = true;
159
160 switch (path) {
161 case MTK_ETH_PATH_GMAC1_SGMII:
162 val = SYSCFG0_SGMII_GMAC1;
163 break;
164 case MTK_ETH_PATH_GMAC2_SGMII:
165 val = SYSCFG0_SGMII_GMAC2;
166 break;
167 case MTK_ETH_PATH_GMAC1_RGMII:
168 case MTK_ETH_PATH_GMAC2_RGMII:
169 regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
170 val &= SYSCFG0_SGMII_MASK;
171
172 if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) ||
173 (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2))
174 val = 0;
175 else
176 updated = false;
177 break;
178 default:
179 updated = false;
180 break;
181 }
182
183 if (updated)
184 regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
185 SYSCFG0_SGMII_MASK, val);
186
187 dev_dbg(eth->dev, "path %s in %s updated = %d\n",
188 mtk_eth_path_name(path), __func__, updated);
189
190 return 0;
191 }
192
set_mux_gmac12_to_gephy_sgmii(struct mtk_eth * eth,u64 path)193 static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path)
194 {
195 unsigned int val = 0;
196 bool updated = true;
197
198 regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
199
200 switch (path) {
201 case MTK_ETH_PATH_GMAC1_SGMII:
202 val |= SYSCFG0_SGMII_GMAC1_V2;
203 break;
204 case MTK_ETH_PATH_GMAC2_GEPHY:
205 val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2;
206 break;
207 case MTK_ETH_PATH_GMAC2_SGMII:
208 val |= SYSCFG0_SGMII_GMAC2_V2;
209 break;
210 default:
211 updated = false;
212 }
213
214 if (updated)
215 regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
216 SYSCFG0_SGMII_MASK, val);
217
218 dev_dbg(eth->dev, "path %s in %s updated = %d\n",
219 mtk_eth_path_name(path), __func__, updated);
220
221 return 0;
222 }
223
224 static const struct mtk_eth_muxc mtk_eth_muxc[] = {
225 {
226 .name = "mux_gdm1_to_gmac1_esw",
227 .cap_bit = MTK_ETH_MUX_GDM1_TO_GMAC1_ESW,
228 .set_path = set_mux_gdm1_to_gmac1_esw,
229 }, {
230 .name = "mux_gmac2_gmac0_to_gephy",
231 .cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY,
232 .set_path = set_mux_gmac2_gmac0_to_gephy,
233 }, {
234 .name = "mux_u3_gmac2_to_qphy",
235 .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY,
236 .set_path = set_mux_u3_gmac2_to_qphy,
237 }, {
238 .name = "mux_gmac2_to_2p5gphy",
239 .cap_bit = MTK_ETH_MUX_GMAC2_TO_2P5GPHY,
240 .set_path = set_mux_gmac2_to_2p5gphy,
241 }, {
242 .name = "mux_gmac1_gmac2_to_sgmii_rgmii",
243 .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII,
244 .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii,
245 }, {
246 .name = "mux_gmac12_to_gephy_sgmii",
247 .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII,
248 .set_path = set_mux_gmac12_to_gephy_sgmii,
249 },
250 };
251
mtk_eth_mux_setup(struct mtk_eth * eth,u64 path)252 static int mtk_eth_mux_setup(struct mtk_eth *eth, u64 path)
253 {
254 int i, err = 0;
255
256 if (!MTK_HAS_CAPS(eth->soc->caps, path)) {
257 dev_err(eth->dev, "path %s isn't support on the SoC\n",
258 mtk_eth_path_name(path));
259 return -EINVAL;
260 }
261
262 if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX))
263 return 0;
264
265 /* Setup MUX in path fabric */
266 for (i = 0; i < ARRAY_SIZE(mtk_eth_muxc); i++) {
267 if (MTK_HAS_CAPS(eth->soc->caps, mtk_eth_muxc[i].cap_bit)) {
268 err = mtk_eth_muxc[i].set_path(eth, path);
269 if (err)
270 goto out;
271 } else {
272 dev_dbg(eth->dev, "mux %s isn't present on the SoC\n",
273 mtk_eth_muxc[i].name);
274 }
275 }
276
277 out:
278 return err;
279 }
280
mtk_gmac_sgmii_path_setup(struct mtk_eth * eth,int mac_id)281 int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
282 {
283 u64 path;
284
285 path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII :
286 MTK_ETH_PATH_GMAC2_SGMII;
287
288 /* Setup proper MUXes along the path */
289 return mtk_eth_mux_setup(eth, path);
290 }
291
mtk_gmac_2p5gphy_path_setup(struct mtk_eth * eth,int mac_id)292 int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id)
293 {
294 u64 path = 0;
295
296 if (mac_id == MTK_GMAC2_ID)
297 path = MTK_ETH_PATH_GMAC2_2P5GPHY;
298
299 if (!path)
300 return -EINVAL;
301
302 /* Setup proper MUXes along the path */
303 return mtk_eth_mux_setup(eth, path);
304 }
305
mtk_gmac_gephy_path_setup(struct mtk_eth * eth,int mac_id)306 int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
307 {
308 u64 path = 0;
309
310 if (mac_id == 1)
311 path = MTK_ETH_PATH_GMAC2_GEPHY;
312
313 if (!path)
314 return -EINVAL;
315
316 /* Setup proper MUXes along the path */
317 return mtk_eth_mux_setup(eth, path);
318 }
319
mtk_gmac_rgmii_path_setup(struct mtk_eth * eth,int mac_id)320 int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)
321 {
322 u64 path;
323
324 path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII :
325 MTK_ETH_PATH_GMAC2_RGMII;
326
327 /* Setup proper MUXes along the path */
328 return mtk_eth_mux_setup(eth, path);
329 }
330
331