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