xref: /linux/drivers/net/ethernet/mediatek/mtk_eth_path.c (revision a6cdeeb16bff89c8486324f53577db058cbe81ba)
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 	int (*set_path)(struct mtk_eth *eth, int path);
17 };
18 
19 static const char * const mtk_eth_mux_name[] = {
20 	"mux_gdm1_to_gmac1_esw", "mux_gmac2_gmac0_to_gephy",
21 	"mux_u3_gmac2_to_qphy", "mux_gmac1_gmac2_to_sgmii_rgmii",
22 	"mux_gmac12_to_gephy_sgmii",
23 };
24 
25 static const char * const mtk_eth_path_name[] = {
26 	"gmac1_rgmii", "gmac1_trgmii", "gmac1_sgmii", "gmac2_rgmii",
27 	"gmac2_sgmii", "gmac2_gephy", "gdm1_esw",
28 };
29 
30 static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, int path)
31 {
32 	bool updated = true;
33 	u32 val, mask, set;
34 
35 	switch (path) {
36 	case MTK_ETH_PATH_GMAC1_SGMII:
37 		mask = ~(u32)MTK_MUX_TO_ESW;
38 		set = 0;
39 		break;
40 	case MTK_ETH_PATH_GDM1_ESW:
41 		mask = ~(u32)MTK_MUX_TO_ESW;
42 		set = MTK_MUX_TO_ESW;
43 		break;
44 	default:
45 		updated = false;
46 		break;
47 	};
48 
49 	if (updated) {
50 		val = mtk_r32(eth, MTK_MAC_MISC);
51 		val = (val & mask) | set;
52 		mtk_w32(eth, val, MTK_MAC_MISC);
53 	}
54 
55 	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
56 		mtk_eth_path_name[path], __func__, updated);
57 
58 	return 0;
59 }
60 
61 static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path)
62 {
63 	unsigned int val = 0;
64 	bool updated = true;
65 
66 	switch (path) {
67 	case MTK_ETH_PATH_GMAC2_GEPHY:
68 		val = ~(u32)GEPHY_MAC_SEL;
69 		break;
70 	default:
71 		updated = false;
72 		break;
73 	}
74 
75 	if (updated)
76 		regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val);
77 
78 	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
79 		mtk_eth_path_name[path], __func__, updated);
80 
81 	return 0;
82 }
83 
84 static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path)
85 {
86 	unsigned int val = 0;
87 	bool updated = true;
88 
89 	switch (path) {
90 	case MTK_ETH_PATH_GMAC2_SGMII:
91 		val = CO_QPHY_SEL;
92 		break;
93 	default:
94 		updated = false;
95 		break;
96 	}
97 
98 	if (updated)
99 		regmap_update_bits(eth->infra, INFRA_MISC2, CO_QPHY_SEL, val);
100 
101 	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
102 		mtk_eth_path_name[path], __func__, updated);
103 
104 	return 0;
105 }
106 
107 static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, int path)
108 {
109 	unsigned int val = 0;
110 	bool updated = true;
111 
112 	switch (path) {
113 	case MTK_ETH_PATH_GMAC1_SGMII:
114 		val = SYSCFG0_SGMII_GMAC1;
115 		break;
116 	case MTK_ETH_PATH_GMAC2_SGMII:
117 		val = SYSCFG0_SGMII_GMAC2;
118 		break;
119 	case MTK_ETH_PATH_GMAC1_RGMII:
120 	case MTK_ETH_PATH_GMAC2_RGMII:
121 		regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
122 		val &= SYSCFG0_SGMII_MASK;
123 
124 		if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) ||
125 		    (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2))
126 			val = 0;
127 		else
128 			updated = false;
129 		break;
130 	default:
131 		updated = false;
132 		break;
133 	};
134 
135 	if (updated)
136 		regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
137 				   SYSCFG0_SGMII_MASK, val);
138 
139 	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
140 		mtk_eth_path_name[path], __func__, updated);
141 
142 	return 0;
143 }
144 
145 static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, int path)
146 {
147 	unsigned int val = 0;
148 	bool updated = true;
149 
150 	regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
151 
152 	switch (path) {
153 	case MTK_ETH_PATH_GMAC1_SGMII:
154 		val |= SYSCFG0_SGMII_GMAC1_V2;
155 		break;
156 	case MTK_ETH_PATH_GMAC2_GEPHY:
157 		val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2;
158 		break;
159 	case MTK_ETH_PATH_GMAC2_SGMII:
160 		val |= SYSCFG0_SGMII_GMAC2_V2;
161 		break;
162 	default:
163 		updated = false;
164 	};
165 
166 	if (updated)
167 		regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
168 				   SYSCFG0_SGMII_MASK, val);
169 
170 	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
171 		mtk_eth_path_name[path], __func__, updated);
172 
173 	return 0;
174 }
175 
176 static const struct mtk_eth_muxc mtk_eth_muxc[] = {
177 	{ .set_path = set_mux_gdm1_to_gmac1_esw, },
178 	{ .set_path = set_mux_gmac2_gmac0_to_gephy, },
179 	{ .set_path = set_mux_u3_gmac2_to_qphy, },
180 	{ .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii, },
181 	{ .set_path = set_mux_gmac12_to_gephy_sgmii, }
182 };
183 
184 static int mtk_eth_mux_setup(struct mtk_eth *eth, int path)
185 {
186 	int i, err = 0;
187 
188 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_PATH_BIT(path))) {
189 		dev_err(eth->dev, "path %s isn't support on the SoC\n",
190 			mtk_eth_path_name[path]);
191 		return -EINVAL;
192 	}
193 
194 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX))
195 		return 0;
196 
197 	/* Setup MUX in path fabric */
198 	for (i = 0; i < MTK_ETH_MUX_MAX; i++) {
199 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_MUX_BIT(i))) {
200 			err = mtk_eth_muxc[i].set_path(eth, path);
201 			if (err)
202 				goto out;
203 		} else {
204 			dev_dbg(eth->dev, "mux %s isn't present on the SoC\n",
205 				mtk_eth_mux_name[i]);
206 		}
207 	}
208 
209 out:
210 	return err;
211 }
212 
213 static int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
214 {
215 	unsigned int val = 0;
216 	int sid, err, path;
217 
218 	path = (mac_id == 0) ?  MTK_ETH_PATH_GMAC1_SGMII :
219 				MTK_ETH_PATH_GMAC2_SGMII;
220 
221 	/* Setup proper MUXes along the path */
222 	err = mtk_eth_mux_setup(eth, path);
223 	if (err)
224 		return err;
225 
226 	/* The path GMAC to SGMII will be enabled once the SGMIISYS is being
227 	 * setup done.
228 	 */
229 	regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
230 
231 	regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
232 			   SYSCFG0_SGMII_MASK, ~(u32)SYSCFG0_SGMII_MASK);
233 
234 	/* Decide how GMAC and SGMIISYS be mapped */
235 	sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? 0 : mac_id;
236 
237 	/* Setup SGMIISYS with the determined property */
238 	if (MTK_HAS_FLAGS(eth->sgmii->flags[sid], MTK_SGMII_PHYSPEED_AN))
239 		err = mtk_sgmii_setup_mode_an(eth->sgmii, sid);
240 	else
241 		err = mtk_sgmii_setup_mode_force(eth->sgmii, sid);
242 
243 	if (err)
244 		return err;
245 
246 	regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
247 			   SYSCFG0_SGMII_MASK, val);
248 
249 	return 0;
250 }
251 
252 static int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
253 {
254 	int err, path = 0;
255 
256 	if (mac_id == 1)
257 		path = MTK_ETH_PATH_GMAC2_GEPHY;
258 
259 	if (!path)
260 		return -EINVAL;
261 
262 	/* Setup proper MUXes along the path */
263 	err = mtk_eth_mux_setup(eth, path);
264 	if (err)
265 		return err;
266 
267 	return 0;
268 }
269 
270 static int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)
271 {
272 	int err, path;
273 
274 	path = (mac_id == 0) ?  MTK_ETH_PATH_GMAC1_RGMII :
275 				MTK_ETH_PATH_GMAC2_RGMII;
276 
277 	/* Setup proper MUXes along the path */
278 	err = mtk_eth_mux_setup(eth, path);
279 	if (err)
280 		return err;
281 
282 	return 0;
283 }
284 
285 int mtk_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode)
286 {
287 	int err;
288 
289 	switch (phymode) {
290 	case PHY_INTERFACE_MODE_TRGMII:
291 	case PHY_INTERFACE_MODE_RGMII_TXID:
292 	case PHY_INTERFACE_MODE_RGMII_RXID:
293 	case PHY_INTERFACE_MODE_RGMII_ID:
294 	case PHY_INTERFACE_MODE_RGMII:
295 	case PHY_INTERFACE_MODE_MII:
296 	case PHY_INTERFACE_MODE_REVMII:
297 	case PHY_INTERFACE_MODE_RMII:
298 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_RGMII)) {
299 			err = mtk_gmac_rgmii_path_setup(eth, mac_id);
300 			if (err)
301 				return err;
302 		}
303 		break;
304 	case PHY_INTERFACE_MODE_SGMII:
305 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
306 			err = mtk_gmac_sgmii_path_setup(eth, mac_id);
307 			if (err)
308 				return err;
309 		}
310 		break;
311 	case PHY_INTERFACE_MODE_GMII:
312 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_GEPHY)) {
313 			err = mtk_gmac_gephy_path_setup(eth, mac_id);
314 			if (err)
315 				return err;
316 		}
317 		break;
318 	default:
319 		break;
320 	}
321 
322 	return 0;
323 }
324