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