1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
|
// SPDX-License-Identifier: GPL-2.0
/*
* Mediatek MT7628 Embedded Switch (ESW) DSA driver
* Copyright (C) 2026 Joris Vaisvila <joey@tinyisr.com>
*
* Portions derived from OpenWRT esw_rt3050 driver:
* Copyright (C) 2009-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
* Copyright (C) 2016 Vittorio Gambaletta <openwrt@vittgam.net>
*/
#include <linux/platform_device.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/dsa/8021q.h>
#include <linux/if_bridge.h>
#include <linux/module.h>
#include <linux/mdio.h>
#include <linux/of.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/kernel.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <net/dsa.h>
#define MT7628_ESW_REG_IMR 0x04
#define MT7628_ESW_REG_FCT0 0x08
#define MT7628_ESW_REG_PFC1 0x14
#define MT7628_ESW_REG_PVIDC(port) (0x40 + 4 * ((port) / 2))
#define MT7628_ESW_REG_VLANI(vlan) (0x50 + 4 * ((vlan) / 2))
#define MT7628_ESW_REG_VMSC(vlan) (0x70 + 4 * ((vlan) / 4))
#define MT7628_ESW_REG_VUB(vlan) (0x100 + 4 * ((vlan) / 4))
#define MT7628_ESW_REG_SOCPC 0x8c
#define MT7628_ESW_REG_POC0 0x90
#define MT7628_ESW_REG_POC2 0x98
#define MT7628_ESW_REG_SGC 0x9c
#define MT7628_ESW_REG_PCR0 0xc0
#define MT7628_ESW_REG_PCR1 0xc4
#define MT7628_ESW_REG_FPA2 0xc8
#define MT7628_ESW_REG_FCT2 0xcc
#define MT7628_ESW_REG_SGC2 0xe4
#define MT7628_ESW_FCT0_DROP_SET_TH GENMASK(7, 0)
#define MT7628_ESW_FCT0_DROP_RLS_TH GENMASK(15, 8)
#define MT7628_ESW_FCT0_FC_SET_TH GENMASK(23, 16)
#define MT7628_ESW_FCT0_FC_RLS_TH GENMASK(31, 24)
#define MT7628_ESW_PFC1_EN_VLAN GENMASK(22, 16)
#define MT7628_ESW_PVID_S 12
#define MT7628_ESW_PVID_M GENMASK(11, 0)
#define MT7628_ESW_PVID_SHIFT(port) \
(MT7628_ESW_PVID_S * ((port) % 2))
#define MT7628_ESW_PVID_MASK(port) \
(MT7628_ESW_PVID_M << MT7628_ESW_PVID_SHIFT(port))
#define MT7628_ESW_PVID_PREP(port, pvid) \
(((pvid) & MT7628_ESW_PVID_M) << MT7628_ESW_PVID_SHIFT(port))
#define MT7628_ESW_VID_S 12
#define MT7628_ESW_VID_M GENMASK(11, 0)
#define MT7628_ESW_VID_SHIFT(vlan) \
(MT7628_ESW_VID_S * ((vlan) % 2))
#define MT7628_ESW_VID_MASK(vlan) \
(MT7628_ESW_VID_M << MT7628_ESW_VID_SHIFT(vlan))
#define MT7628_ESW_VID_PREP(vlan, vid) \
(((vid) & MT7628_ESW_VID_M) << MT7628_ESW_VID_SHIFT(vlan))
#define MT7628_ESW_VMSC_S 8
#define MT7628_ESW_VMSC_M GENMASK(7, 0)
#define MT7628_ESW_VMSC_SHIFT(vlan) \
(MT7628_ESW_VMSC_S * ((vlan) % 4))
#define MT7628_ESW_VMSC_MASK(vlan) \
(MT7628_ESW_VMSC_M << MT7628_ESW_VMSC_SHIFT(vlan))
#define MT7628_ESW_VMSC_PREP(vlan, vmsc) \
(((vmsc) & MT7628_ESW_VMSC_M) << MT7628_ESW_VMSC_SHIFT(vlan))
#define MT7628_ESW_VUB_S 7
#define MT7628_ESW_VUB_M GENMASK(6, 0)
#define MT7628_ESW_VUB_SHIFT(vlan) \
(MT7628_ESW_VUB_S * ((vlan) % 4))
#define MT7628_ESW_VUB_MASK(vlan) \
(MT7628_ESW_VUB_M << MT7628_ESW_VUB_SHIFT(vlan))
#define MT7628_ESW_VUB_PREP(vlan, vub) \
(((vub) & MT7628_ESW_VUB_M) << MT7628_ESW_VUB_SHIFT(vlan))
#define MT7628_ESW_SOCPC_CRC_PADDING BIT(25)
#define MT7628_ESW_SOCPC_DISBC2CPU GENMASK(22, 16)
#define MT7628_ESW_SOCPC_DISMC2CPU GENMASK(14, 8)
#define MT7628_ESW_SOCPC_DISUN2CPU GENMASK(6, 0)
#define MT7628_ESW_POC0_PORT_DISABLE GENMASK(29, 23)
#define MT7628_ESW_POC2_PER_VLAN_UNTAG_EN BIT(15)
#define MT7628_ESW_SGC_AGING_INTERVAL GENMASK(3, 0)
#define MT7628_ESW_BC_STORM_PROT GENMASK(5, 4)
#define MT7628_ESW_PKT_MAX_LEN GENMASK(7, 6)
#define MT7628_ESW_DIS_PKT_ABORT BIT(8)
#define MT7628_ESW_ADDRESS_HASH_ALG GENMASK(10, 9)
#define MT7628_ESW_DISABLE_TX_BACKOFF BIT(11)
#define MT7628_ESW_BP_JAM_CNT GENMASK(15, 12)
#define MT7628_ESW_DISMIIPORT_WASTX GENMASK(17, 16)
#define MT7628_ESW_BP_MODE GENMASK(19, 18)
#define MT7628_ESW_BISH_DIS BIT(20)
#define MT7628_ESW_BISH_TH GENMASK(22, 21)
#define MT7628_ESW_LED_FLASH_TIME GENMASK(24, 23)
#define MT7628_ESW_RMC_RULE GENMASK(26, 25)
#define MT7628_ESW_IP_MULT_RULE GENMASK(28, 27)
#define MT7628_ESW_LEN_ERR_CHK BIT(29)
#define MT7628_ESW_BKOFF_ALG BIT(30)
#define MT7628_ESW_PCR0_WT_NWAY_DATA GENMASK(31, 16)
#define MT7628_ESW_PCR0_RD_PHY_CMD BIT(14)
#define MT7628_ESW_PCR0_WT_PHY_CMD BIT(13)
#define MT7628_ESW_PCR0_CPU_PHY_REG GENMASK(12, 8)
#define MT7628_ESW_PCR0_CPU_PHY_ADDR GENMASK(4, 0)
#define MT7628_ESW_PCR1_RD_DATA GENMASK(31, 16)
#define MT7628_ESW_PCR1_RD_DONE BIT(1)
#define MT7628_ESW_PCR1_WT_DONE BIT(0)
#define MT7628_ESW_FPA2_AP_EN BIT(29)
#define MT7628_ESW_FPA2_EXT_PHY_ADDR_BASE GENMASK(28, 24)
#define MT7628_ESW_FPA2_FORCE_RGMII_LINK1 BIT(13)
#define MT7628_ESW_FPA2_FORCE_RGMII_EN1 BIT(11)
#define MT7628_ESW_FCT2_MUST_DROP_RLS_TH GENMASK(17, 13)
#define MT7628_ESW_FCT2_MUST_DROP_SET_TH GENMASK(12, 8)
#define MT7628_ESW_FCT2_MC_PER_PORT_TH GENMASK(5, 0)
#define MT7628_ESW_SGC2_SPECIAL_TAG_EN BIT(23)
#define MT7628_ESW_SGC2_TX_CPU_TPID_BIT_MAP GENMASK(22, 16)
#define MT7628_ESW_SGC2_DOUBLE_TAG_EN GENMASK(6, 0)
#define MT7628_ESW_PORTS_NOCPU GENMASK(5, 0)
#define MT7628_ESW_PORTS_CPU BIT(6)
#define MT7628_ESW_PORTS_ALL GENMASK(6, 0)
#define MT7628_ESW_NUM_PORTS 7
#define MT7628_NUM_VLANS 16
static const struct regmap_config mt7628_esw_regmap_cfg = {
.name = "mt7628-esw",
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.fast_io = true,
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
struct mt7628_vlan {
bool active;
u8 members;
u8 untag;
u16 vid;
};
struct mt7628_esw {
struct reset_control *rst_ephy;
struct reset_control *rst_esw;
struct regmap *regmap;
struct dsa_switch *ds;
u16 tag_8021q_pvid[MT7628_ESW_NUM_PORTS];
struct mt7628_vlan vlans[MT7628_NUM_VLANS];
struct device *dev;
};
static int mt7628_mii_read(struct mii_bus *bus, int port, int regnum)
{
struct mt7628_esw *esw = bus->priv;
int ret;
u32 val;
/*
* RD_DONE bit is read to clear. Read PCR1 once to acknowledge any
* stale completion indicator before starting a new transaction.
*/
ret = regmap_read(esw->regmap, MT7628_ESW_REG_PCR1, &val);
if (ret)
goto out;
ret = regmap_write(esw->regmap, MT7628_ESW_REG_PCR0,
FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_REG,
regnum) |
FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_ADDR,
port) | MT7628_ESW_PCR0_RD_PHY_CMD);
if (ret)
goto out;
ret = regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,
(val & MT7628_ESW_PCR1_RD_DONE), 10,
5000);
if (ret)
goto out;
return FIELD_GET(MT7628_ESW_PCR1_RD_DATA, val);
out:
dev_err(&bus->dev, "read failed. MDIO timeout?\n");
return ret;
}
static int mt7628_mii_write(struct mii_bus *bus, int port, int regnum, u16 dat)
{
struct mt7628_esw *esw = bus->priv;
u32 val;
int ret;
/*
* WT_DONE bit is read to clear. Read PCR1 once to acknowledge any
* stale completion indicator before starting a new transaction.
*/
ret = regmap_read(esw->regmap, MT7628_ESW_REG_PCR1, &val);
if (ret)
goto out;
ret = regmap_write(esw->regmap, MT7628_ESW_REG_PCR0,
FIELD_PREP(MT7628_ESW_PCR0_WT_NWAY_DATA, dat) |
FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_REG,
regnum) |
FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_ADDR,
port) | MT7628_ESW_PCR0_WT_PHY_CMD);
if (ret)
goto out;
ret = regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,
(val & MT7628_ESW_PCR1_WT_DONE), 10,
5000);
if (ret)
goto out;
return 0;
out:
dev_err(&bus->dev, "write failed. MDIO timeout?\n");
return ret;
}
static int mt7628_setup_internal_mdio(struct dsa_switch *ds)
{
struct mt7628_esw *esw = ds->priv;
struct device *dev = ds->dev;
struct mii_bus *bus;
bus = devm_mdiobus_alloc(dev);
if (!bus)
return -ENOMEM;
bus->name = "MT7628 internal MDIO bus";
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(dev));
bus->priv = esw;
bus->read = mt7628_mii_read;
bus->write = mt7628_mii_write;
bus->parent = dev;
ds->user_mii_bus = bus;
bus->phy_mask = ~ds->phys_mii_mask;
return devm_mdiobus_register(dev, bus);
}
static void mt7628_switch_init(struct dsa_switch *ds)
{
struct mt7628_esw *esw = ds->priv;
regmap_write(esw->regmap, MT7628_ESW_REG_FCT0,
FIELD_PREP(MT7628_ESW_FCT0_DROP_SET_TH, 0x50) |
FIELD_PREP(MT7628_ESW_FCT0_DROP_RLS_TH, 0x78) |
FIELD_PREP(MT7628_ESW_FCT0_FC_SET_TH, 0xa0) |
FIELD_PREP(MT7628_ESW_FCT0_FC_RLS_TH, 0xc8));
regmap_write(esw->regmap, MT7628_ESW_REG_FCT2,
FIELD_PREP(MT7628_ESW_FCT2_MC_PER_PORT_TH, 0xc) |
FIELD_PREP(MT7628_ESW_FCT2_MUST_DROP_SET_TH, 0x10) |
FIELD_PREP(MT7628_ESW_FCT2_MUST_DROP_RLS_TH, 0x12));
/*
* general switch configuration:
* 300s aging interval
* broadcast storm prevention disabled
* max packet length 1536 bytes
* disable collision 16 packet abort and late collision abort
* use xor48 for address hashing
* disable tx backoff
* 10 packet back pressure jam
* disable was_transmit
* jam until BP condition released
* 30ms LED flash
* rmc tb fault to all ports
* unmatched IGMP as broadcast
*/
regmap_write(esw->regmap, MT7628_ESW_REG_SGC,
FIELD_PREP(MT7628_ESW_SGC_AGING_INTERVAL, 1) |
FIELD_PREP(MT7628_ESW_BC_STORM_PROT, 0) |
FIELD_PREP(MT7628_ESW_PKT_MAX_LEN, 0) |
MT7628_ESW_DIS_PKT_ABORT |
FIELD_PREP(MT7628_ESW_ADDRESS_HASH_ALG, 1) |
MT7628_ESW_DISABLE_TX_BACKOFF |
FIELD_PREP(MT7628_ESW_BP_JAM_CNT, 10) |
FIELD_PREP(MT7628_ESW_DISMIIPORT_WASTX, 0) |
FIELD_PREP(MT7628_ESW_BP_MODE, 0b10) |
FIELD_PREP(MT7628_ESW_LED_FLASH_TIME, 0) |
FIELD_PREP(MT7628_ESW_RMC_RULE, 0) |
FIELD_PREP(MT7628_ESW_IP_MULT_RULE, 0));
regmap_write(esw->regmap, MT7628_ESW_REG_SOCPC,
MT7628_ESW_SOCPC_CRC_PADDING |
FIELD_PREP(MT7628_ESW_SOCPC_DISUN2CPU,
MT7628_ESW_PORTS_CPU) |
FIELD_PREP(MT7628_ESW_SOCPC_DISMC2CPU,
MT7628_ESW_PORTS_CPU) |
FIELD_PREP(MT7628_ESW_SOCPC_DISBC2CPU,
MT7628_ESW_PORTS_CPU));
regmap_set_bits(esw->regmap, MT7628_ESW_REG_FPA2,
MT7628_ESW_FPA2_FORCE_RGMII_EN1 |
MT7628_ESW_FPA2_FORCE_RGMII_LINK1 |
MT7628_ESW_FPA2_AP_EN);
regmap_update_bits(esw->regmap, MT7628_ESW_REG_FPA2,
MT7628_ESW_FPA2_EXT_PHY_ADDR_BASE,
FIELD_PREP(MT7628_ESW_FPA2_EXT_PHY_ADDR_BASE, 31));
/* disable all interrupts */
regmap_write(esw->regmap, MT7628_ESW_REG_IMR, 0);
/* enable MT7628 DSA tag on CPU port */
regmap_write(esw->regmap, MT7628_ESW_REG_SGC2,
MT7628_ESW_SGC2_SPECIAL_TAG_EN |
FIELD_PREP(MT7628_ESW_SGC2_TX_CPU_TPID_BIT_MAP,
MT7628_ESW_PORTS_CPU));
/*
* Double tag feature allows switch to always append the port PVID VLAN tag
* regardless of if the incoming packet already has a VLAN tag.
* This is enabled to simulate VLAN unawareness.
*/
regmap_set_bits(esw->regmap, MT7628_ESW_REG_SGC2,
FIELD_PREP(MT7628_ESW_SGC2_DOUBLE_TAG_EN,
MT7628_ESW_PORTS_NOCPU));
regmap_set_bits(esw->regmap, MT7628_ESW_REG_POC2,
MT7628_ESW_POC2_PER_VLAN_UNTAG_EN);
regmap_update_bits(esw->regmap, MT7628_ESW_REG_PFC1,
MT7628_ESW_PFC1_EN_VLAN,
FIELD_PREP(MT7628_ESW_PFC1_EN_VLAN,
MT7628_ESW_PORTS_ALL));
}
static void mt7628_esw_set_pvid(struct mt7628_esw *esw, unsigned int port,
unsigned int pvid)
{
regmap_update_bits(esw->regmap, MT7628_ESW_REG_PVIDC(port),
MT7628_ESW_PVID_MASK(port),
MT7628_ESW_PVID_PREP(port, pvid));
}
static void mt7628_esw_set_vlan_id(struct mt7628_esw *esw, unsigned int vlan,
unsigned int vid)
{
regmap_update_bits(esw->regmap, MT7628_ESW_REG_VLANI(vlan),
MT7628_ESW_VID_MASK(vlan),
MT7628_ESW_VID_PREP(vlan, vid));
}
static void mt7628_esw_set_vmsc(struct mt7628_esw *esw, unsigned int vlan,
unsigned int msc)
{
regmap_update_bits(esw->regmap, MT7628_ESW_REG_VMSC(vlan),
MT7628_ESW_VMSC_MASK(vlan),
MT7628_ESW_VMSC_PREP(vlan, msc));
}
static void mt7628_esw_set_vub(struct mt7628_esw *esw, unsigned int vlan,
unsigned int vub)
{
regmap_update_bits(esw->regmap, MT7628_ESW_REG_VUB(vlan),
MT7628_ESW_VUB_MASK(vlan),
MT7628_ESW_VUB_PREP(vlan, vub));
}
static void mt7628_vlan_sync(struct dsa_switch *ds)
{
struct mt7628_esw *esw = ds->priv;
int i;
for (i = 0; i < MT7628_NUM_VLANS; i++) {
struct mt7628_vlan *vlan = &esw->vlans[i];
mt7628_esw_set_vmsc(esw, i, vlan->members);
mt7628_esw_set_vlan_id(esw, i, vlan->vid);
mt7628_esw_set_vub(esw, i, vlan->untag);
}
for (i = 0; i < ds->num_ports; i++)
mt7628_esw_set_pvid(esw, i, esw->tag_8021q_pvid[i]);
}
static int mt7628_setup(struct dsa_switch *ds)
{
struct mt7628_esw *esw = ds->priv;
int ret;
ret = reset_control_reset(esw->rst_esw);
if (ret)
return ret;
usleep_range(1000, 2000);
ret = reset_control_reset(esw->rst_ephy);
if (ret)
return ret;
usleep_range(1000, 2000);
/*
* all MMIO reads hang if esw is not out of reset
* ephy needs extra time to get out of reset or it ends up misconfigured
*/
mt7628_switch_init(ds);
ret = mt7628_setup_internal_mdio(ds);
if (ret)
return ret;
rtnl_lock();
ret = dsa_tag_8021q_register(ds, htons(ETH_P_8021Q));
rtnl_unlock();
return ret;
}
static int mt7628_port_enable(struct dsa_switch *ds, int port,
struct phy_device *phy)
{
struct mt7628_esw *esw = ds->priv;
/*
* All switch ports are disabled by esw reset and enabled here by DSA.
*/
regmap_clear_bits(esw->regmap, MT7628_ESW_REG_POC0,
FIELD_PREP(MT7628_ESW_POC0_PORT_DISABLE, BIT(port)));
return 0;
}
static void mt7628_port_disable(struct dsa_switch *ds, int port)
{
struct mt7628_esw *esw = ds->priv;
regmap_set_bits(esw->regmap, MT7628_ESW_REG_POC0,
FIELD_PREP(MT7628_ESW_POC0_PORT_DISABLE, BIT(port)));
}
static enum dsa_tag_protocol
mt7628_get_tag_proto(struct dsa_switch *ds, int port, enum dsa_tag_protocol mp)
{
return DSA_TAG_PROTO_MT7628;
}
static void mt7628_phylink_get_caps(struct dsa_switch *ds, int port,
struct phylink_config *config)
{
switch (port) {
case 6:
config->mac_capabilities |= MAC_1000;
fallthrough;
case 0 ... 4:
config->mac_capabilities |= MAC_100 | MAC_10;
__set_bit(PHY_INTERFACE_MODE_INTERNAL,
config->supported_interfaces);
break;
default:
break; /* port 5 does not exist on MT7628 */
}
}
static int mt7628_dsa_8021q_vlan_add(struct dsa_switch *ds, int port,
u16 vid, u16 flags)
{
struct mt7628_esw *esw = ds->priv;
struct mt7628_vlan *vlan = NULL;
int i;
for (i = 0; i < MT7628_NUM_VLANS; i++) {
struct mt7628_vlan *check_vlan = &esw->vlans[i];
if (!check_vlan->active && !vlan)
vlan = check_vlan;
if (check_vlan->active && check_vlan->vid == vid) {
vlan = check_vlan;
break;
}
}
if (!vlan)
return -ENOSPC;
vlan->vid = vid;
vlan->active = true;
vlan->members |= BIT(port);
if (flags & BRIDGE_VLAN_INFO_PVID)
esw->tag_8021q_pvid[port] = vid;
if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
vlan->untag |= BIT(port);
mt7628_vlan_sync(ds);
return 0;
}
static int mt7628_dsa_8021q_vlan_del(struct dsa_switch *ds, int port, u16 vid)
{
struct mt7628_esw *esw = ds->priv;
struct mt7628_vlan *vlan = NULL;
int i;
for (i = 0; i < MT7628_NUM_VLANS; i++) {
struct mt7628_vlan *check_vlan = &esw->vlans[i];
if (!check_vlan->active || check_vlan->vid != vid)
continue;
vlan = check_vlan;
break;
}
if (!vlan)
return -ENOENT;
if (esw->tag_8021q_pvid[port] == vid)
esw->tag_8021q_pvid[port] = 0;
vlan->members &= ~BIT(port);
vlan->untag &= ~BIT(port);
if (!vlan->members) {
vlan->active = false;
vlan->vid = 0;
}
mt7628_vlan_sync(ds);
return 0;
}
static void mt7628_teardown(struct dsa_switch *ds)
{
rtnl_lock();
dsa_tag_8021q_unregister(ds);
rtnl_unlock();
}
static const struct dsa_switch_ops mt7628_switch_ops = {
.get_tag_protocol = mt7628_get_tag_proto,
.setup = mt7628_setup,
.teardown = mt7628_teardown,
.port_enable = mt7628_port_enable,
.port_disable = mt7628_port_disable,
.phylink_get_caps = mt7628_phylink_get_caps,
.tag_8021q_vlan_add = mt7628_dsa_8021q_vlan_add,
.tag_8021q_vlan_del = mt7628_dsa_8021q_vlan_del,
};
static int mt7628_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mt7628_esw *esw;
struct dsa_switch *ds;
void __iomem *base;
ds = devm_kzalloc(&pdev->dev, sizeof(*ds), GFP_KERNEL);
if (!ds)
return -ENOMEM;
esw = devm_kzalloc(&pdev->dev, sizeof(*esw), GFP_KERNEL);
if (!esw)
return -ENOMEM;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
esw->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&mt7628_esw_regmap_cfg);
if (IS_ERR(esw->regmap))
return PTR_ERR(esw->regmap);
esw->rst_ephy = devm_reset_control_get_exclusive(&pdev->dev, "ephy");
if (IS_ERR(esw->rst_ephy))
return dev_err_probe(dev, PTR_ERR(esw->rst_ephy),
"failed to get EPHY reset\n");
esw->rst_esw = devm_reset_control_get_exclusive(&pdev->dev, "esw");
if (IS_ERR(esw->rst_esw))
return dev_err_probe(dev, PTR_ERR(esw->rst_esw),
"failed to get ESW reset\n");
ds->dev = dev;
ds->num_ports = MT7628_ESW_NUM_PORTS;
ds->ops = &mt7628_switch_ops;
ds->priv = esw;
esw->ds = ds;
esw->dev = dev;
dev_set_drvdata(dev, esw);
return dsa_register_switch(ds);
}
static void mt7628_remove(struct platform_device *pdev)
{
struct mt7628_esw *esw = platform_get_drvdata(pdev);
if (!esw)
return;
dsa_unregister_switch(esw->ds);
}
static void mt7628_shutdown(struct platform_device *pdev)
{
struct mt7628_esw *esw = platform_get_drvdata(pdev);
if (!esw)
return;
dsa_switch_shutdown(esw->ds);
dev_set_drvdata(&pdev->dev, NULL);
}
static const struct of_device_id mt7628_of_match[] = {
{ .compatible = "mediatek,mt7628-esw" },
{}
};
MODULE_DEVICE_TABLE(of, mt7628_of_match);
static struct platform_driver mt7628_driver = {
.driver = {
.name = "mt7628-esw",
.of_match_table = mt7628_of_match,
},
.probe = mt7628_probe,
.remove = mt7628_remove,
.shutdown = mt7628_shutdown,
};
module_platform_driver(mt7628_driver);
MODULE_AUTHOR("Joris Vaisvila <joey@tinyisr.com>");
MODULE_DESCRIPTION("Driver for Mediatek MT7628 embedded switch");
MODULE_LICENSE("GPL");
|