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