Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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