3d94295eee3fb75d7769e361d6dc0f0980dbc320
[librecmc/librecmc.git] /
1 From 110c18bfed41421edd677935dd33be5e6507ba92 Mon Sep 17 00:00:00 2001
2 From: Daniel Golle <daniel@makrotopia.org>
3 Date: Mon, 3 Apr 2023 02:19:40 +0100
4 Subject: [PATCH 16/16] net: dsa: mt7530: introduce driver for MT7988 built-in
5  switch
6
7 Add driver for the built-in Gigabit Ethernet switch which can be found
8 in the MediaTek MT7988 SoC.
9
10 The switch shares most of its design with MT7530 and MT7531, but has
11 it's registers mapped into the SoCs register space rather than being
12 connected externally or internally via MDIO.
13
14 Introduce a new platform driver to support that.
15
16 Signed-off-by: Daniel Golle <daniel@makrotopia.org>
17 Reviewed-by: Andrew Lunn <andrew@lunn.ch>
18 Signed-off-by: David S. Miller <davem@davemloft.net>
19 ---
20  MAINTAINERS                   |   2 +
21  drivers/net/dsa/Kconfig       |  12 +++
22  drivers/net/dsa/Makefile      |   1 +
23  drivers/net/dsa/mt7530-mmio.c | 101 +++++++++++++++++++++++++
24  drivers/net/dsa/mt7530.c      | 137 +++++++++++++++++++++++++++++++++-
25  drivers/net/dsa/mt7530.h      |  12 +--
26  6 files changed, 255 insertions(+), 10 deletions(-)
27  create mode 100644 drivers/net/dsa/mt7530-mmio.c
28
29 --- a/MAINTAINERS
30 +++ b/MAINTAINERS
31 @@ -11900,9 +11900,11 @@ MEDIATEK SWITCH DRIVER
32  M:     Sean Wang <sean.wang@mediatek.com>
33  M:     Landen Chao <Landen.Chao@mediatek.com>
34  M:     DENG Qingfang <dqfext@gmail.com>
35 +M:     Daniel Golle <daniel@makrotopia.org>
36  L:     netdev@vger.kernel.org
37  S:     Maintained
38  F:     drivers/net/dsa/mt7530-mdio.c
39 +F:     drivers/net/dsa/mt7530-mmio.c
40  F:     drivers/net/dsa/mt7530.*
41  F:     net/dsa/tag_mtk.c
42  
43 --- a/drivers/net/dsa/Kconfig
44 +++ b/drivers/net/dsa/Kconfig
45 @@ -38,6 +38,7 @@ config NET_DSA_MT7530
46         select NET_DSA_TAG_MTK
47         select MEDIATEK_GE_PHY
48         imply NET_DSA_MT7530_MDIO
49 +       imply NET_DSA_MT7530_MMIO
50         help
51           This enables support for the MediaTek MT7530 and MT7531 Ethernet
52           switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT,
53 @@ -54,6 +55,17 @@ config NET_DSA_MT7530_MDIO
54           module MT7530 which can be found in the MT7621AT, MT7621DAT,
55           MT7621ST and MT7623AI SoCs.
56  
57 +config NET_DSA_MT7530_MMIO
58 +       tristate "MediaTek MT7530 MMIO interface driver"
59 +       depends on NET_DSA_MT7530
60 +       depends on HAS_IOMEM
61 +       help
62 +         This enables support for the built-in Ethernet switch found
63 +         in the MediaTek MT7988 SoC.
64 +         The switch is a similar design as MT7531, but the switch registers
65 +         are directly mapped into the SoCs register space rather than being
66 +         accessible via MDIO.
67 +
68  config NET_DSA_MV88E6060
69         tristate "Marvell 88E6060 ethernet switch chip support"
70         select NET_DSA_TAG_TRAILER
71 --- a/drivers/net/dsa/Makefile
72 +++ b/drivers/net/dsa/Makefile
73 @@ -8,6 +8,7 @@ endif
74  obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o
75  obj-$(CONFIG_NET_DSA_MT7530)   += mt7530.o
76  obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o
77 +obj-$(CONFIG_NET_DSA_MT7530_MMIO) += mt7530-mmio.o
78  obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
79  obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
80  realtek-smi-objs               := realtek-smi-core.o rtl8366.o rtl8366rb.o
81 --- /dev/null
82 +++ b/drivers/net/dsa/mt7530-mmio.c
83 @@ -0,0 +1,101 @@
84 +// SPDX-License-Identifier: GPL-2.0-only
85 +
86 +#include <linux/module.h>
87 +#include <linux/of_platform.h>
88 +#include <linux/regmap.h>
89 +#include <linux/regulator/consumer.h>
90 +#include <linux/reset.h>
91 +#include <net/dsa.h>
92 +
93 +#include "mt7530.h"
94 +
95 +static const struct of_device_id mt7988_of_match[] = {
96 +       { .compatible = "mediatek,mt7988-switch", .data = &mt753x_table[ID_MT7988], },
97 +       { /* sentinel */ },
98 +};
99 +MODULE_DEVICE_TABLE(of, mt7988_of_match);
100 +
101 +static int
102 +mt7988_probe(struct platform_device *pdev)
103 +{
104 +       static struct regmap_config *sw_regmap_config;
105 +       struct mt7530_priv *priv;
106 +       void __iomem *base_addr;
107 +       int ret;
108 +
109 +       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
110 +       if (!priv)
111 +               return -ENOMEM;
112 +
113 +       priv->bus = NULL;
114 +       priv->dev = &pdev->dev;
115 +
116 +       ret = mt7530_probe_common(priv);
117 +       if (ret)
118 +               return ret;
119 +
120 +       priv->rstc = devm_reset_control_get(&pdev->dev, NULL);
121 +       if (IS_ERR(priv->rstc)) {
122 +               dev_err(&pdev->dev, "Couldn't get our reset line\n");
123 +               return PTR_ERR(priv->rstc);
124 +       }
125 +
126 +       base_addr = devm_platform_ioremap_resource(pdev, 0);
127 +       if (IS_ERR(base_addr)) {
128 +               dev_err(&pdev->dev, "cannot request I/O memory space\n");
129 +               return -ENXIO;
130 +       }
131 +
132 +       sw_regmap_config = devm_kzalloc(&pdev->dev, sizeof(*sw_regmap_config), GFP_KERNEL);
133 +       if (!sw_regmap_config)
134 +               return -ENOMEM;
135 +
136 +       sw_regmap_config->name = "switch";
137 +       sw_regmap_config->reg_bits = 16;
138 +       sw_regmap_config->val_bits = 32;
139 +       sw_regmap_config->reg_stride = 4;
140 +       sw_regmap_config->max_register = MT7530_CREV;
141 +       priv->regmap = devm_regmap_init_mmio(&pdev->dev, base_addr, sw_regmap_config);
142 +       if (IS_ERR(priv->regmap))
143 +               return PTR_ERR(priv->regmap);
144 +
145 +       return dsa_register_switch(priv->ds);
146 +}
147 +
148 +static int
149 +mt7988_remove(struct platform_device *pdev)
150 +{
151 +       struct mt7530_priv *priv = platform_get_drvdata(pdev);
152 +
153 +       if (priv)
154 +               mt7530_remove_common(priv);
155 +
156 +       return 0;
157 +}
158 +
159 +static void mt7988_shutdown(struct platform_device *pdev)
160 +{
161 +       struct mt7530_priv *priv = platform_get_drvdata(pdev);
162 +
163 +       if (!priv)
164 +               return;
165 +
166 +       dsa_switch_shutdown(priv->ds);
167 +
168 +       dev_set_drvdata(&pdev->dev, NULL);
169 +}
170 +
171 +static struct platform_driver mt7988_platform_driver = {
172 +       .probe  = mt7988_probe,
173 +       .remove = mt7988_remove,
174 +       .shutdown = mt7988_shutdown,
175 +       .driver = {
176 +               .name = "mt7530-mmio",
177 +               .of_match_table = mt7988_of_match,
178 +       },
179 +};
180 +module_platform_driver(mt7988_platform_driver);
181 +
182 +MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
183 +MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch (MMIO)");
184 +MODULE_LICENSE("GPL");
185 --- a/drivers/net/dsa/mt7530.c
186 +++ b/drivers/net/dsa/mt7530.c
187 @@ -2198,6 +2198,47 @@ static const struct irq_domain_ops mt753
188  };
189  
190  static void
191 +mt7988_irq_mask(struct irq_data *d)
192 +{
193 +       struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
194 +
195 +       priv->irq_enable &= ~BIT(d->hwirq);
196 +       mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable);
197 +}
198 +
199 +static void
200 +mt7988_irq_unmask(struct irq_data *d)
201 +{
202 +       struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
203 +
204 +       priv->irq_enable |= BIT(d->hwirq);
205 +       mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable);
206 +}
207 +
208 +static struct irq_chip mt7988_irq_chip = {
209 +       .name = KBUILD_MODNAME,
210 +       .irq_mask = mt7988_irq_mask,
211 +       .irq_unmask = mt7988_irq_unmask,
212 +};
213 +
214 +static int
215 +mt7988_irq_map(struct irq_domain *domain, unsigned int irq,
216 +              irq_hw_number_t hwirq)
217 +{
218 +       irq_set_chip_data(irq, domain->host_data);
219 +       irq_set_chip_and_handler(irq, &mt7988_irq_chip, handle_simple_irq);
220 +       irq_set_nested_thread(irq, true);
221 +       irq_set_noprobe(irq);
222 +
223 +       return 0;
224 +}
225 +
226 +static const struct irq_domain_ops mt7988_irq_domain_ops = {
227 +       .map = mt7988_irq_map,
228 +       .xlate = irq_domain_xlate_onecell,
229 +};
230 +
231 +static void
232  mt7530_setup_mdio_irq(struct mt7530_priv *priv)
233  {
234         struct dsa_switch *ds = priv->ds;
235 @@ -2231,8 +2272,15 @@ mt7530_setup_irq(struct mt7530_priv *pri
236                 return priv->irq ? : -EINVAL;
237         }
238  
239 -       priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS,
240 -                                                &mt7530_irq_domain_ops, priv);
241 +       if (priv->id == ID_MT7988)
242 +               priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS,
243 +                                                        &mt7988_irq_domain_ops,
244 +                                                        priv);
245 +       else
246 +               priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS,
247 +                                                        &mt7530_irq_domain_ops,
248 +                                                        priv);
249 +
250         if (!priv->irq_domain) {
251                 dev_err(dev, "failed to create IRQ domain\n");
252                 return -ENOMEM;
253 @@ -2727,6 +2775,25 @@ static void mt7531_mac_port_get_caps(str
254         }
255  }
256  
257 +static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port,
258 +                                    struct phylink_config *config)
259 +{
260 +       phy_interface_zero(config->supported_interfaces);
261 +
262 +       switch (port) {
263 +       case 0 ... 4: /* Internal phy */
264 +               __set_bit(PHY_INTERFACE_MODE_INTERNAL,
265 +                         config->supported_interfaces);
266 +               break;
267 +
268 +       case 6:
269 +               __set_bit(PHY_INTERFACE_MODE_INTERNAL,
270 +                         config->supported_interfaces);
271 +               config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
272 +                                          MAC_10000FD;
273 +       }
274 +}
275 +
276  static int
277  mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state)
278  {
279 @@ -2803,6 +2870,17 @@ static bool mt753x_is_mac_port(u32 port)
280  }
281  
282  static int
283 +mt7988_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
284 +                 phy_interface_t interface)
285 +{
286 +       if (dsa_is_cpu_port(ds, port) &&
287 +           interface == PHY_INTERFACE_MODE_INTERNAL)
288 +               return 0;
289 +
290 +       return -EINVAL;
291 +}
292 +
293 +static int
294  mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
295                   phy_interface_t interface)
296  {
297 @@ -2872,7 +2950,8 @@ mt753x_phylink_mac_config(struct dsa_swi
298  
299         switch (port) {
300         case 0 ... 4: /* Internal phy */
301 -               if (state->interface != PHY_INTERFACE_MODE_GMII)
302 +               if (state->interface != PHY_INTERFACE_MODE_GMII &&
303 +                   state->interface != PHY_INTERFACE_MODE_INTERNAL)
304                         goto unsupported;
305                 break;
306         case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
307 @@ -2950,7 +3029,8 @@ static void mt753x_phylink_mac_link_up(s
308         /* MT753x MAC works in 1G full duplex mode for all up-clocked
309          * variants.
310          */
311 -       if (interface == PHY_INTERFACE_MODE_TRGMII ||
312 +       if (interface == PHY_INTERFACE_MODE_INTERNAL ||
313 +           interface == PHY_INTERFACE_MODE_TRGMII ||
314             (phy_interface_mode_is_8023z(interface))) {
315                 speed = SPEED_1000;
316                 duplex = DUPLEX_FULL;
317 @@ -3030,6 +3110,21 @@ mt7531_cpu_port_config(struct dsa_switch
318         return 0;
319  }
320  
321 +static int
322 +mt7988_cpu_port_config(struct dsa_switch *ds, int port)
323 +{
324 +       struct mt7530_priv *priv = ds->priv;
325 +
326 +       mt7530_write(priv, MT7530_PMCR_P(port),
327 +                    PMCR_CPU_PORT_SETTING(priv->id));
328 +
329 +       mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED,
330 +                                  PHY_INTERFACE_MODE_INTERNAL, NULL,
331 +                                  SPEED_10000, DUPLEX_FULL, true, true);
332 +
333 +       return 0;
334 +}
335 +
336  static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
337                                     struct phylink_config *config)
338  {
339 @@ -3175,6 +3270,27 @@ static int mt753x_set_mac_eee(struct dsa
340         return 0;
341  }
342  
343 +static int mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
344 +{
345 +       return 0;
346 +}
347 +
348 +static int mt7988_setup(struct dsa_switch *ds)
349 +{
350 +       struct mt7530_priv *priv = ds->priv;
351 +
352 +       /* Reset the switch */
353 +       reset_control_assert(priv->rstc);
354 +       usleep_range(20, 50);
355 +       reset_control_deassert(priv->rstc);
356 +       usleep_range(20, 50);
357 +
358 +       /* Reset the switch PHYs */
359 +       mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_PHY_RST);
360 +
361 +       return mt7531_setup_common(ds);
362 +}
363 +
364  const struct dsa_switch_ops mt7530_switch_ops = {
365         .get_tag_protocol       = mtk_get_tag_protocol,
366         .setup                  = mt753x_setup,
367 @@ -3243,6 +3359,17 @@ const struct mt753x_info mt753x_table[]
368                 .mac_port_get_caps = mt7531_mac_port_get_caps,
369                 .mac_port_config = mt7531_mac_config,
370         },
371 +       [ID_MT7988] = {
372 +               .id = ID_MT7988,
373 +               .pcs_ops = &mt7530_pcs_ops,
374 +               .sw_setup = mt7988_setup,
375 +               .phy_read = mt7531_ind_phy_read,
376 +               .phy_write = mt7531_ind_phy_write,
377 +               .pad_setup = mt7988_pad_setup,
378 +               .cpu_port_config = mt7988_cpu_port_config,
379 +               .mac_port_get_caps = mt7988_mac_port_get_caps,
380 +               .mac_port_config = mt7988_mac_config,
381 +       },
382  };
383  EXPORT_SYMBOL_GPL(mt753x_table);
384  
385 --- a/drivers/net/dsa/mt7530.h
386 +++ b/drivers/net/dsa/mt7530.h
387 @@ -18,6 +18,7 @@ enum mt753x_id {
388         ID_MT7530 = 0,
389         ID_MT7621 = 1,
390         ID_MT7531 = 2,
391 +       ID_MT7988 = 3,
392  };
393  
394  #define        NUM_TRGMII_CTRL                 5
395 @@ -54,11 +55,11 @@ enum mt753x_id {
396  #define  MT7531_MIRROR_PORT_SET(x)     (((x) & MIRROR_MASK) << 16)
397  #define  MT7531_CPU_PMAP_MASK          GENMASK(7, 0)
398  
399 -#define MT753X_MIRROR_REG(id)          (((id) == ID_MT7531) ? \
400 +#define MT753X_MIRROR_REG(id)          ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
401                                          MT7531_CFC : MT7530_MFC)
402 -#define MT753X_MIRROR_EN(id)           (((id) == ID_MT7531) ? \
403 +#define MT753X_MIRROR_EN(id)           ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
404                                          MT7531_MIRROR_EN : MIRROR_EN)
405 -#define MT753X_MIRROR_MASK(id)         (((id) == ID_MT7531) ? \
406 +#define MT753X_MIRROR_MASK(id)         ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
407                                          MT7531_MIRROR_MASK : MIRROR_MASK)
408  
409  /* Registers for BPDU and PAE frame control*/
410 @@ -327,9 +328,8 @@ enum mt7530_vlan_port_acc_frm {
411                                          MT7531_FORCE_DPX | \
412                                          MT7531_FORCE_RX_FC | \
413                                          MT7531_FORCE_TX_FC)
414 -#define  PMCR_FORCE_MODE_ID(id)                (((id) == ID_MT7531) ? \
415 -                                        MT7531_FORCE_MODE : \
416 -                                        PMCR_FORCE_MODE)
417 +#define  PMCR_FORCE_MODE_ID(id)                ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
418 +                                        MT7531_FORCE_MODE : PMCR_FORCE_MODE)
419  #define  PMCR_LINK_SETTINGS_MASK       (PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \
420                                          PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \
421                                          PMCR_TX_FC_EN | PMCR_RX_FC_EN | \