GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / net / ethernet / mediatek / mtk_eth_path.c
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, u64 path);
19 };
20
21 static 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
43 static 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
76 static 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
99 static 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
130 static 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
168 static 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
199 static 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
223 static 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
248 out:
249         return err;
250 }
251
252 int 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
263 int 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
277 int 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