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 	int		cap_bit;
18 	int		(*set_path)(struct mtk_eth *eth, u64 path);
19 };
20 
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_GEPHY:
35 		return "gmac2_gephy";
36 	case MTK_ETH_PATH_GDM1_ESW:
37 		return "gdm1_esw";
38 	default:
39 		return "unknown path";
40 	}
41 }
42 
43 static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, u64 path)
44 {
45 	bool updated = true;
46 	u32 mask, set, reg;
47 
48 	switch (path) {
49 	case MTK_ETH_PATH_GMAC1_SGMII:
50 		mask = ~(u32)MTK_MUX_TO_ESW;
51 		set = 0;
52 		break;
53 	case MTK_ETH_PATH_GDM1_ESW:
54 		mask = ~(u32)MTK_MUX_TO_ESW;
55 		set = MTK_MUX_TO_ESW;
56 		break;
57 	default:
58 		updated = false;
59 		break;
60 	}
61 
62 	if (mtk_is_netsys_v3_or_greater(eth))
63 		reg = MTK_MAC_MISC_V3;
64 	else
65 		reg = MTK_MAC_MISC;
66 
67 	if (updated)
68 		mtk_m32(eth, mask, set, reg);
69 
70 	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
71 		mtk_eth_path_name(path), __func__, updated);
72 
73 	return 0;
74 }
75 
76 static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, u64 path)
77 {
78 	unsigned int val = 0;
79 	bool updated = true;
80 
81 	switch (path) {
82 	case MTK_ETH_PATH_GMAC2_GEPHY:
83 		val = ~(u32)GEPHY_MAC_SEL;
84 		break;
85 	default:
86 		updated = false;
87 		break;
88 	}
89 
90 	if (updated)
91 		regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val);
92 
93 	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
94 		mtk_eth_path_name(path), __func__, updated);
95 
96 	return 0;
97 }
98 
99 static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path)
100 {
101 	unsigned int val = 0, mask = 0, reg = 0;
102 	bool updated = true;
103 
104 	switch (path) {
105 	case MTK_ETH_PATH_GMAC2_SGMII:
106 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) {
107 			reg = USB_PHY_SWITCH_REG;
108 			val = SGMII_QPHY_SEL;
109 			mask = QPHY_SEL_MASK;
110 		} else {
111 			reg = INFRA_MISC2;
112 			val = CO_QPHY_SEL;
113 			mask = val;
114 		}
115 		break;
116 	default:
117 		updated = false;
118 		break;
119 	}
120 
121 	if (updated)
122 		regmap_update_bits(eth->infra, reg, mask, val);
123 
124 	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
125 		mtk_eth_path_name(path), __func__, updated);
126 
127 	return 0;
128 }
129 
130 static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path)
131 {
132 	unsigned int val = 0;
133 	bool updated = true;
134 
135 	switch (path) {
136 	case MTK_ETH_PATH_GMAC1_SGMII:
137 		val = SYSCFG0_SGMII_GMAC1;
138 		break;
139 	case MTK_ETH_PATH_GMAC2_SGMII:
140 		val = SYSCFG0_SGMII_GMAC2;
141 		break;
142 	case MTK_ETH_PATH_GMAC1_RGMII:
143 	case MTK_ETH_PATH_GMAC2_RGMII:
144 		regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
145 		val &= SYSCFG0_SGMII_MASK;
146 
147 		if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) ||
148 		    (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2))
149 			val = 0;
150 		else
151 			updated = false;
152 		break;
153 	default:
154 		updated = false;
155 		break;
156 	}
157 
158 	if (updated)
159 		regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
160 				   SYSCFG0_SGMII_MASK, val);
161 
162 	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
163 		mtk_eth_path_name(path), __func__, updated);
164 
165 	return 0;
166 }
167 
168 static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path)
169 {
170 	unsigned int val = 0;
171 	bool updated = true;
172 
173 	regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
174 
175 	switch (path) {
176 	case MTK_ETH_PATH_GMAC1_SGMII:
177 		val |= SYSCFG0_SGMII_GMAC1_V2;
178 		break;
179 	case MTK_ETH_PATH_GMAC2_GEPHY:
180 		val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2;
181 		break;
182 	case MTK_ETH_PATH_GMAC2_SGMII:
183 		val |= SYSCFG0_SGMII_GMAC2_V2;
184 		break;
185 	default:
186 		updated = false;
187 	}
188 
189 	if (updated)
190 		regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
191 				   SYSCFG0_SGMII_MASK, val);
192 
193 	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
194 		mtk_eth_path_name(path), __func__, updated);
195 
196 	return 0;
197 }
198 
199 static const struct mtk_eth_muxc mtk_eth_muxc[] = {
200 	{
201 		.name = "mux_gdm1_to_gmac1_esw",
202 		.cap_bit = MTK_ETH_MUX_GDM1_TO_GMAC1_ESW,
203 		.set_path = set_mux_gdm1_to_gmac1_esw,
204 	}, {
205 		.name = "mux_gmac2_gmac0_to_gephy",
206 		.cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY,
207 		.set_path = set_mux_gmac2_gmac0_to_gephy,
208 	}, {
209 		.name = "mux_u3_gmac2_to_qphy",
210 		.cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY,
211 		.set_path = set_mux_u3_gmac2_to_qphy,
212 	}, {
213 		.name = "mux_gmac1_gmac2_to_sgmii_rgmii",
214 		.cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII,
215 		.set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii,
216 	}, {
217 		.name = "mux_gmac12_to_gephy_sgmii",
218 		.cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII,
219 		.set_path = set_mux_gmac12_to_gephy_sgmii,
220 	},
221 };
222 
223 static int mtk_eth_mux_setup(struct mtk_eth *eth, u64 path)
224 {
225 	int i, err = 0;
226 
227 	if (!MTK_HAS_CAPS(eth->soc->caps, path)) {
228 		dev_err(eth->dev, "path %s isn't support on the SoC\n",
229 			mtk_eth_path_name(path));
230 		return -EINVAL;
231 	}
232 
233 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX))
234 		return 0;
235 
236 	/* Setup MUX in path fabric */
237 	for (i = 0; i < ARRAY_SIZE(mtk_eth_muxc); i++) {
238 		if (MTK_HAS_CAPS(eth->soc->caps, mtk_eth_muxc[i].cap_bit)) {
239 			err = mtk_eth_muxc[i].set_path(eth, path);
240 			if (err)
241 				goto out;
242 		} else {
243 			dev_dbg(eth->dev, "mux %s isn't present on the SoC\n",
244 				mtk_eth_muxc[i].name);
245 		}
246 	}
247 
248 out:
249 	return err;
250 }
251 
252 int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
253 {
254 	u64 path;
255 
256 	path = (mac_id == 0) ?  MTK_ETH_PATH_GMAC1_SGMII :
257 				MTK_ETH_PATH_GMAC2_SGMII;
258 
259 	/* Setup proper MUXes along the path */
260 	return mtk_eth_mux_setup(eth, path);
261 }
262 
263 int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
264 {
265 	u64 path = 0;
266 
267 	if (mac_id == 1)
268 		path = MTK_ETH_PATH_GMAC2_GEPHY;
269 
270 	if (!path)
271 		return -EINVAL;
272 
273 	/* Setup proper MUXes along the path */
274 	return mtk_eth_mux_setup(eth, path);
275 }
276 
277 int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)
278 {
279 	u64 path;
280 
281 	path = (mac_id == 0) ?  MTK_ETH_PATH_GMAC1_RGMII :
282 				MTK_ETH_PATH_GMAC2_RGMII;
283 
284 	/* Setup proper MUXes along the path */
285 	return mtk_eth_mux_setup(eth, path);
286 }
287 
288