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
15struct mtk_eth_muxc {
16	const char	*name;
17	int		cap_bit;
18	int		(*set_path)(struct mtk_eth *eth, u64 path);
19};
20
21static 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
43static 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
76static 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
99static 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
130static 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
168static 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
199static 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
223static 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
248out:
249	return err;
250}
251
252int 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
263int 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
277int 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