blob: dcb3c8a60319ce4f15e484ffd47ecd3a15e393e5 [file] [log] [blame]
developerfd40db22021-04-29 10:08:25 +08001// 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, int path);
19};
20
21static 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
43static 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
74static 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
97static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path)
98{
developer255bba22021-07-27 15:16:33 +080099 unsigned int val = 0,mask=0,reg=0;
developerfd40db22021-04-29 10:08:25 +0800100 bool updated = true;
101
102 switch (path) {
103 case MTK_ETH_PATH_GMAC2_SGMII:
developer255bba22021-07-27 15:16:33 +0800104 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 }
developerfd40db22021-04-29 10:08:25 +0800113 break;
114 default:
115 updated = false;
116 break;
117 }
118
119 if (updated)
developer255bba22021-07-27 15:16:33 +0800120 regmap_update_bits(eth->infra, reg, mask, val);
developerfd40db22021-04-29 10:08:25 +0800121
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
128static 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
developerd82e8372022-02-09 15:00:09 +0800133 spin_lock(&eth->syscfg0_lock);
134
developerfd40db22021-04-29 10:08:25 +0800135 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
developerd82e8372022-02-09 15:00:09 +0800162 spin_unlock(&eth->syscfg0_lock);
163
developerfd40db22021-04-29 10:08:25 +0800164 dev_dbg(eth->dev, "path %s in %s updated = %d\n",
165 mtk_eth_path_name(path), __func__, updated);
166
167 return 0;
168}
169
170static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, int path)
171{
172 unsigned int val = 0;
173 bool updated = true;
174
developerd82e8372022-02-09 15:00:09 +0800175 spin_lock(&eth->syscfg0_lock);
176
developerfd40db22021-04-29 10:08:25 +0800177 regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
178
179 switch (path) {
180 case MTK_ETH_PATH_GMAC1_SGMII:
181 val |= SYSCFG0_SGMII_GMAC1_V2;
182 break;
183 case MTK_ETH_PATH_GMAC2_GEPHY:
184 val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2;
185 break;
186 case MTK_ETH_PATH_GMAC2_SGMII:
187 val |= SYSCFG0_SGMII_GMAC2_V2;
188 break;
189 default:
190 updated = false;
191 };
192
193 if (updated)
194 regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
195 SYSCFG0_SGMII_MASK, val);
196
developerd82e8372022-02-09 15:00:09 +0800197 spin_unlock(&eth->syscfg0_lock);
198
developerfd40db22021-04-29 10:08:25 +0800199 dev_dbg(eth->dev, "path %s in %s updated = %d\n",
200 mtk_eth_path_name(path), __func__, updated);
201
202 return 0;
203}
204
205static const struct mtk_eth_muxc mtk_eth_muxc[] = {
206 {
207 .name = "mux_gdm1_to_gmac1_esw",
208 .cap_bit = MTK_ETH_MUX_GDM1_TO_GMAC1_ESW,
209 .set_path = set_mux_gdm1_to_gmac1_esw,
210 }, {
211 .name = "mux_gmac2_gmac0_to_gephy",
212 .cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY,
213 .set_path = set_mux_gmac2_gmac0_to_gephy,
214 }, {
215 .name = "mux_u3_gmac2_to_qphy",
216 .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY,
217 .set_path = set_mux_u3_gmac2_to_qphy,
218 }, {
219 .name = "mux_gmac1_gmac2_to_sgmii_rgmii",
220 .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII,
221 .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii,
222 }, {
223 .name = "mux_gmac12_to_gephy_sgmii",
224 .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII,
225 .set_path = set_mux_gmac12_to_gephy_sgmii,
226 },
227};
228
229static int mtk_eth_mux_setup(struct mtk_eth *eth, int path)
230{
231 int i, err = 0;
232
233 if (!MTK_HAS_CAPS(eth->soc->caps, path)) {
234 dev_err(eth->dev, "path %s isn't support on the SoC\n",
235 mtk_eth_path_name(path));
236 return -EINVAL;
237 }
238
239 if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX))
240 return 0;
241
242 /* Setup MUX in path fabric */
243 for (i = 0; i < ARRAY_SIZE(mtk_eth_muxc); i++) {
244 if (MTK_HAS_CAPS(eth->soc->caps, mtk_eth_muxc[i].cap_bit)) {
245 err = mtk_eth_muxc[i].set_path(eth, path);
246 if (err)
247 goto out;
248 } else {
249 dev_dbg(eth->dev, "mux %s isn't present on the SoC\n",
250 mtk_eth_muxc[i].name);
251 }
252 }
253
254out:
255 return err;
256}
257
258int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
259{
260 int err, path;
261
262 path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII :
263 MTK_ETH_PATH_GMAC2_SGMII;
264
265 /* Setup proper MUXes along the path */
266 err = mtk_eth_mux_setup(eth, path);
267 if (err)
268 return err;
269
270 return 0;
271}
272
273int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
274{
275 int err, path = 0;
276
277 if (mac_id == 1)
278 path = MTK_ETH_PATH_GMAC2_GEPHY;
279
280 if (!path)
281 return -EINVAL;
282
283 /* Setup proper MUXes along the path */
284 err = mtk_eth_mux_setup(eth, path);
285 if (err)
286 return err;
287
288 return 0;
289}
290
291int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)
292{
293 int err, path;
294
295 path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII :
296 MTK_ETH_PATH_GMAC2_RGMII;
297
298 /* Setup proper MUXes along the path */
299 err = mtk_eth_mux_setup(eth, path);
300 if (err)
301 return err;
302
303 return 0;
304}
305