Merge tag 'drm-next-2020-12-24' of git://anongit.freedesktop.org/drm/drm
[linux-2.6-microblaze.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, int path);
19 };
20
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
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
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
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
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
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
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
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
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
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