xref: /linux/drivers/net/ethernet/mediatek/mtk_eth_path.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
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