xref: /openbmc/linux/drivers/net/dsa/mv88e6xxx/chip.c (revision bfb25542)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2fad09c73SVivien Didelot /*
3fad09c73SVivien Didelot  * Marvell 88e6xxx Ethernet switch single-chip support
4fad09c73SVivien Didelot  *
5fad09c73SVivien Didelot  * Copyright (c) 2008 Marvell Semiconductor
6fad09c73SVivien Didelot  *
7fad09c73SVivien Didelot  * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
8fad09c73SVivien Didelot  *
94333d619SVivien Didelot  * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
104333d619SVivien Didelot  *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
11fad09c73SVivien Didelot  */
12fad09c73SVivien Didelot 
1319fb7f69SVivien Didelot #include <linux/bitfield.h>
14fad09c73SVivien Didelot #include <linux/delay.h>
15fad09c73SVivien Didelot #include <linux/etherdevice.h>
16fad09c73SVivien Didelot #include <linux/ethtool.h>
17fad09c73SVivien Didelot #include <linux/if_bridge.h>
18dc30c35bSAndrew Lunn #include <linux/interrupt.h>
19dc30c35bSAndrew Lunn #include <linux/irq.h>
20dc30c35bSAndrew Lunn #include <linux/irqdomain.h>
21fad09c73SVivien Didelot #include <linux/jiffies.h>
22fad09c73SVivien Didelot #include <linux/list.h>
23fad09c73SVivien Didelot #include <linux/mdio.h>
24fad09c73SVivien Didelot #include <linux/module.h>
25fad09c73SVivien Didelot #include <linux/of_device.h>
26dc30c35bSAndrew Lunn #include <linux/of_irq.h>
27fad09c73SVivien Didelot #include <linux/of_mdio.h>
28877b7cb0SAndrew Lunn #include <linux/platform_data/mv88e6xxx.h>
29fad09c73SVivien Didelot #include <linux/netdevice.h>
30fad09c73SVivien Didelot #include <linux/gpio/consumer.h>
31c9a2356fSRussell King #include <linux/phylink.h>
32fad09c73SVivien Didelot #include <net/dsa.h>
33ec561276SVivien Didelot 
344d5f2ba7SVivien Didelot #include "chip.h"
359dd43aa2SAndrew Lunn #include "devlink.h"
36a935c052SVivien Didelot #include "global1.h"
37ec561276SVivien Didelot #include "global2.h"
38c6fe0ad2SBrandon Streiff #include "hwtstamp.h"
3910fa5bfcSAndrew Lunn #include "phy.h"
4018abed21SVivien Didelot #include "port.h"
412fa8d3afSBrandon Streiff #include "ptp.h"
426d91782fSAndrew Lunn #include "serdes.h"
43e7ba0fadSVivien Didelot #include "smi.h"
44fad09c73SVivien Didelot 
45fad09c73SVivien Didelot static void assert_reg_lock(struct mv88e6xxx_chip *chip)
46fad09c73SVivien Didelot {
47fad09c73SVivien Didelot 	if (unlikely(!mutex_is_locked(&chip->reg_lock))) {
48fad09c73SVivien Didelot 		dev_err(chip->dev, "Switch registers lock not held!\n");
49fad09c73SVivien Didelot 		dump_stack();
50fad09c73SVivien Didelot 	}
51fad09c73SVivien Didelot }
52fad09c73SVivien Didelot 
53ec561276SVivien Didelot int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
54fad09c73SVivien Didelot {
55fad09c73SVivien Didelot 	int err;
56fad09c73SVivien Didelot 
57fad09c73SVivien Didelot 	assert_reg_lock(chip);
58fad09c73SVivien Didelot 
59fad09c73SVivien Didelot 	err = mv88e6xxx_smi_read(chip, addr, reg, val);
60fad09c73SVivien Didelot 	if (err)
61fad09c73SVivien Didelot 		return err;
62fad09c73SVivien Didelot 
63fad09c73SVivien Didelot 	dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
64fad09c73SVivien Didelot 		addr, reg, *val);
65fad09c73SVivien Didelot 
66fad09c73SVivien Didelot 	return 0;
67fad09c73SVivien Didelot }
68fad09c73SVivien Didelot 
69ec561276SVivien Didelot int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
70fad09c73SVivien Didelot {
71fad09c73SVivien Didelot 	int err;
72fad09c73SVivien Didelot 
73fad09c73SVivien Didelot 	assert_reg_lock(chip);
74fad09c73SVivien Didelot 
75fad09c73SVivien Didelot 	err = mv88e6xxx_smi_write(chip, addr, reg, val);
76fad09c73SVivien Didelot 	if (err)
77fad09c73SVivien Didelot 		return err;
78fad09c73SVivien Didelot 
79fad09c73SVivien Didelot 	dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
80fad09c73SVivien Didelot 		addr, reg, val);
81fad09c73SVivien Didelot 
82fad09c73SVivien Didelot 	return 0;
83fad09c73SVivien Didelot }
84fad09c73SVivien Didelot 
85683f2244SVivien Didelot int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg,
86683f2244SVivien Didelot 			u16 mask, u16 val)
87683f2244SVivien Didelot {
88683f2244SVivien Didelot 	u16 data;
89683f2244SVivien Didelot 	int err;
90683f2244SVivien Didelot 	int i;
91683f2244SVivien Didelot 
92683f2244SVivien Didelot 	/* There's no bus specific operation to wait for a mask */
93683f2244SVivien Didelot 	for (i = 0; i < 16; i++) {
94683f2244SVivien Didelot 		err = mv88e6xxx_read(chip, addr, reg, &data);
95683f2244SVivien Didelot 		if (err)
96683f2244SVivien Didelot 			return err;
97683f2244SVivien Didelot 
98683f2244SVivien Didelot 		if ((data & mask) == val)
99683f2244SVivien Didelot 			return 0;
100683f2244SVivien Didelot 
101683f2244SVivien Didelot 		usleep_range(1000, 2000);
102683f2244SVivien Didelot 	}
103683f2244SVivien Didelot 
104683f2244SVivien Didelot 	dev_err(chip->dev, "Timeout while waiting for switch\n");
105683f2244SVivien Didelot 	return -ETIMEDOUT;
106683f2244SVivien Didelot }
107683f2244SVivien Didelot 
10819fb7f69SVivien Didelot int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg,
10919fb7f69SVivien Didelot 		       int bit, int val)
11019fb7f69SVivien Didelot {
11119fb7f69SVivien Didelot 	return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit),
11219fb7f69SVivien Didelot 				   val ? BIT(bit) : 0x0000);
11319fb7f69SVivien Didelot }
11419fb7f69SVivien Didelot 
11510fa5bfcSAndrew Lunn struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
116a3c53be5SAndrew Lunn {
117a3c53be5SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
118a3c53be5SAndrew Lunn 
119a3c53be5SAndrew Lunn 	mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus,
120a3c53be5SAndrew Lunn 				    list);
121a3c53be5SAndrew Lunn 	if (!mdio_bus)
122a3c53be5SAndrew Lunn 		return NULL;
123a3c53be5SAndrew Lunn 
124a3c53be5SAndrew Lunn 	return mdio_bus->bus;
125a3c53be5SAndrew Lunn }
126a3c53be5SAndrew Lunn 
127dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_mask(struct irq_data *d)
128dc30c35bSAndrew Lunn {
129dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
130dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
131dc30c35bSAndrew Lunn 
132dc30c35bSAndrew Lunn 	chip->g1_irq.masked |= (1 << n);
133dc30c35bSAndrew Lunn }
134dc30c35bSAndrew Lunn 
135dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_unmask(struct irq_data *d)
136dc30c35bSAndrew Lunn {
137dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
138dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
139dc30c35bSAndrew Lunn 
140dc30c35bSAndrew Lunn 	chip->g1_irq.masked &= ~(1 << n);
141dc30c35bSAndrew Lunn }
142dc30c35bSAndrew Lunn 
143294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip)
144dc30c35bSAndrew Lunn {
145dc30c35bSAndrew Lunn 	unsigned int nhandled = 0;
146dc30c35bSAndrew Lunn 	unsigned int sub_irq;
147dc30c35bSAndrew Lunn 	unsigned int n;
148dc30c35bSAndrew Lunn 	u16 reg;
1497c0db24cSJohn David Anglin 	u16 ctl1;
150dc30c35bSAndrew Lunn 	int err;
151dc30c35bSAndrew Lunn 
152c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
15382466921SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
154c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
155dc30c35bSAndrew Lunn 
156dc30c35bSAndrew Lunn 	if (err)
157dc30c35bSAndrew Lunn 		goto out;
158dc30c35bSAndrew Lunn 
1597c0db24cSJohn David Anglin 	do {
160dc30c35bSAndrew Lunn 		for (n = 0; n < chip->g1_irq.nirqs; ++n) {
161dc30c35bSAndrew Lunn 			if (reg & (1 << n)) {
1627c0db24cSJohn David Anglin 				sub_irq = irq_find_mapping(chip->g1_irq.domain,
1637c0db24cSJohn David Anglin 							   n);
164dc30c35bSAndrew Lunn 				handle_nested_irq(sub_irq);
165dc30c35bSAndrew Lunn 				++nhandled;
166dc30c35bSAndrew Lunn 			}
167dc30c35bSAndrew Lunn 		}
1687c0db24cSJohn David Anglin 
169c9acece0SRasmus Villemoes 		mv88e6xxx_reg_lock(chip);
1707c0db24cSJohn David Anglin 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1);
1717c0db24cSJohn David Anglin 		if (err)
1727c0db24cSJohn David Anglin 			goto unlock;
1737c0db24cSJohn David Anglin 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
1747c0db24cSJohn David Anglin unlock:
175c9acece0SRasmus Villemoes 		mv88e6xxx_reg_unlock(chip);
1767c0db24cSJohn David Anglin 		if (err)
1777c0db24cSJohn David Anglin 			goto out;
1787c0db24cSJohn David Anglin 		ctl1 &= GENMASK(chip->g1_irq.nirqs, 0);
1797c0db24cSJohn David Anglin 	} while (reg & ctl1);
1807c0db24cSJohn David Anglin 
181dc30c35bSAndrew Lunn out:
182dc30c35bSAndrew Lunn 	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
183dc30c35bSAndrew Lunn }
184dc30c35bSAndrew Lunn 
185294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
186294d711eSAndrew Lunn {
187294d711eSAndrew Lunn 	struct mv88e6xxx_chip *chip = dev_id;
188294d711eSAndrew Lunn 
189294d711eSAndrew Lunn 	return mv88e6xxx_g1_irq_thread_work(chip);
190294d711eSAndrew Lunn }
191294d711eSAndrew Lunn 
192dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
193dc30c35bSAndrew Lunn {
194dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
195dc30c35bSAndrew Lunn 
196c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
197dc30c35bSAndrew Lunn }
198dc30c35bSAndrew Lunn 
199dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
200dc30c35bSAndrew Lunn {
201dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
202dc30c35bSAndrew Lunn 	u16 mask = GENMASK(chip->g1_irq.nirqs, 0);
203dc30c35bSAndrew Lunn 	u16 reg;
204dc30c35bSAndrew Lunn 	int err;
205dc30c35bSAndrew Lunn 
206d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &reg);
207dc30c35bSAndrew Lunn 	if (err)
208dc30c35bSAndrew Lunn 		goto out;
209dc30c35bSAndrew Lunn 
210dc30c35bSAndrew Lunn 	reg &= ~mask;
211dc30c35bSAndrew Lunn 	reg |= (~chip->g1_irq.masked & mask);
212dc30c35bSAndrew Lunn 
213d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg);
214dc30c35bSAndrew Lunn 	if (err)
215dc30c35bSAndrew Lunn 		goto out;
216dc30c35bSAndrew Lunn 
217dc30c35bSAndrew Lunn out:
218c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
219dc30c35bSAndrew Lunn }
220dc30c35bSAndrew Lunn 
2216eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g1_irq_chip = {
222dc30c35bSAndrew Lunn 	.name			= "mv88e6xxx-g1",
223dc30c35bSAndrew Lunn 	.irq_mask		= mv88e6xxx_g1_irq_mask,
224dc30c35bSAndrew Lunn 	.irq_unmask		= mv88e6xxx_g1_irq_unmask,
225dc30c35bSAndrew Lunn 	.irq_bus_lock		= mv88e6xxx_g1_irq_bus_lock,
226dc30c35bSAndrew Lunn 	.irq_bus_sync_unlock	= mv88e6xxx_g1_irq_bus_sync_unlock,
227dc30c35bSAndrew Lunn };
228dc30c35bSAndrew Lunn 
229dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d,
230dc30c35bSAndrew Lunn 				       unsigned int irq,
231dc30c35bSAndrew Lunn 				       irq_hw_number_t hwirq)
232dc30c35bSAndrew Lunn {
233dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = d->host_data;
234dc30c35bSAndrew Lunn 
235dc30c35bSAndrew Lunn 	irq_set_chip_data(irq, d->host_data);
236dc30c35bSAndrew Lunn 	irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq);
237dc30c35bSAndrew Lunn 	irq_set_noprobe(irq);
238dc30c35bSAndrew Lunn 
239dc30c35bSAndrew Lunn 	return 0;
240dc30c35bSAndrew Lunn }
241dc30c35bSAndrew Lunn 
242dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = {
243dc30c35bSAndrew Lunn 	.map	= mv88e6xxx_g1_irq_domain_map,
244dc30c35bSAndrew Lunn 	.xlate	= irq_domain_xlate_twocell,
245dc30c35bSAndrew Lunn };
246dc30c35bSAndrew Lunn 
2473d82475aSUwe Kleine-König /* To be called with reg_lock held */
248294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip)
249dc30c35bSAndrew Lunn {
250dc30c35bSAndrew Lunn 	int irq, virq;
2513460a577SAndrew Lunn 	u16 mask;
2523460a577SAndrew Lunn 
253d77f4321SVivien Didelot 	mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
2543d5fdba1SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
255d77f4321SVivien Didelot 	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
2563460a577SAndrew Lunn 
2575edef2f2SAndreas Färber 	for (irq = 0; irq < chip->g1_irq.nirqs; irq++) {
258a3db3d3aSAndrew Lunn 		virq = irq_find_mapping(chip->g1_irq.domain, irq);
259dc30c35bSAndrew Lunn 		irq_dispose_mapping(virq);
260dc30c35bSAndrew Lunn 	}
261dc30c35bSAndrew Lunn 
262a3db3d3aSAndrew Lunn 	irq_domain_remove(chip->g1_irq.domain);
263dc30c35bSAndrew Lunn }
264dc30c35bSAndrew Lunn 
265294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
266294d711eSAndrew Lunn {
2673d82475aSUwe Kleine-König 	/*
2683d82475aSUwe Kleine-König 	 * free_irq must be called without reg_lock taken because the irq
2693d82475aSUwe Kleine-König 	 * handler takes this lock, too.
2703d82475aSUwe Kleine-König 	 */
271294d711eSAndrew Lunn 	free_irq(chip->irq, chip);
2723d82475aSUwe Kleine-König 
273c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2743d82475aSUwe Kleine-König 	mv88e6xxx_g1_irq_free_common(chip);
275c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
276294d711eSAndrew Lunn }
277294d711eSAndrew Lunn 
278294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip)
279dc30c35bSAndrew Lunn {
2803dd0ef05SAndrew Lunn 	int err, irq, virq;
2813dd0ef05SAndrew Lunn 	u16 reg, mask;
282dc30c35bSAndrew Lunn 
283dc30c35bSAndrew Lunn 	chip->g1_irq.nirqs = chip->info->g1_irqs;
284dc30c35bSAndrew Lunn 	chip->g1_irq.domain = irq_domain_add_simple(
285dc30c35bSAndrew Lunn 		NULL, chip->g1_irq.nirqs, 0,
286dc30c35bSAndrew Lunn 		&mv88e6xxx_g1_irq_domain_ops, chip);
287dc30c35bSAndrew Lunn 	if (!chip->g1_irq.domain)
288dc30c35bSAndrew Lunn 		return -ENOMEM;
289dc30c35bSAndrew Lunn 
290dc30c35bSAndrew Lunn 	for (irq = 0; irq < chip->g1_irq.nirqs; irq++)
291dc30c35bSAndrew Lunn 		irq_create_mapping(chip->g1_irq.domain, irq);
292dc30c35bSAndrew Lunn 
293dc30c35bSAndrew Lunn 	chip->g1_irq.chip = mv88e6xxx_g1_irq_chip;
294dc30c35bSAndrew Lunn 	chip->g1_irq.masked = ~0;
295dc30c35bSAndrew Lunn 
296d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
297dc30c35bSAndrew Lunn 	if (err)
2983dd0ef05SAndrew Lunn 		goto out_mapping;
299dc30c35bSAndrew Lunn 
3003dd0ef05SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
301dc30c35bSAndrew Lunn 
302d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
303dc30c35bSAndrew Lunn 	if (err)
3043dd0ef05SAndrew Lunn 		goto out_disable;
305dc30c35bSAndrew Lunn 
306dc30c35bSAndrew Lunn 	/* Reading the interrupt status clears (most of) them */
30782466921SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
308dc30c35bSAndrew Lunn 	if (err)
3093dd0ef05SAndrew Lunn 		goto out_disable;
310dc30c35bSAndrew Lunn 
311dc30c35bSAndrew Lunn 	return 0;
312dc30c35bSAndrew Lunn 
3133dd0ef05SAndrew Lunn out_disable:
3143d5fdba1SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
315d77f4321SVivien Didelot 	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
3163dd0ef05SAndrew Lunn 
3173dd0ef05SAndrew Lunn out_mapping:
3183dd0ef05SAndrew Lunn 	for (irq = 0; irq < 16; irq++) {
3193dd0ef05SAndrew Lunn 		virq = irq_find_mapping(chip->g1_irq.domain, irq);
3203dd0ef05SAndrew Lunn 		irq_dispose_mapping(virq);
3213dd0ef05SAndrew Lunn 	}
3223dd0ef05SAndrew Lunn 
3233dd0ef05SAndrew Lunn 	irq_domain_remove(chip->g1_irq.domain);
324dc30c35bSAndrew Lunn 
325dc30c35bSAndrew Lunn 	return err;
326dc30c35bSAndrew Lunn }
327dc30c35bSAndrew Lunn 
328294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
329294d711eSAndrew Lunn {
330f6d9758bSAndrew Lunn 	static struct lock_class_key lock_key;
331f6d9758bSAndrew Lunn 	static struct lock_class_key request_key;
332294d711eSAndrew Lunn 	int err;
333294d711eSAndrew Lunn 
334294d711eSAndrew Lunn 	err = mv88e6xxx_g1_irq_setup_common(chip);
335294d711eSAndrew Lunn 	if (err)
336294d711eSAndrew Lunn 		return err;
337294d711eSAndrew Lunn 
338f6d9758bSAndrew Lunn 	/* These lock classes tells lockdep that global 1 irqs are in
339f6d9758bSAndrew Lunn 	 * a different category than their parent GPIO, so it won't
340f6d9758bSAndrew Lunn 	 * report false recursion.
341f6d9758bSAndrew Lunn 	 */
342f6d9758bSAndrew Lunn 	irq_set_lockdep_class(chip->irq, &lock_key, &request_key);
343f6d9758bSAndrew Lunn 
3443095383aSAndrew Lunn 	snprintf(chip->irq_name, sizeof(chip->irq_name),
3453095383aSAndrew Lunn 		 "mv88e6xxx-%s", dev_name(chip->dev));
3463095383aSAndrew Lunn 
347c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
348294d711eSAndrew Lunn 	err = request_threaded_irq(chip->irq, NULL,
349294d711eSAndrew Lunn 				   mv88e6xxx_g1_irq_thread_fn,
3500340376eSMarek Behún 				   IRQF_ONESHOT | IRQF_SHARED,
3513095383aSAndrew Lunn 				   chip->irq_name, chip);
352c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
353294d711eSAndrew Lunn 	if (err)
354294d711eSAndrew Lunn 		mv88e6xxx_g1_irq_free_common(chip);
355294d711eSAndrew Lunn 
356294d711eSAndrew Lunn 	return err;
357294d711eSAndrew Lunn }
358294d711eSAndrew Lunn 
359294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work)
360294d711eSAndrew Lunn {
361294d711eSAndrew Lunn 	struct mv88e6xxx_chip *chip = container_of(work,
362294d711eSAndrew Lunn 						   struct mv88e6xxx_chip,
363294d711eSAndrew Lunn 						   irq_poll_work.work);
364294d711eSAndrew Lunn 	mv88e6xxx_g1_irq_thread_work(chip);
365294d711eSAndrew Lunn 
366294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
367294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
368294d711eSAndrew Lunn }
369294d711eSAndrew Lunn 
370294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip)
371294d711eSAndrew Lunn {
372294d711eSAndrew Lunn 	int err;
373294d711eSAndrew Lunn 
374294d711eSAndrew Lunn 	err = mv88e6xxx_g1_irq_setup_common(chip);
375294d711eSAndrew Lunn 	if (err)
376294d711eSAndrew Lunn 		return err;
377294d711eSAndrew Lunn 
378294d711eSAndrew Lunn 	kthread_init_delayed_work(&chip->irq_poll_work,
379294d711eSAndrew Lunn 				  mv88e6xxx_irq_poll);
380294d711eSAndrew Lunn 
3813f8b8696SFlorian Fainelli 	chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev));
382294d711eSAndrew Lunn 	if (IS_ERR(chip->kworker))
383294d711eSAndrew Lunn 		return PTR_ERR(chip->kworker);
384294d711eSAndrew Lunn 
385294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
386294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
387294d711eSAndrew Lunn 
388294d711eSAndrew Lunn 	return 0;
389294d711eSAndrew Lunn }
390294d711eSAndrew Lunn 
391294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip)
392294d711eSAndrew Lunn {
393294d711eSAndrew Lunn 	kthread_cancel_delayed_work_sync(&chip->irq_poll_work);
394294d711eSAndrew Lunn 	kthread_destroy_worker(chip->kworker);
3953d82475aSUwe Kleine-König 
396c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3973d82475aSUwe Kleine-König 	mv88e6xxx_g1_irq_free_common(chip);
398c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
399294d711eSAndrew Lunn }
400294d711eSAndrew Lunn 
40164d47d50SRussell King static int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip,
40264d47d50SRussell King 					   int port, phy_interface_t interface)
40364d47d50SRussell King {
40464d47d50SRussell King 	int err;
40564d47d50SRussell King 
40664d47d50SRussell King 	if (chip->info->ops->port_set_rgmii_delay) {
40764d47d50SRussell King 		err = chip->info->ops->port_set_rgmii_delay(chip, port,
40864d47d50SRussell King 							    interface);
40964d47d50SRussell King 		if (err && err != -EOPNOTSUPP)
41064d47d50SRussell King 			return err;
41164d47d50SRussell King 	}
41264d47d50SRussell King 
41364d47d50SRussell King 	if (chip->info->ops->port_set_cmode) {
41464d47d50SRussell King 		err = chip->info->ops->port_set_cmode(chip, port,
41564d47d50SRussell King 						      interface);
41664d47d50SRussell King 		if (err && err != -EOPNOTSUPP)
41764d47d50SRussell King 			return err;
41864d47d50SRussell King 	}
41964d47d50SRussell King 
42064d47d50SRussell King 	return 0;
42164d47d50SRussell King }
42264d47d50SRussell King 
423a5a6858bSRussell King static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
424a5a6858bSRussell King 				    int link, int speed, int duplex, int pause,
425d78343d2SVivien Didelot 				    phy_interface_t mode)
426d78343d2SVivien Didelot {
427d78343d2SVivien Didelot 	int err;
428d78343d2SVivien Didelot 
429d78343d2SVivien Didelot 	if (!chip->info->ops->port_set_link)
430d78343d2SVivien Didelot 		return 0;
431d78343d2SVivien Didelot 
432d78343d2SVivien Didelot 	/* Port's MAC control must not be changed unless the link is down */
43343c8e0aeSHubert Feurstein 	err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN);
434d78343d2SVivien Didelot 	if (err)
435d78343d2SVivien Didelot 		return err;
436d78343d2SVivien Didelot 
437f365c6f7SRussell King 	if (chip->info->ops->port_set_speed_duplex) {
438f365c6f7SRussell King 		err = chip->info->ops->port_set_speed_duplex(chip, port,
439f365c6f7SRussell King 							     speed, duplex);
440d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
441d78343d2SVivien Didelot 			goto restore_link;
442d78343d2SVivien Didelot 	}
443d78343d2SVivien Didelot 
4447cbbee05SAndrew Lunn 	if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode)
4457cbbee05SAndrew Lunn 		mode = chip->info->ops->port_max_speed_mode(port);
4467cbbee05SAndrew Lunn 
44754186b91SAndrew Lunn 	if (chip->info->ops->port_set_pause) {
44854186b91SAndrew Lunn 		err = chip->info->ops->port_set_pause(chip, port, pause);
44954186b91SAndrew Lunn 		if (err)
45054186b91SAndrew Lunn 			goto restore_link;
45154186b91SAndrew Lunn 	}
45254186b91SAndrew Lunn 
45364d47d50SRussell King 	err = mv88e6xxx_port_config_interface(chip, port, mode);
454d78343d2SVivien Didelot restore_link:
455d78343d2SVivien Didelot 	if (chip->info->ops->port_set_link(chip, port, link))
456774439e5SVivien Didelot 		dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
457d78343d2SVivien Didelot 
458d78343d2SVivien Didelot 	return err;
459d78343d2SVivien Didelot }
460d78343d2SVivien Didelot 
461d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
462d700ec41SMarek Vasut {
463d700ec41SMarek Vasut 	struct mv88e6xxx_chip *chip = ds->priv;
464d700ec41SMarek Vasut 
465d700ec41SMarek Vasut 	return port < chip->info->num_internal_phys;
466d700ec41SMarek Vasut }
467d700ec41SMarek Vasut 
4685d5b231dSRussell King static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port)
4695d5b231dSRussell King {
4705d5b231dSRussell King 	u16 reg;
4715d5b231dSRussell King 	int err;
4725d5b231dSRussell King 
4735d5b231dSRussell King 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
4745d5b231dSRussell King 	if (err) {
4755d5b231dSRussell King 		dev_err(chip->dev,
4765d5b231dSRussell King 			"p%d: %s: failed to read port status\n",
4775d5b231dSRussell King 			port, __func__);
4785d5b231dSRussell King 		return err;
4795d5b231dSRussell King 	}
4805d5b231dSRussell King 
4815d5b231dSRussell King 	return !!(reg & MV88E6XXX_PORT_STS_PHY_DETECT);
4825d5b231dSRussell King }
4835d5b231dSRussell King 
484a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port,
485a5a6858bSRussell King 					  struct phylink_link_state *state)
486a5a6858bSRussell King {
487a5a6858bSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
488a5a6858bSRussell King 	u8 lane;
489a5a6858bSRussell King 	int err;
490a5a6858bSRussell King 
491a5a6858bSRussell King 	mv88e6xxx_reg_lock(chip);
492a5a6858bSRussell King 	lane = mv88e6xxx_serdes_get_lane(chip, port);
493a5a6858bSRussell King 	if (lane && chip->info->ops->serdes_pcs_get_state)
494a5a6858bSRussell King 		err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
495a5a6858bSRussell King 							    state);
496a5a6858bSRussell King 	else
497a5a6858bSRussell King 		err = -EOPNOTSUPP;
498a5a6858bSRussell King 	mv88e6xxx_reg_unlock(chip);
499a5a6858bSRussell King 
500a5a6858bSRussell King 	return err;
501a5a6858bSRussell King }
502a5a6858bSRussell King 
503a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
504a5a6858bSRussell King 				       unsigned int mode,
505a5a6858bSRussell King 				       phy_interface_t interface,
506a5a6858bSRussell King 				       const unsigned long *advertise)
507a5a6858bSRussell King {
508a5a6858bSRussell King 	const struct mv88e6xxx_ops *ops = chip->info->ops;
509a5a6858bSRussell King 	u8 lane;
510a5a6858bSRussell King 
511a5a6858bSRussell King 	if (ops->serdes_pcs_config) {
512a5a6858bSRussell King 		lane = mv88e6xxx_serdes_get_lane(chip, port);
513a5a6858bSRussell King 		if (lane)
514a5a6858bSRussell King 			return ops->serdes_pcs_config(chip, port, lane, mode,
515a5a6858bSRussell King 						      interface, advertise);
516a5a6858bSRussell King 	}
517a5a6858bSRussell King 
518a5a6858bSRussell King 	return 0;
519a5a6858bSRussell King }
520a5a6858bSRussell King 
521a5a6858bSRussell King static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port)
522a5a6858bSRussell King {
523a5a6858bSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
524a5a6858bSRussell King 	const struct mv88e6xxx_ops *ops;
525a5a6858bSRussell King 	int err = 0;
526a5a6858bSRussell King 	u8 lane;
527a5a6858bSRussell King 
528a5a6858bSRussell King 	ops = chip->info->ops;
529a5a6858bSRussell King 
530a5a6858bSRussell King 	if (ops->serdes_pcs_an_restart) {
531a5a6858bSRussell King 		mv88e6xxx_reg_lock(chip);
532a5a6858bSRussell King 		lane = mv88e6xxx_serdes_get_lane(chip, port);
533a5a6858bSRussell King 		if (lane)
534a5a6858bSRussell King 			err = ops->serdes_pcs_an_restart(chip, port, lane);
535a5a6858bSRussell King 		mv88e6xxx_reg_unlock(chip);
536a5a6858bSRussell King 
537a5a6858bSRussell King 		if (err)
538a5a6858bSRussell King 			dev_err(ds->dev, "p%d: failed to restart AN\n", port);
539a5a6858bSRussell King 	}
540a5a6858bSRussell King }
541a5a6858bSRussell King 
542a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
543a5a6858bSRussell King 					unsigned int mode,
544a5a6858bSRussell King 					int speed, int duplex)
545a5a6858bSRussell King {
546a5a6858bSRussell King 	const struct mv88e6xxx_ops *ops = chip->info->ops;
547a5a6858bSRussell King 	u8 lane;
548a5a6858bSRussell King 
549a5a6858bSRussell King 	if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) {
550a5a6858bSRussell King 		lane = mv88e6xxx_serdes_get_lane(chip, port);
551a5a6858bSRussell King 		if (lane)
552a5a6858bSRussell King 			return ops->serdes_pcs_link_up(chip, port, lane,
553a5a6858bSRussell King 						       speed, duplex);
554a5a6858bSRussell King 	}
555a5a6858bSRussell King 
556a5a6858bSRussell King 	return 0;
557a5a6858bSRussell King }
558a5a6858bSRussell King 
5596c422e34SRussell King static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5606c422e34SRussell King 				       unsigned long *mask,
5616c422e34SRussell King 				       struct phylink_link_state *state)
5626c422e34SRussell King {
5636c422e34SRussell King 	if (!phy_interface_mode_is_8023z(state->interface)) {
5646c422e34SRussell King 		/* 10M and 100M are only supported in non-802.3z mode */
5656c422e34SRussell King 		phylink_set(mask, 10baseT_Half);
5666c422e34SRussell King 		phylink_set(mask, 10baseT_Full);
5676c422e34SRussell King 		phylink_set(mask, 100baseT_Half);
5686c422e34SRussell King 		phylink_set(mask, 100baseT_Full);
5696c422e34SRussell King 	}
5706c422e34SRussell King }
5716c422e34SRussell King 
5726c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5736c422e34SRussell King 				       unsigned long *mask,
5746c422e34SRussell King 				       struct phylink_link_state *state)
5756c422e34SRussell King {
5766c422e34SRussell King 	/* FIXME: if the port is in 1000Base-X mode, then it only supports
5776c422e34SRussell King 	 * 1000M FD speeds.  In this case, CMODE will indicate 5.
5786c422e34SRussell King 	 */
5796c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
5806c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
5816c422e34SRussell King 
5826c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
5836c422e34SRussell King }
5846c422e34SRussell King 
585e3af71a3SMarek Behún static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port,
586e3af71a3SMarek Behún 				       unsigned long *mask,
587e3af71a3SMarek Behún 				       struct phylink_link_state *state)
588e3af71a3SMarek Behún {
589e3af71a3SMarek Behún 	if (port >= 5)
590e3af71a3SMarek Behún 		phylink_set(mask, 2500baseX_Full);
591e3af71a3SMarek Behún 
592e3af71a3SMarek Behún 	/* No ethtool bits for 200Mbps */
593e3af71a3SMarek Behún 	phylink_set(mask, 1000baseT_Full);
594e3af71a3SMarek Behún 	phylink_set(mask, 1000baseX_Full);
595e3af71a3SMarek Behún 
596e3af71a3SMarek Behún 	mv88e6065_phylink_validate(chip, port, mask, state);
597e3af71a3SMarek Behún }
598e3af71a3SMarek Behún 
5996c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6006c422e34SRussell King 				       unsigned long *mask,
6016c422e34SRussell King 				       struct phylink_link_state *state)
6026c422e34SRussell King {
6036c422e34SRussell King 	/* No ethtool bits for 200Mbps */
6046c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
6056c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
6066c422e34SRussell King 
6076c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
6086c422e34SRussell King }
6096c422e34SRussell King 
6106c422e34SRussell King static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6116c422e34SRussell King 				       unsigned long *mask,
6126c422e34SRussell King 				       struct phylink_link_state *state)
6136c422e34SRussell King {
614ec26016bSAndrew Lunn 	if (port >= 9) {
6156c422e34SRussell King 		phylink_set(mask, 2500baseX_Full);
616ec26016bSAndrew Lunn 		phylink_set(mask, 2500baseT_Full);
617ec26016bSAndrew Lunn 	}
6186c422e34SRussell King 
6196c422e34SRussell King 	/* No ethtool bits for 200Mbps */
6206c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
6216c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
6226c422e34SRussell King 
6236c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
6246c422e34SRussell King }
6256c422e34SRussell King 
6266c422e34SRussell King static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6276c422e34SRussell King 					unsigned long *mask,
6286c422e34SRussell King 					struct phylink_link_state *state)
6296c422e34SRussell King {
6306c422e34SRussell King 	if (port >= 9) {
6316c422e34SRussell King 		phylink_set(mask, 10000baseT_Full);
6326c422e34SRussell King 		phylink_set(mask, 10000baseKR_Full);
6336c422e34SRussell King 	}
6346c422e34SRussell King 
6356c422e34SRussell King 	mv88e6390_phylink_validate(chip, port, mask, state);
6366c422e34SRussell King }
6376c422e34SRussell King 
638c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
639c9a2356fSRussell King 			       unsigned long *supported,
640c9a2356fSRussell King 			       struct phylink_link_state *state)
641c9a2356fSRussell King {
6426c422e34SRussell King 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
6436c422e34SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
6446c422e34SRussell King 
6456c422e34SRussell King 	/* Allow all the expected bits */
6466c422e34SRussell King 	phylink_set(mask, Autoneg);
6476c422e34SRussell King 	phylink_set(mask, Pause);
6486c422e34SRussell King 	phylink_set_port_modes(mask);
6496c422e34SRussell King 
6506c422e34SRussell King 	if (chip->info->ops->phylink_validate)
6516c422e34SRussell King 		chip->info->ops->phylink_validate(chip, port, mask, state);
6526c422e34SRussell King 
6536c422e34SRussell King 	bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
6546c422e34SRussell King 	bitmap_and(state->advertising, state->advertising, mask,
6556c422e34SRussell King 		   __ETHTOOL_LINK_MODE_MASK_NBITS);
6566c422e34SRussell King 
6576c422e34SRussell King 	/* We can only operate at 2500BaseX or 1000BaseX.  If requested
6586c422e34SRussell King 	 * to advertise both, only report advertising at 2500BaseX.
6596c422e34SRussell King 	 */
6606c422e34SRussell King 	phylink_helper_basex_speed(state);
661c9a2356fSRussell King }
662c9a2356fSRussell King 
663c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
664c9a2356fSRussell King 				 unsigned int mode,
665c9a2356fSRussell King 				 const struct phylink_link_state *state)
666c9a2356fSRussell King {
667c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
668fad58190SRussell King 	struct mv88e6xxx_port *p;
66964d47d50SRussell King 	int err;
670c9a2356fSRussell King 
671fad58190SRussell King 	p = &chip->ports[port];
672fad58190SRussell King 
67364d47d50SRussell King 	/* FIXME: is this the correct test? If we're in fixed mode on an
67464d47d50SRussell King 	 * internal port, why should we process this any different from
67564d47d50SRussell King 	 * PHY mode? On the other hand, the port may be automedia between
67664d47d50SRussell King 	 * an internal PHY and the serdes...
67764d47d50SRussell King 	 */
678d700ec41SMarek Vasut 	if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port))
679c9a2356fSRussell King 		return;
680c9a2356fSRussell King 
681c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
682fad58190SRussell King 	/* In inband mode, the link may come up at any time while the link
683fad58190SRussell King 	 * is not forced down. Force the link down while we reconfigure the
684fad58190SRussell King 	 * interface mode.
68564d47d50SRussell King 	 */
686fad58190SRussell King 	if (mode == MLO_AN_INBAND && p->interface != state->interface &&
687fad58190SRussell King 	    chip->info->ops->port_set_link)
688fad58190SRussell King 		chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN);
689fad58190SRussell King 
69064d47d50SRussell King 	err = mv88e6xxx_port_config_interface(chip, port, state->interface);
691a5a6858bSRussell King 	if (err && err != -EOPNOTSUPP)
692a5a6858bSRussell King 		goto err_unlock;
693a5a6858bSRussell King 
694a5a6858bSRussell King 	err = mv88e6xxx_serdes_pcs_config(chip, port, mode, state->interface,
695a5a6858bSRussell King 					  state->advertising);
696a5a6858bSRussell King 	/* FIXME: we should restart negotiation if something changed - which
697a5a6858bSRussell King 	 * is something we get if we convert to using phylinks PCS operations.
698a5a6858bSRussell King 	 */
699a5a6858bSRussell King 	if (err > 0)
700a5a6858bSRussell King 		err = 0;
701a5a6858bSRussell King 
702fad58190SRussell King 	/* Undo the forced down state above after completing configuration
703fad58190SRussell King 	 * irrespective of its state on entry, which allows the link to come up.
704fad58190SRussell King 	 */
705fad58190SRussell King 	if (mode == MLO_AN_INBAND && p->interface != state->interface &&
706fad58190SRussell King 	    chip->info->ops->port_set_link)
707fad58190SRussell King 		chip->info->ops->port_set_link(chip, port, LINK_UNFORCED);
708fad58190SRussell King 
709fad58190SRussell King 	p->interface = state->interface;
710fad58190SRussell King 
711a5a6858bSRussell King err_unlock:
712c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
713c9a2356fSRussell King 
714c9a2356fSRussell King 	if (err && err != -EOPNOTSUPP)
71564d47d50SRussell King 		dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port);
716c9a2356fSRussell King }
717c9a2356fSRussell King 
718c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
719c9a2356fSRussell King 				    unsigned int mode,
720c9a2356fSRussell King 				    phy_interface_t interface)
721c9a2356fSRussell King {
72230c4a5b0SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
72330c4a5b0SRussell King 	const struct mv88e6xxx_ops *ops;
72430c4a5b0SRussell King 	int err = 0;
72530c4a5b0SRussell King 
72630c4a5b0SRussell King 	ops = chip->info->ops;
72730c4a5b0SRussell King 
72830c4a5b0SRussell King 	mv88e6xxx_reg_lock(chip);
72934b5e6a3SAndrew Lunn 	if ((!mv88e6xxx_port_ppu_updates(chip, port) ||
73034b5e6a3SAndrew Lunn 	     mode == MLO_AN_FIXED) && ops->port_set_link)
73130c4a5b0SRussell King 		err = ops->port_set_link(chip, port, LINK_FORCED_DOWN);
73230c4a5b0SRussell King 	mv88e6xxx_reg_unlock(chip);
73330c4a5b0SRussell King 
73430c4a5b0SRussell King 	if (err)
73530c4a5b0SRussell King 		dev_err(chip->dev,
73630c4a5b0SRussell King 			"p%d: failed to force MAC link down\n", port);
73730c4a5b0SRussell King }
738c9a2356fSRussell King 
739c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
740c9a2356fSRussell King 				  unsigned int mode, phy_interface_t interface,
7415b502a7bSRussell King 				  struct phy_device *phydev,
7425b502a7bSRussell King 				  int speed, int duplex,
7435b502a7bSRussell King 				  bool tx_pause, bool rx_pause)
744c9a2356fSRussell King {
74530c4a5b0SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
74630c4a5b0SRussell King 	const struct mv88e6xxx_ops *ops;
74730c4a5b0SRussell King 	int err = 0;
74830c4a5b0SRussell King 
74930c4a5b0SRussell King 	ops = chip->info->ops;
75030c4a5b0SRussell King 
75130c4a5b0SRussell King 	mv88e6xxx_reg_lock(chip);
75234b5e6a3SAndrew Lunn 	if (!mv88e6xxx_port_ppu_updates(chip, port) || mode == MLO_AN_FIXED) {
75330c4a5b0SRussell King 		/* FIXME: for an automedia port, should we force the link
75430c4a5b0SRussell King 		 * down here - what if the link comes up due to "other" media
75530c4a5b0SRussell King 		 * while we're bringing the port up, how is the exclusivity
756a5a6858bSRussell King 		 * handled in the Marvell hardware? E.g. port 2 on 88E6390
75730c4a5b0SRussell King 		 * shared between internal PHY and Serdes.
75830c4a5b0SRussell King 		 */
759a5a6858bSRussell King 		err = mv88e6xxx_serdes_pcs_link_up(chip, port, mode, speed,
760a5a6858bSRussell King 						   duplex);
761a5a6858bSRussell King 		if (err)
762a5a6858bSRussell King 			goto error;
763a5a6858bSRussell King 
764f365c6f7SRussell King 		if (ops->port_set_speed_duplex) {
765f365c6f7SRussell King 			err = ops->port_set_speed_duplex(chip, port,
766f365c6f7SRussell King 							 speed, duplex);
76730c4a5b0SRussell King 			if (err && err != -EOPNOTSUPP)
76830c4a5b0SRussell King 				goto error;
76930c4a5b0SRussell King 		}
77030c4a5b0SRussell King 
77130c4a5b0SRussell King 		if (ops->port_set_link)
77230c4a5b0SRussell King 			err = ops->port_set_link(chip, port, LINK_FORCED_UP);
7735d5b231dSRussell King 	}
77430c4a5b0SRussell King error:
77530c4a5b0SRussell King 	mv88e6xxx_reg_unlock(chip);
77630c4a5b0SRussell King 
77730c4a5b0SRussell King 	if (err && err != -EOPNOTSUPP)
77830c4a5b0SRussell King 		dev_err(ds->dev,
77930c4a5b0SRussell King 			"p%d: failed to configure MAC link up\n", port);
78030c4a5b0SRussell King }
781c9a2356fSRussell King 
782a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
783fad09c73SVivien Didelot {
784a605a0feSAndrew Lunn 	if (!chip->info->ops->stats_snapshot)
785a605a0feSAndrew Lunn 		return -EOPNOTSUPP;
786fad09c73SVivien Didelot 
787a605a0feSAndrew Lunn 	return chip->info->ops->stats_snapshot(chip, port);
788fad09c73SVivien Didelot }
789fad09c73SVivien Didelot 
790fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
791dfafe449SAndrew Lunn 	{ "in_good_octets",		8, 0x00, STATS_TYPE_BANK0, },
792dfafe449SAndrew Lunn 	{ "in_bad_octets",		4, 0x02, STATS_TYPE_BANK0, },
793dfafe449SAndrew Lunn 	{ "in_unicast",			4, 0x04, STATS_TYPE_BANK0, },
794dfafe449SAndrew Lunn 	{ "in_broadcasts",		4, 0x06, STATS_TYPE_BANK0, },
795dfafe449SAndrew Lunn 	{ "in_multicasts",		4, 0x07, STATS_TYPE_BANK0, },
796dfafe449SAndrew Lunn 	{ "in_pause",			4, 0x16, STATS_TYPE_BANK0, },
797dfafe449SAndrew Lunn 	{ "in_undersize",		4, 0x18, STATS_TYPE_BANK0, },
798dfafe449SAndrew Lunn 	{ "in_fragments",		4, 0x19, STATS_TYPE_BANK0, },
799dfafe449SAndrew Lunn 	{ "in_oversize",		4, 0x1a, STATS_TYPE_BANK0, },
800dfafe449SAndrew Lunn 	{ "in_jabber",			4, 0x1b, STATS_TYPE_BANK0, },
801dfafe449SAndrew Lunn 	{ "in_rx_error",		4, 0x1c, STATS_TYPE_BANK0, },
802dfafe449SAndrew Lunn 	{ "in_fcs_error",		4, 0x1d, STATS_TYPE_BANK0, },
803dfafe449SAndrew Lunn 	{ "out_octets",			8, 0x0e, STATS_TYPE_BANK0, },
804dfafe449SAndrew Lunn 	{ "out_unicast",		4, 0x10, STATS_TYPE_BANK0, },
805dfafe449SAndrew Lunn 	{ "out_broadcasts",		4, 0x13, STATS_TYPE_BANK0, },
806dfafe449SAndrew Lunn 	{ "out_multicasts",		4, 0x12, STATS_TYPE_BANK0, },
807dfafe449SAndrew Lunn 	{ "out_pause",			4, 0x15, STATS_TYPE_BANK0, },
808dfafe449SAndrew Lunn 	{ "excessive",			4, 0x11, STATS_TYPE_BANK0, },
809dfafe449SAndrew Lunn 	{ "collisions",			4, 0x1e, STATS_TYPE_BANK0, },
810dfafe449SAndrew Lunn 	{ "deferred",			4, 0x05, STATS_TYPE_BANK0, },
811dfafe449SAndrew Lunn 	{ "single",			4, 0x14, STATS_TYPE_BANK0, },
812dfafe449SAndrew Lunn 	{ "multiple",			4, 0x17, STATS_TYPE_BANK0, },
813dfafe449SAndrew Lunn 	{ "out_fcs_error",		4, 0x03, STATS_TYPE_BANK0, },
814dfafe449SAndrew Lunn 	{ "late",			4, 0x1f, STATS_TYPE_BANK0, },
815dfafe449SAndrew Lunn 	{ "hist_64bytes",		4, 0x08, STATS_TYPE_BANK0, },
816dfafe449SAndrew Lunn 	{ "hist_65_127bytes",		4, 0x09, STATS_TYPE_BANK0, },
817dfafe449SAndrew Lunn 	{ "hist_128_255bytes",		4, 0x0a, STATS_TYPE_BANK0, },
818dfafe449SAndrew Lunn 	{ "hist_256_511bytes",		4, 0x0b, STATS_TYPE_BANK0, },
819dfafe449SAndrew Lunn 	{ "hist_512_1023bytes",		4, 0x0c, STATS_TYPE_BANK0, },
820dfafe449SAndrew Lunn 	{ "hist_1024_max_bytes",	4, 0x0d, STATS_TYPE_BANK0, },
821dfafe449SAndrew Lunn 	{ "sw_in_discards",		4, 0x10, STATS_TYPE_PORT, },
822dfafe449SAndrew Lunn 	{ "sw_in_filtered",		2, 0x12, STATS_TYPE_PORT, },
823dfafe449SAndrew Lunn 	{ "sw_out_filtered",		2, 0x13, STATS_TYPE_PORT, },
824dfafe449SAndrew Lunn 	{ "in_discards",		4, 0x00, STATS_TYPE_BANK1, },
825dfafe449SAndrew Lunn 	{ "in_filtered",		4, 0x01, STATS_TYPE_BANK1, },
826dfafe449SAndrew Lunn 	{ "in_accepted",		4, 0x02, STATS_TYPE_BANK1, },
827dfafe449SAndrew Lunn 	{ "in_bad_accepted",		4, 0x03, STATS_TYPE_BANK1, },
828dfafe449SAndrew Lunn 	{ "in_good_avb_class_a",	4, 0x04, STATS_TYPE_BANK1, },
829dfafe449SAndrew Lunn 	{ "in_good_avb_class_b",	4, 0x05, STATS_TYPE_BANK1, },
830dfafe449SAndrew Lunn 	{ "in_bad_avb_class_a",		4, 0x06, STATS_TYPE_BANK1, },
831dfafe449SAndrew Lunn 	{ "in_bad_avb_class_b",		4, 0x07, STATS_TYPE_BANK1, },
832dfafe449SAndrew Lunn 	{ "tcam_counter_0",		4, 0x08, STATS_TYPE_BANK1, },
833dfafe449SAndrew Lunn 	{ "tcam_counter_1",		4, 0x09, STATS_TYPE_BANK1, },
834dfafe449SAndrew Lunn 	{ "tcam_counter_2",		4, 0x0a, STATS_TYPE_BANK1, },
835dfafe449SAndrew Lunn 	{ "tcam_counter_3",		4, 0x0b, STATS_TYPE_BANK1, },
836dfafe449SAndrew Lunn 	{ "in_da_unknown",		4, 0x0e, STATS_TYPE_BANK1, },
837dfafe449SAndrew Lunn 	{ "in_management",		4, 0x0f, STATS_TYPE_BANK1, },
838dfafe449SAndrew Lunn 	{ "out_queue_0",		4, 0x10, STATS_TYPE_BANK1, },
839dfafe449SAndrew Lunn 	{ "out_queue_1",		4, 0x11, STATS_TYPE_BANK1, },
840dfafe449SAndrew Lunn 	{ "out_queue_2",		4, 0x12, STATS_TYPE_BANK1, },
841dfafe449SAndrew Lunn 	{ "out_queue_3",		4, 0x13, STATS_TYPE_BANK1, },
842dfafe449SAndrew Lunn 	{ "out_queue_4",		4, 0x14, STATS_TYPE_BANK1, },
843dfafe449SAndrew Lunn 	{ "out_queue_5",		4, 0x15, STATS_TYPE_BANK1, },
844dfafe449SAndrew Lunn 	{ "out_queue_6",		4, 0x16, STATS_TYPE_BANK1, },
845dfafe449SAndrew Lunn 	{ "out_queue_7",		4, 0x17, STATS_TYPE_BANK1, },
846dfafe449SAndrew Lunn 	{ "out_cut_through",		4, 0x18, STATS_TYPE_BANK1, },
847dfafe449SAndrew Lunn 	{ "out_octets_a",		4, 0x1a, STATS_TYPE_BANK1, },
848dfafe449SAndrew Lunn 	{ "out_octets_b",		4, 0x1b, STATS_TYPE_BANK1, },
849dfafe449SAndrew Lunn 	{ "out_management",		4, 0x1f, STATS_TYPE_BANK1, },
850fad09c73SVivien Didelot };
851fad09c73SVivien Didelot 
852fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
853fad09c73SVivien Didelot 					    struct mv88e6xxx_hw_stat *s,
854e0d8b615SAndrew Lunn 					    int port, u16 bank1_select,
855e0d8b615SAndrew Lunn 					    u16 histogram)
856fad09c73SVivien Didelot {
857fad09c73SVivien Didelot 	u32 low;
858fad09c73SVivien Didelot 	u32 high = 0;
859dfafe449SAndrew Lunn 	u16 reg = 0;
8600e7b9925SAndrew Lunn 	int err;
861fad09c73SVivien Didelot 	u64 value;
862fad09c73SVivien Didelot 
863fad09c73SVivien Didelot 	switch (s->type) {
864dfafe449SAndrew Lunn 	case STATS_TYPE_PORT:
8650e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
8660e7b9925SAndrew Lunn 		if (err)
8676c3442f5SJisheng Zhang 			return U64_MAX;
868fad09c73SVivien Didelot 
8690e7b9925SAndrew Lunn 		low = reg;
870cda9f4aaSAndrew Lunn 		if (s->size == 4) {
8710e7b9925SAndrew Lunn 			err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
8720e7b9925SAndrew Lunn 			if (err)
8736c3442f5SJisheng Zhang 				return U64_MAX;
87484b3fd1fSRasmus Villemoes 			low |= ((u32)reg) << 16;
875fad09c73SVivien Didelot 		}
876fad09c73SVivien Didelot 		break;
877dfafe449SAndrew Lunn 	case STATS_TYPE_BANK1:
878e0d8b615SAndrew Lunn 		reg = bank1_select;
879df561f66SGustavo A. R. Silva 		fallthrough;
880dfafe449SAndrew Lunn 	case STATS_TYPE_BANK0:
881e0d8b615SAndrew Lunn 		reg |= s->reg | histogram;
8827f9ef3afSAndrew Lunn 		mv88e6xxx_g1_stats_read(chip, reg, &low);
883cda9f4aaSAndrew Lunn 		if (s->size == 8)
8847f9ef3afSAndrew Lunn 			mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
8859fc3e4dcSGustavo A. R. Silva 		break;
8869fc3e4dcSGustavo A. R. Silva 	default:
8876c3442f5SJisheng Zhang 		return U64_MAX;
888fad09c73SVivien Didelot 	}
8896e46e2d8SAndrew Lunn 	value = (((u64)high) << 32) | low;
890fad09c73SVivien Didelot 	return value;
891fad09c73SVivien Didelot }
892fad09c73SVivien Didelot 
893436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
894dfafe449SAndrew Lunn 				       uint8_t *data, int types)
895fad09c73SVivien Didelot {
896fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
897fad09c73SVivien Didelot 	int i, j;
898fad09c73SVivien Didelot 
899fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
900fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
901dfafe449SAndrew Lunn 		if (stat->type & types) {
902fad09c73SVivien Didelot 			memcpy(data + j * ETH_GSTRING_LEN, stat->string,
903fad09c73SVivien Didelot 			       ETH_GSTRING_LEN);
904fad09c73SVivien Didelot 			j++;
905fad09c73SVivien Didelot 		}
906fad09c73SVivien Didelot 	}
907436fe17dSAndrew Lunn 
908436fe17dSAndrew Lunn 	return j;
909fad09c73SVivien Didelot }
910fad09c73SVivien Didelot 
911436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
912dfafe449SAndrew Lunn 				       uint8_t *data)
913dfafe449SAndrew Lunn {
914436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
915dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_PORT);
916dfafe449SAndrew Lunn }
917dfafe449SAndrew Lunn 
9181f71836fSRasmus Villemoes static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip,
9191f71836fSRasmus Villemoes 				       uint8_t *data)
9201f71836fSRasmus Villemoes {
9211f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0);
9221f71836fSRasmus Villemoes }
9231f71836fSRasmus Villemoes 
924436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
925dfafe449SAndrew Lunn 				       uint8_t *data)
926dfafe449SAndrew Lunn {
927436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
928dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
929dfafe449SAndrew Lunn }
930dfafe449SAndrew Lunn 
93165f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = {
93265f60e45SAndrew Lunn 	"atu_member_violation",
93365f60e45SAndrew Lunn 	"atu_miss_violation",
93465f60e45SAndrew Lunn 	"atu_full_violation",
93565f60e45SAndrew Lunn 	"vtu_member_violation",
93665f60e45SAndrew Lunn 	"vtu_miss_violation",
93765f60e45SAndrew Lunn };
93865f60e45SAndrew Lunn 
93965f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data)
94065f60e45SAndrew Lunn {
94165f60e45SAndrew Lunn 	unsigned int i;
94265f60e45SAndrew Lunn 
94365f60e45SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++)
94465f60e45SAndrew Lunn 		strlcpy(data + i * ETH_GSTRING_LEN,
94565f60e45SAndrew Lunn 			mv88e6xxx_atu_vtu_stats_strings[i],
94665f60e45SAndrew Lunn 			ETH_GSTRING_LEN);
94765f60e45SAndrew Lunn }
94865f60e45SAndrew Lunn 
949dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
95089f09048SFlorian Fainelli 				  u32 stringset, uint8_t *data)
951fad09c73SVivien Didelot {
95204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
953436fe17dSAndrew Lunn 	int count = 0;
954dfafe449SAndrew Lunn 
95589f09048SFlorian Fainelli 	if (stringset != ETH_SS_STATS)
95689f09048SFlorian Fainelli 		return;
95789f09048SFlorian Fainelli 
958c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
959c6c8cd5eSAndrew Lunn 
960dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_strings)
961436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_strings(chip, data);
962436fe17dSAndrew Lunn 
963436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_strings) {
964436fe17dSAndrew Lunn 		data += count * ETH_GSTRING_LEN;
96565f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_strings(chip, port, data);
966436fe17dSAndrew Lunn 	}
967c6c8cd5eSAndrew Lunn 
96865f60e45SAndrew Lunn 	data += count * ETH_GSTRING_LEN;
96965f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_strings(data);
97065f60e45SAndrew Lunn 
971c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
972dfafe449SAndrew Lunn }
973dfafe449SAndrew Lunn 
974dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
975dfafe449SAndrew Lunn 					  int types)
976dfafe449SAndrew Lunn {
977fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
978fad09c73SVivien Didelot 	int i, j;
979fad09c73SVivien Didelot 
980fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
981fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
982dfafe449SAndrew Lunn 		if (stat->type & types)
983fad09c73SVivien Didelot 			j++;
984fad09c73SVivien Didelot 	}
985fad09c73SVivien Didelot 	return j;
986fad09c73SVivien Didelot }
987fad09c73SVivien Didelot 
988dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
989dfafe449SAndrew Lunn {
990dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
991dfafe449SAndrew Lunn 					      STATS_TYPE_PORT);
992dfafe449SAndrew Lunn }
993dfafe449SAndrew Lunn 
9941f71836fSRasmus Villemoes static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip)
9951f71836fSRasmus Villemoes {
9961f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0);
9971f71836fSRasmus Villemoes }
9981f71836fSRasmus Villemoes 
999dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
1000dfafe449SAndrew Lunn {
1001dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
1002dfafe449SAndrew Lunn 					      STATS_TYPE_BANK1);
1003dfafe449SAndrew Lunn }
1004dfafe449SAndrew Lunn 
100589f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
1006dfafe449SAndrew Lunn {
1007dfafe449SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
1008436fe17dSAndrew Lunn 	int serdes_count = 0;
1009436fe17dSAndrew Lunn 	int count = 0;
1010dfafe449SAndrew Lunn 
101189f09048SFlorian Fainelli 	if (sset != ETH_SS_STATS)
101289f09048SFlorian Fainelli 		return 0;
101389f09048SFlorian Fainelli 
1014c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1015dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_sset_count)
1016436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_sset_count(chip);
1017436fe17dSAndrew Lunn 	if (count < 0)
1018436fe17dSAndrew Lunn 		goto out;
1019436fe17dSAndrew Lunn 
1020436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_sset_count)
1021436fe17dSAndrew Lunn 		serdes_count = chip->info->ops->serdes_get_sset_count(chip,
1022436fe17dSAndrew Lunn 								      port);
102365f60e45SAndrew Lunn 	if (serdes_count < 0) {
1024436fe17dSAndrew Lunn 		count = serdes_count;
102565f60e45SAndrew Lunn 		goto out;
102665f60e45SAndrew Lunn 	}
1027436fe17dSAndrew Lunn 	count += serdes_count;
102865f60e45SAndrew Lunn 	count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings);
102965f60e45SAndrew Lunn 
1030436fe17dSAndrew Lunn out:
1031c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1032dfafe449SAndrew Lunn 
1033436fe17dSAndrew Lunn 	return count;
1034dfafe449SAndrew Lunn }
1035dfafe449SAndrew Lunn 
1036436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1037e0d8b615SAndrew Lunn 				     uint64_t *data, int types,
1038e0d8b615SAndrew Lunn 				     u16 bank1_select, u16 histogram)
1039052f947fSAndrew Lunn {
1040052f947fSAndrew Lunn 	struct mv88e6xxx_hw_stat *stat;
1041052f947fSAndrew Lunn 	int i, j;
1042052f947fSAndrew Lunn 
1043052f947fSAndrew Lunn 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
1044052f947fSAndrew Lunn 		stat = &mv88e6xxx_hw_stats[i];
1045052f947fSAndrew Lunn 		if (stat->type & types) {
1046c9acece0SRasmus Villemoes 			mv88e6xxx_reg_lock(chip);
1047e0d8b615SAndrew Lunn 			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
1048e0d8b615SAndrew Lunn 							      bank1_select,
1049e0d8b615SAndrew Lunn 							      histogram);
1050c9acece0SRasmus Villemoes 			mv88e6xxx_reg_unlock(chip);
1051377cda13SAndrew Lunn 
1052052f947fSAndrew Lunn 			j++;
1053052f947fSAndrew Lunn 		}
1054052f947fSAndrew Lunn 	}
1055436fe17dSAndrew Lunn 	return j;
1056052f947fSAndrew Lunn }
1057052f947fSAndrew Lunn 
1058436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1059052f947fSAndrew Lunn 				     uint64_t *data)
1060052f947fSAndrew Lunn {
1061052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1062e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
106357d1ef38SVivien Didelot 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1064052f947fSAndrew Lunn }
1065052f947fSAndrew Lunn 
10661f71836fSRasmus Villemoes static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
10671f71836fSRasmus Villemoes 				     uint64_t *data)
10681f71836fSRasmus Villemoes {
10691f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0,
10701f71836fSRasmus Villemoes 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
10711f71836fSRasmus Villemoes }
10721f71836fSRasmus Villemoes 
1073436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1074052f947fSAndrew Lunn 				     uint64_t *data)
1075052f947fSAndrew Lunn {
1076052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1077e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
107857d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
107957d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1080e0d8b615SAndrew Lunn }
1081e0d8b615SAndrew Lunn 
1082436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1083e0d8b615SAndrew Lunn 				     uint64_t *data)
1084e0d8b615SAndrew Lunn {
1085e0d8b615SAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1086e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
108757d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
108857d1ef38SVivien Didelot 					 0);
1089052f947fSAndrew Lunn }
1090052f947fSAndrew Lunn 
109165f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
109265f60e45SAndrew Lunn 					uint64_t *data)
109365f60e45SAndrew Lunn {
109465f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_member_violation;
109565f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_miss_violation;
109665f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_full_violation;
109765f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_member_violation;
109865f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_miss_violation;
109965f60e45SAndrew Lunn }
110065f60e45SAndrew Lunn 
1101052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
1102052f947fSAndrew Lunn 				uint64_t *data)
1103052f947fSAndrew Lunn {
1104436fe17dSAndrew Lunn 	int count = 0;
1105436fe17dSAndrew Lunn 
1106052f947fSAndrew Lunn 	if (chip->info->ops->stats_get_stats)
1107436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_stats(chip, port, data);
1108436fe17dSAndrew Lunn 
1109c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1110436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_stats) {
1111436fe17dSAndrew Lunn 		data += count;
111265f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_stats(chip, port, data);
1113436fe17dSAndrew Lunn 	}
111465f60e45SAndrew Lunn 	data += count;
111565f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_stats(chip, port, data);
1116c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1117052f947fSAndrew Lunn }
1118052f947fSAndrew Lunn 
1119fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
1120fad09c73SVivien Didelot 					uint64_t *data)
1121fad09c73SVivien Didelot {
112204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1123fad09c73SVivien Didelot 	int ret;
1124fad09c73SVivien Didelot 
1125c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1126fad09c73SVivien Didelot 
1127a605a0feSAndrew Lunn 	ret = mv88e6xxx_stats_snapshot(chip, port);
1128c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1129377cda13SAndrew Lunn 
1130377cda13SAndrew Lunn 	if (ret < 0)
1131fad09c73SVivien Didelot 		return;
1132052f947fSAndrew Lunn 
1133052f947fSAndrew Lunn 	mv88e6xxx_get_stats(chip, port, data);
1134fad09c73SVivien Didelot 
1135fad09c73SVivien Didelot }
1136fad09c73SVivien Didelot 
1137fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
1138fad09c73SVivien Didelot {
11390d30bbd0SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
11400d30bbd0SAndrew Lunn 	int len;
11410d30bbd0SAndrew Lunn 
11420d30bbd0SAndrew Lunn 	len = 32 * sizeof(u16);
11430d30bbd0SAndrew Lunn 	if (chip->info->ops->serdes_get_regs_len)
11440d30bbd0SAndrew Lunn 		len += chip->info->ops->serdes_get_regs_len(chip, port);
11450d30bbd0SAndrew Lunn 
11460d30bbd0SAndrew Lunn 	return len;
1147fad09c73SVivien Didelot }
1148fad09c73SVivien Didelot 
1149fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
1150fad09c73SVivien Didelot 			       struct ethtool_regs *regs, void *_p)
1151fad09c73SVivien Didelot {
115204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
11530e7b9925SAndrew Lunn 	int err;
11540e7b9925SAndrew Lunn 	u16 reg;
1155fad09c73SVivien Didelot 	u16 *p = _p;
1156fad09c73SVivien Didelot 	int i;
1157fad09c73SVivien Didelot 
1158a5f39326SVivien Didelot 	regs->version = chip->info->prod_num;
1159fad09c73SVivien Didelot 
1160fad09c73SVivien Didelot 	memset(p, 0xff, 32 * sizeof(u16));
1161fad09c73SVivien Didelot 
1162c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1163fad09c73SVivien Didelot 
1164fad09c73SVivien Didelot 	for (i = 0; i < 32; i++) {
1165fad09c73SVivien Didelot 
11660e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, i, &reg);
11670e7b9925SAndrew Lunn 		if (!err)
11680e7b9925SAndrew Lunn 			p[i] = reg;
1169fad09c73SVivien Didelot 	}
1170fad09c73SVivien Didelot 
11710d30bbd0SAndrew Lunn 	if (chip->info->ops->serdes_get_regs)
11720d30bbd0SAndrew Lunn 		chip->info->ops->serdes_get_regs(chip, port, &p[i]);
11730d30bbd0SAndrew Lunn 
1174c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1175fad09c73SVivien Didelot }
1176fad09c73SVivien Didelot 
117708f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
1178fad09c73SVivien Didelot 				 struct ethtool_eee *e)
1179fad09c73SVivien Didelot {
11805480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
11815480db69SVivien Didelot 	return 0;
1182fad09c73SVivien Didelot }
1183fad09c73SVivien Didelot 
118408f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port,
118546587e4aSVivien Didelot 				 struct ethtool_eee *e)
1186fad09c73SVivien Didelot {
11875480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
11885480db69SVivien Didelot 	return 0;
1189fad09c73SVivien Didelot }
1190fad09c73SVivien Didelot 
11919dc8b13eSVivien Didelot /* Mask of the local ports allowed to receive frames from a given fabric port */
1192e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
1193fad09c73SVivien Didelot {
11949dc8b13eSVivien Didelot 	struct dsa_switch *ds = chip->ds;
11959dc8b13eSVivien Didelot 	struct dsa_switch_tree *dst = ds->dst;
1196e5887a2aSVivien Didelot 	struct net_device *br;
11979dc8b13eSVivien Didelot 	struct dsa_port *dp;
11989dc8b13eSVivien Didelot 	bool found = false;
1199e5887a2aSVivien Didelot 	u16 pvlan;
1200fad09c73SVivien Didelot 
12019dc8b13eSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list) {
12029dc8b13eSVivien Didelot 		if (dp->ds->index == dev && dp->index == port) {
12039dc8b13eSVivien Didelot 			found = true;
12049dc8b13eSVivien Didelot 			break;
12059dc8b13eSVivien Didelot 		}
12069dc8b13eSVivien Didelot 	}
1207fad09c73SVivien Didelot 
1208e5887a2aSVivien Didelot 	/* Prevent frames from unknown switch or port */
12099dc8b13eSVivien Didelot 	if (!found)
1210e5887a2aSVivien Didelot 		return 0;
1211e5887a2aSVivien Didelot 
1212e5887a2aSVivien Didelot 	/* Frames from DSA links and CPU ports can egress any local port */
12139dc8b13eSVivien Didelot 	if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA)
1214e5887a2aSVivien Didelot 		return mv88e6xxx_port_mask(chip);
1215e5887a2aSVivien Didelot 
12169dc8b13eSVivien Didelot 	br = dp->bridge_dev;
1217e5887a2aSVivien Didelot 	pvlan = 0;
1218e5887a2aSVivien Didelot 
1219e5887a2aSVivien Didelot 	/* Frames from user ports can egress any local DSA links and CPU ports,
1220e5887a2aSVivien Didelot 	 * as well as any local member of their bridge group.
1221e5887a2aSVivien Didelot 	 */
12229dc8b13eSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list)
12239dc8b13eSVivien Didelot 		if (dp->ds == ds &&
12249dc8b13eSVivien Didelot 		    (dp->type == DSA_PORT_TYPE_CPU ||
12259dc8b13eSVivien Didelot 		     dp->type == DSA_PORT_TYPE_DSA ||
12269dc8b13eSVivien Didelot 		     (br && dp->bridge_dev == br)))
12279dc8b13eSVivien Didelot 			pvlan |= BIT(dp->index);
1228e5887a2aSVivien Didelot 
1229e5887a2aSVivien Didelot 	return pvlan;
1230fad09c73SVivien Didelot }
1231e5887a2aSVivien Didelot 
1232240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port)
1233e5887a2aSVivien Didelot {
1234e5887a2aSVivien Didelot 	u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port);
1235fad09c73SVivien Didelot 
1236fad09c73SVivien Didelot 	/* prevent frames from going back out of the port they came in on */
1237fad09c73SVivien Didelot 	output_ports &= ~BIT(port);
1238fad09c73SVivien Didelot 
12395a7921f4SVivien Didelot 	return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
1240fad09c73SVivien Didelot }
1241fad09c73SVivien Didelot 
1242fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
1243fad09c73SVivien Didelot 					 u8 state)
1244fad09c73SVivien Didelot {
124504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1246fad09c73SVivien Didelot 	int err;
1247fad09c73SVivien Didelot 
1248c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1249f894c29cSVivien Didelot 	err = mv88e6xxx_port_set_state(chip, port, state);
1250c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1251fad09c73SVivien Didelot 
1252fad09c73SVivien Didelot 	if (err)
1253774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to update state\n", port);
1254fad09c73SVivien Didelot }
1255fad09c73SVivien Didelot 
125693e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip)
125793e18d61SVivien Didelot {
125893e18d61SVivien Didelot 	int err;
125993e18d61SVivien Didelot 
126093e18d61SVivien Didelot 	if (chip->info->ops->ieee_pri_map) {
126193e18d61SVivien Didelot 		err = chip->info->ops->ieee_pri_map(chip);
126293e18d61SVivien Didelot 		if (err)
126393e18d61SVivien Didelot 			return err;
126493e18d61SVivien Didelot 	}
126593e18d61SVivien Didelot 
126693e18d61SVivien Didelot 	if (chip->info->ops->ip_pri_map) {
126793e18d61SVivien Didelot 		err = chip->info->ops->ip_pri_map(chip);
126893e18d61SVivien Didelot 		if (err)
126993e18d61SVivien Didelot 			return err;
127093e18d61SVivien Didelot 	}
127193e18d61SVivien Didelot 
127293e18d61SVivien Didelot 	return 0;
127393e18d61SVivien Didelot }
127493e18d61SVivien Didelot 
1275c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
1276c7f047b6SVivien Didelot {
1277c5f51765SVivien Didelot 	struct dsa_switch *ds = chip->ds;
1278c7f047b6SVivien Didelot 	int target, port;
1279c7f047b6SVivien Didelot 	int err;
1280c7f047b6SVivien Didelot 
1281c7f047b6SVivien Didelot 	if (!chip->info->global2_addr)
1282c7f047b6SVivien Didelot 		return 0;
1283c7f047b6SVivien Didelot 
1284c7f047b6SVivien Didelot 	/* Initialize the routing port to the 32 possible target devices */
1285c7f047b6SVivien Didelot 	for (target = 0; target < 32; target++) {
1286c5f51765SVivien Didelot 		port = dsa_routing_port(ds, target);
1287c5f51765SVivien Didelot 		if (port == ds->num_ports)
1288c7f047b6SVivien Didelot 			port = 0x1f;
1289c7f047b6SVivien Didelot 
1290c7f047b6SVivien Didelot 		err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
1291c7f047b6SVivien Didelot 		if (err)
1292c7f047b6SVivien Didelot 			return err;
1293c7f047b6SVivien Didelot 	}
1294c7f047b6SVivien Didelot 
129502317e68SVivien Didelot 	if (chip->info->ops->set_cascade_port) {
129602317e68SVivien Didelot 		port = MV88E6XXX_CASCADE_PORT_MULTIPLE;
129702317e68SVivien Didelot 		err = chip->info->ops->set_cascade_port(chip, port);
129802317e68SVivien Didelot 		if (err)
129902317e68SVivien Didelot 			return err;
130002317e68SVivien Didelot 	}
130102317e68SVivien Didelot 
130223c98919SVivien Didelot 	err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index);
130323c98919SVivien Didelot 	if (err)
130423c98919SVivien Didelot 		return err;
130523c98919SVivien Didelot 
1306c7f047b6SVivien Didelot 	return 0;
1307c7f047b6SVivien Didelot }
1308c7f047b6SVivien Didelot 
1309b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip)
1310b28f872dSVivien Didelot {
1311b28f872dSVivien Didelot 	/* Clear all trunk masks and mapping */
1312b28f872dSVivien Didelot 	if (chip->info->global2_addr)
1313b28f872dSVivien Didelot 		return mv88e6xxx_g2_trunk_clear(chip);
1314b28f872dSVivien Didelot 
1315b28f872dSVivien Didelot 	return 0;
1316b28f872dSVivien Didelot }
1317b28f872dSVivien Didelot 
13189e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
13199e5baf9bSVivien Didelot {
13209e5baf9bSVivien Didelot 	if (chip->info->ops->rmu_disable)
13219e5baf9bSVivien Didelot 		return chip->info->ops->rmu_disable(chip);
13229e5baf9bSVivien Didelot 
13239e5baf9bSVivien Didelot 	return 0;
13249e5baf9bSVivien Didelot }
13259e5baf9bSVivien Didelot 
13269e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
13279e907d73SVivien Didelot {
13289e907d73SVivien Didelot 	if (chip->info->ops->pot_clear)
13299e907d73SVivien Didelot 		return chip->info->ops->pot_clear(chip);
13309e907d73SVivien Didelot 
13319e907d73SVivien Didelot 	return 0;
13329e907d73SVivien Didelot }
13339e907d73SVivien Didelot 
133451c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip)
133551c901a7SVivien Didelot {
133651c901a7SVivien Didelot 	if (chip->info->ops->mgmt_rsvd2cpu)
133751c901a7SVivien Didelot 		return chip->info->ops->mgmt_rsvd2cpu(chip);
133851c901a7SVivien Didelot 
133951c901a7SVivien Didelot 	return 0;
134051c901a7SVivien Didelot }
134151c901a7SVivien Didelot 
1342a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
1343a2ac29d2SVivien Didelot {
1344c3a7d4adSVivien Didelot 	int err;
1345c3a7d4adSVivien Didelot 
1346daefc943SVivien Didelot 	err = mv88e6xxx_g1_atu_flush(chip, 0, true);
1347daefc943SVivien Didelot 	if (err)
1348daefc943SVivien Didelot 		return err;
1349daefc943SVivien Didelot 
1350c3a7d4adSVivien Didelot 	err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
1351c3a7d4adSVivien Didelot 	if (err)
1352c3a7d4adSVivien Didelot 		return err;
1353c3a7d4adSVivien Didelot 
1354a2ac29d2SVivien Didelot 	return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
1355a2ac29d2SVivien Didelot }
1356a2ac29d2SVivien Didelot 
1357cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip)
1358cd8da8bbSVivien Didelot {
1359cd8da8bbSVivien Didelot 	int port;
1360cd8da8bbSVivien Didelot 	int err;
1361cd8da8bbSVivien Didelot 
1362cd8da8bbSVivien Didelot 	if (!chip->info->ops->irl_init_all)
1363cd8da8bbSVivien Didelot 		return 0;
1364cd8da8bbSVivien Didelot 
1365cd8da8bbSVivien Didelot 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
1366cd8da8bbSVivien Didelot 		/* Disable ingress rate limiting by resetting all per port
1367cd8da8bbSVivien Didelot 		 * ingress rate limit resources to their initial state.
1368cd8da8bbSVivien Didelot 		 */
1369cd8da8bbSVivien Didelot 		err = chip->info->ops->irl_init_all(chip, port);
1370cd8da8bbSVivien Didelot 		if (err)
1371cd8da8bbSVivien Didelot 			return err;
1372cd8da8bbSVivien Didelot 	}
1373cd8da8bbSVivien Didelot 
1374cd8da8bbSVivien Didelot 	return 0;
1375cd8da8bbSVivien Didelot }
1376cd8da8bbSVivien Didelot 
137704a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip)
137804a69a17SVivien Didelot {
137904a69a17SVivien Didelot 	if (chip->info->ops->set_switch_mac) {
138004a69a17SVivien Didelot 		u8 addr[ETH_ALEN];
138104a69a17SVivien Didelot 
138204a69a17SVivien Didelot 		eth_random_addr(addr);
138304a69a17SVivien Didelot 
138404a69a17SVivien Didelot 		return chip->info->ops->set_switch_mac(chip, addr);
138504a69a17SVivien Didelot 	}
138604a69a17SVivien Didelot 
138704a69a17SVivien Didelot 	return 0;
138804a69a17SVivien Didelot }
138904a69a17SVivien Didelot 
139017a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
139117a1594eSVivien Didelot {
139217a1594eSVivien Didelot 	u16 pvlan = 0;
139317a1594eSVivien Didelot 
139417a1594eSVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
1395d14939beSVivien Didelot 		return 0;
139617a1594eSVivien Didelot 
139717a1594eSVivien Didelot 	/* Skip the local source device, which uses in-chip port VLAN */
139817a1594eSVivien Didelot 	if (dev != chip->ds->index)
1399aec5ac88SVivien Didelot 		pvlan = mv88e6xxx_port_vlan(chip, dev, port);
140017a1594eSVivien Didelot 
140117a1594eSVivien Didelot 	return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
140217a1594eSVivien Didelot }
140317a1594eSVivien Didelot 
140481228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
140581228996SVivien Didelot {
140617a1594eSVivien Didelot 	int dev, port;
140717a1594eSVivien Didelot 	int err;
140817a1594eSVivien Didelot 
140981228996SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
141081228996SVivien Didelot 		return 0;
141181228996SVivien Didelot 
141281228996SVivien Didelot 	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
141381228996SVivien Didelot 	 * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
141481228996SVivien Didelot 	 */
141517a1594eSVivien Didelot 	err = mv88e6xxx_g2_misc_4_bit_port(chip);
141617a1594eSVivien Didelot 	if (err)
141717a1594eSVivien Didelot 		return err;
141817a1594eSVivien Didelot 
141917a1594eSVivien Didelot 	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) {
142017a1594eSVivien Didelot 		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) {
142117a1594eSVivien Didelot 			err = mv88e6xxx_pvt_map(chip, dev, port);
142217a1594eSVivien Didelot 			if (err)
142317a1594eSVivien Didelot 				return err;
142417a1594eSVivien Didelot 		}
142517a1594eSVivien Didelot 	}
142617a1594eSVivien Didelot 
142717a1594eSVivien Didelot 	return 0;
142881228996SVivien Didelot }
142981228996SVivien Didelot 
1430749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
1431749efcb8SVivien Didelot {
1432749efcb8SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1433749efcb8SVivien Didelot 	int err;
1434749efcb8SVivien Didelot 
1435c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1436e606ca36SVivien Didelot 	err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
1437c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1438749efcb8SVivien Didelot 
1439749efcb8SVivien Didelot 	if (err)
1440774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to flush ATU\n", port);
1441749efcb8SVivien Didelot }
1442749efcb8SVivien Didelot 
1443b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)
1444b486d7c9SVivien Didelot {
1445b486d7c9SVivien Didelot 	if (!chip->info->max_vid)
1446b486d7c9SVivien Didelot 		return 0;
1447b486d7c9SVivien Didelot 
1448b486d7c9SVivien Didelot 	return mv88e6xxx_g1_vtu_flush(chip);
1449b486d7c9SVivien Didelot }
1450b486d7c9SVivien Didelot 
1451f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,
1452f1394b78SVivien Didelot 				 struct mv88e6xxx_vtu_entry *entry)
1453f1394b78SVivien Didelot {
1454f1394b78SVivien Didelot 	if (!chip->info->ops->vtu_getnext)
1455f1394b78SVivien Didelot 		return -EOPNOTSUPP;
1456f1394b78SVivien Didelot 
1457f1394b78SVivien Didelot 	return chip->info->ops->vtu_getnext(chip, entry);
1458f1394b78SVivien Didelot }
1459f1394b78SVivien Didelot 
14600ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
14610ad5daf6SVivien Didelot 				   struct mv88e6xxx_vtu_entry *entry)
14620ad5daf6SVivien Didelot {
14630ad5daf6SVivien Didelot 	if (!chip->info->ops->vtu_loadpurge)
14640ad5daf6SVivien Didelot 		return -EOPNOTSUPP;
14650ad5daf6SVivien Didelot 
14660ad5daf6SVivien Didelot 	return chip->info->ops->vtu_loadpurge(chip, entry);
14670ad5daf6SVivien Didelot }
14680ad5daf6SVivien Didelot 
146990b6dbdfSAndrew Lunn int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *fid_bitmap)
1470fad09c73SVivien Didelot {
1471425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1472fad09c73SVivien Didelot 	int i, err;
147390b6dbdfSAndrew Lunn 	u16 fid;
1474fad09c73SVivien Didelot 
1475fad09c73SVivien Didelot 	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
1476fad09c73SVivien Didelot 
1477fad09c73SVivien Didelot 	/* Set every FID bit used by the (un)bridged ports */
1478370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
147990b6dbdfSAndrew Lunn 		err = mv88e6xxx_port_get_fid(chip, i, &fid);
1480fad09c73SVivien Didelot 		if (err)
1481fad09c73SVivien Didelot 			return err;
1482fad09c73SVivien Didelot 
148390b6dbdfSAndrew Lunn 		set_bit(fid, fid_bitmap);
1484fad09c73SVivien Didelot 	}
1485fad09c73SVivien Didelot 
1486fad09c73SVivien Didelot 	/* Set every FID bit used by the VLAN entries */
1487425d2d37SVivien Didelot 	vlan.vid = chip->info->max_vid;
1488425d2d37SVivien Didelot 	vlan.valid = false;
1489425d2d37SVivien Didelot 
1490fad09c73SVivien Didelot 	do {
1491f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1492fad09c73SVivien Didelot 		if (err)
1493fad09c73SVivien Didelot 			return err;
1494fad09c73SVivien Didelot 
1495fad09c73SVivien Didelot 		if (!vlan.valid)
1496fad09c73SVivien Didelot 			break;
1497fad09c73SVivien Didelot 
1498fad09c73SVivien Didelot 		set_bit(vlan.fid, fid_bitmap);
14993cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
1500fad09c73SVivien Didelot 
150190b6dbdfSAndrew Lunn 	return 0;
150290b6dbdfSAndrew Lunn }
150390b6dbdfSAndrew Lunn 
150490b6dbdfSAndrew Lunn static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
150590b6dbdfSAndrew Lunn {
150690b6dbdfSAndrew Lunn 	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
150790b6dbdfSAndrew Lunn 	int err;
150890b6dbdfSAndrew Lunn 
150990b6dbdfSAndrew Lunn 	err = mv88e6xxx_fid_map(chip, fid_bitmap);
151090b6dbdfSAndrew Lunn 	if (err)
151190b6dbdfSAndrew Lunn 		return err;
151290b6dbdfSAndrew Lunn 
1513fad09c73SVivien Didelot 	/* The reset value 0x000 is used to indicate that multiple address
1514fad09c73SVivien Didelot 	 * databases are not needed. Return the next positive available.
1515fad09c73SVivien Didelot 	 */
1516fad09c73SVivien Didelot 	*fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1);
1517fad09c73SVivien Didelot 	if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
1518fad09c73SVivien Didelot 		return -ENOSPC;
1519fad09c73SVivien Didelot 
1520fad09c73SVivien Didelot 	/* Clear the database */
1521daefc943SVivien Didelot 	return mv88e6xxx_g1_atu_flush(chip, *fid, true);
1522fad09c73SVivien Didelot }
1523fad09c73SVivien Didelot 
1524fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
1525fad09c73SVivien Didelot 					u16 vid_begin, u16 vid_end)
1526fad09c73SVivien Didelot {
152704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1528425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1529fad09c73SVivien Didelot 	int i, err;
1530fad09c73SVivien Didelot 
1531db06ae41SAndrew Lunn 	/* DSA and CPU ports have to be members of multiple vlans */
1532db06ae41SAndrew Lunn 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
1533db06ae41SAndrew Lunn 		return 0;
1534db06ae41SAndrew Lunn 
1535fad09c73SVivien Didelot 	if (!vid_begin)
1536fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1537fad09c73SVivien Didelot 
1538425d2d37SVivien Didelot 	vlan.vid = vid_begin - 1;
1539425d2d37SVivien Didelot 	vlan.valid = false;
1540425d2d37SVivien Didelot 
1541fad09c73SVivien Didelot 	do {
1542f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1543fad09c73SVivien Didelot 		if (err)
15447095a4c4SVivien Didelot 			return err;
1545fad09c73SVivien Didelot 
1546fad09c73SVivien Didelot 		if (!vlan.valid)
1547fad09c73SVivien Didelot 			break;
1548fad09c73SVivien Didelot 
1549fad09c73SVivien Didelot 		if (vlan.vid > vid_end)
1550fad09c73SVivien Didelot 			break;
1551fad09c73SVivien Didelot 
1552370b4ffbSVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1553fad09c73SVivien Didelot 			if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
1554fad09c73SVivien Didelot 				continue;
1555fad09c73SVivien Didelot 
155668bb8ea8SVivien Didelot 			if (!dsa_to_port(ds, i)->slave)
155766e2809dSAndrew Lunn 				continue;
155866e2809dSAndrew Lunn 
1559bd00e053SVivien Didelot 			if (vlan.member[i] ==
15607ec60d6eSVivien Didelot 			    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1561fad09c73SVivien Didelot 				continue;
1562fad09c73SVivien Didelot 
1563c8652c83SVivien Didelot 			if (dsa_to_port(ds, i)->bridge_dev ==
156468bb8ea8SVivien Didelot 			    dsa_to_port(ds, port)->bridge_dev)
1565fad09c73SVivien Didelot 				break; /* same bridge, check next VLAN */
1566fad09c73SVivien Didelot 
1567c8652c83SVivien Didelot 			if (!dsa_to_port(ds, i)->bridge_dev)
156866e2809dSAndrew Lunn 				continue;
156966e2809dSAndrew Lunn 
1570743fcc28SAndrew Lunn 			dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
1571743fcc28SAndrew Lunn 				port, vlan.vid, i,
1572c8652c83SVivien Didelot 				netdev_name(dsa_to_port(ds, i)->bridge_dev));
15737095a4c4SVivien Didelot 			return -EOPNOTSUPP;
1574fad09c73SVivien Didelot 		}
1575fad09c73SVivien Didelot 	} while (vlan.vid < vid_end);
1576fad09c73SVivien Didelot 
15777095a4c4SVivien Didelot 	return 0;
1578fad09c73SVivien Didelot }
1579fad09c73SVivien Didelot 
1580fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
1581fad09c73SVivien Didelot 					 bool vlan_filtering)
1582fad09c73SVivien Didelot {
158304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
158481c6edb2SVivien Didelot 	u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
158581c6edb2SVivien Didelot 		MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
15860e7b9925SAndrew Lunn 	int err;
1587fad09c73SVivien Didelot 
15883cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1589fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1590fad09c73SVivien Didelot 
1591c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1592385a0995SVivien Didelot 	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
1593c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1594fad09c73SVivien Didelot 
15950e7b9925SAndrew Lunn 	return err;
1596fad09c73SVivien Didelot }
1597fad09c73SVivien Didelot 
1598fad09c73SVivien Didelot static int
1599fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
160080e02360SVivien Didelot 			    const struct switchdev_obj_port_vlan *vlan)
1601fad09c73SVivien Didelot {
160204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1603fad09c73SVivien Didelot 	int err;
1604fad09c73SVivien Didelot 
16053cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1606fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1607fad09c73SVivien Didelot 
1608fad09c73SVivien Didelot 	/* If the requested port doesn't belong to the same bridge as the VLAN
1609fad09c73SVivien Didelot 	 * members, do not support it (yet) and fallback to software VLAN.
1610fad09c73SVivien Didelot 	 */
16117095a4c4SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1612fad09c73SVivien Didelot 	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
1613fad09c73SVivien Didelot 					   vlan->vid_end);
16147095a4c4SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1615fad09c73SVivien Didelot 
1616fad09c73SVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
1617fad09c73SVivien Didelot 	 * so skip the prepare phase.
1618fad09c73SVivien Didelot 	 */
16197095a4c4SVivien Didelot 	return err;
1620fad09c73SVivien Didelot }
1621fad09c73SVivien Didelot 
1622a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
1623a4c93ae1SAndrew Lunn 					const unsigned char *addr, u16 vid,
1624a4c93ae1SAndrew Lunn 					u8 state)
1625a4c93ae1SAndrew Lunn {
1626a4c93ae1SAndrew Lunn 	struct mv88e6xxx_atu_entry entry;
16275ef8d249SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
16285ef8d249SVivien Didelot 	u16 fid;
1629a4c93ae1SAndrew Lunn 	int err;
1630a4c93ae1SAndrew Lunn 
1631a4c93ae1SAndrew Lunn 	/* Null VLAN ID corresponds to the port private database */
16325ef8d249SVivien Didelot 	if (vid == 0) {
16335ef8d249SVivien Didelot 		err = mv88e6xxx_port_get_fid(chip, port, &fid);
1634a4c93ae1SAndrew Lunn 		if (err)
1635a4c93ae1SAndrew Lunn 			return err;
16365ef8d249SVivien Didelot 	} else {
16375ef8d249SVivien Didelot 		vlan.vid = vid - 1;
16385ef8d249SVivien Didelot 		vlan.valid = false;
16395ef8d249SVivien Didelot 
16405ef8d249SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
16415ef8d249SVivien Didelot 		if (err)
16425ef8d249SVivien Didelot 			return err;
16435ef8d249SVivien Didelot 
16445ef8d249SVivien Didelot 		/* switchdev expects -EOPNOTSUPP to honor software VLANs */
16455ef8d249SVivien Didelot 		if (vlan.vid != vid || !vlan.valid)
16465ef8d249SVivien Didelot 			return -EOPNOTSUPP;
16475ef8d249SVivien Didelot 
16485ef8d249SVivien Didelot 		fid = vlan.fid;
16495ef8d249SVivien Didelot 	}
1650a4c93ae1SAndrew Lunn 
1651d8291a95SVivien Didelot 	entry.state = 0;
1652a4c93ae1SAndrew Lunn 	ether_addr_copy(entry.mac, addr);
1653a4c93ae1SAndrew Lunn 	eth_addr_dec(entry.mac);
1654a4c93ae1SAndrew Lunn 
16555ef8d249SVivien Didelot 	err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry);
1656a4c93ae1SAndrew Lunn 	if (err)
1657a4c93ae1SAndrew Lunn 		return err;
1658a4c93ae1SAndrew Lunn 
1659a4c93ae1SAndrew Lunn 	/* Initialize a fresh ATU entry if it isn't found */
1660d8291a95SVivien Didelot 	if (!entry.state || !ether_addr_equal(entry.mac, addr)) {
1661a4c93ae1SAndrew Lunn 		memset(&entry, 0, sizeof(entry));
1662a4c93ae1SAndrew Lunn 		ether_addr_copy(entry.mac, addr);
1663a4c93ae1SAndrew Lunn 	}
1664a4c93ae1SAndrew Lunn 
1665a4c93ae1SAndrew Lunn 	/* Purge the ATU entry only if no port is using it anymore */
1666d8291a95SVivien Didelot 	if (!state) {
1667a4c93ae1SAndrew Lunn 		entry.portvec &= ~BIT(port);
1668a4c93ae1SAndrew Lunn 		if (!entry.portvec)
1669d8291a95SVivien Didelot 			entry.state = 0;
1670a4c93ae1SAndrew Lunn 	} else {
1671a4c93ae1SAndrew Lunn 		entry.portvec |= BIT(port);
1672a4c93ae1SAndrew Lunn 		entry.state = state;
1673a4c93ae1SAndrew Lunn 	}
1674a4c93ae1SAndrew Lunn 
16755ef8d249SVivien Didelot 	return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry);
1676a4c93ae1SAndrew Lunn }
1677a4c93ae1SAndrew Lunn 
1678da7dc875SVivien Didelot static int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port,
1679da7dc875SVivien Didelot 				  const struct mv88e6xxx_policy *policy)
1680da7dc875SVivien Didelot {
1681da7dc875SVivien Didelot 	enum mv88e6xxx_policy_mapping mapping = policy->mapping;
1682da7dc875SVivien Didelot 	enum mv88e6xxx_policy_action action = policy->action;
1683da7dc875SVivien Didelot 	const u8 *addr = policy->addr;
1684da7dc875SVivien Didelot 	u16 vid = policy->vid;
1685da7dc875SVivien Didelot 	u8 state;
1686da7dc875SVivien Didelot 	int err;
1687da7dc875SVivien Didelot 	int id;
1688da7dc875SVivien Didelot 
1689da7dc875SVivien Didelot 	if (!chip->info->ops->port_set_policy)
1690da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1691da7dc875SVivien Didelot 
1692da7dc875SVivien Didelot 	switch (mapping) {
1693da7dc875SVivien Didelot 	case MV88E6XXX_POLICY_MAPPING_DA:
1694da7dc875SVivien Didelot 	case MV88E6XXX_POLICY_MAPPING_SA:
1695da7dc875SVivien Didelot 		if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
1696da7dc875SVivien Didelot 			state = 0; /* Dissociate the port and address */
1697da7dc875SVivien Didelot 		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
1698da7dc875SVivien Didelot 			 is_multicast_ether_addr(addr))
1699da7dc875SVivien Didelot 			state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY;
1700da7dc875SVivien Didelot 		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
1701da7dc875SVivien Didelot 			 is_unicast_ether_addr(addr))
1702da7dc875SVivien Didelot 			state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY;
1703da7dc875SVivien Didelot 		else
1704da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1705da7dc875SVivien Didelot 
1706da7dc875SVivien Didelot 		err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
1707da7dc875SVivien Didelot 						   state);
1708da7dc875SVivien Didelot 		if (err)
1709da7dc875SVivien Didelot 			return err;
1710da7dc875SVivien Didelot 		break;
1711da7dc875SVivien Didelot 	default:
1712da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1713da7dc875SVivien Didelot 	}
1714da7dc875SVivien Didelot 
1715da7dc875SVivien Didelot 	/* Skip the port's policy clearing if the mapping is still in use */
1716da7dc875SVivien Didelot 	if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
1717da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1718da7dc875SVivien Didelot 			if (policy->port == port &&
1719da7dc875SVivien Didelot 			    policy->mapping == mapping &&
1720da7dc875SVivien Didelot 			    policy->action != action)
1721da7dc875SVivien Didelot 				return 0;
1722da7dc875SVivien Didelot 
1723da7dc875SVivien Didelot 	return chip->info->ops->port_set_policy(chip, port, mapping, action);
1724da7dc875SVivien Didelot }
1725da7dc875SVivien Didelot 
1726da7dc875SVivien Didelot static int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port,
1727da7dc875SVivien Didelot 				   struct ethtool_rx_flow_spec *fs)
1728da7dc875SVivien Didelot {
1729da7dc875SVivien Didelot 	struct ethhdr *mac_entry = &fs->h_u.ether_spec;
1730da7dc875SVivien Didelot 	struct ethhdr *mac_mask = &fs->m_u.ether_spec;
1731da7dc875SVivien Didelot 	enum mv88e6xxx_policy_mapping mapping;
1732da7dc875SVivien Didelot 	enum mv88e6xxx_policy_action action;
1733da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1734da7dc875SVivien Didelot 	u16 vid = 0;
1735da7dc875SVivien Didelot 	u8 *addr;
1736da7dc875SVivien Didelot 	int err;
1737da7dc875SVivien Didelot 	int id;
1738da7dc875SVivien Didelot 
1739da7dc875SVivien Didelot 	if (fs->location != RX_CLS_LOC_ANY)
1740da7dc875SVivien Didelot 		return -EINVAL;
1741da7dc875SVivien Didelot 
1742da7dc875SVivien Didelot 	if (fs->ring_cookie == RX_CLS_FLOW_DISC)
1743da7dc875SVivien Didelot 		action = MV88E6XXX_POLICY_ACTION_DISCARD;
1744da7dc875SVivien Didelot 	else
1745da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1746da7dc875SVivien Didelot 
1747da7dc875SVivien Didelot 	switch (fs->flow_type & ~FLOW_EXT) {
1748da7dc875SVivien Didelot 	case ETHER_FLOW:
1749da7dc875SVivien Didelot 		if (!is_zero_ether_addr(mac_mask->h_dest) &&
1750da7dc875SVivien Didelot 		    is_zero_ether_addr(mac_mask->h_source)) {
1751da7dc875SVivien Didelot 			mapping = MV88E6XXX_POLICY_MAPPING_DA;
1752da7dc875SVivien Didelot 			addr = mac_entry->h_dest;
1753da7dc875SVivien Didelot 		} else if (is_zero_ether_addr(mac_mask->h_dest) &&
1754da7dc875SVivien Didelot 		    !is_zero_ether_addr(mac_mask->h_source)) {
1755da7dc875SVivien Didelot 			mapping = MV88E6XXX_POLICY_MAPPING_SA;
1756da7dc875SVivien Didelot 			addr = mac_entry->h_source;
1757da7dc875SVivien Didelot 		} else {
1758da7dc875SVivien Didelot 			/* Cannot support DA and SA mapping in the same rule */
1759da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1760da7dc875SVivien Didelot 		}
1761da7dc875SVivien Didelot 		break;
1762da7dc875SVivien Didelot 	default:
1763da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1764da7dc875SVivien Didelot 	}
1765da7dc875SVivien Didelot 
1766da7dc875SVivien Didelot 	if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) {
176704844280SAndrew Lunn 		if (fs->m_ext.vlan_tci != htons(0xffff))
1768da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1769da7dc875SVivien Didelot 		vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK;
1770da7dc875SVivien Didelot 	}
1771da7dc875SVivien Didelot 
1772da7dc875SVivien Didelot 	idr_for_each_entry(&chip->policies, policy, id) {
1773da7dc875SVivien Didelot 		if (policy->port == port && policy->mapping == mapping &&
1774da7dc875SVivien Didelot 		    policy->action == action && policy->vid == vid &&
1775da7dc875SVivien Didelot 		    ether_addr_equal(policy->addr, addr))
1776da7dc875SVivien Didelot 			return -EEXIST;
1777da7dc875SVivien Didelot 	}
1778da7dc875SVivien Didelot 
1779da7dc875SVivien Didelot 	policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL);
1780da7dc875SVivien Didelot 	if (!policy)
1781da7dc875SVivien Didelot 		return -ENOMEM;
1782da7dc875SVivien Didelot 
1783da7dc875SVivien Didelot 	fs->location = 0;
1784da7dc875SVivien Didelot 	err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff,
1785da7dc875SVivien Didelot 			    GFP_KERNEL);
1786da7dc875SVivien Didelot 	if (err) {
1787da7dc875SVivien Didelot 		devm_kfree(chip->dev, policy);
1788da7dc875SVivien Didelot 		return err;
1789da7dc875SVivien Didelot 	}
1790da7dc875SVivien Didelot 
1791da7dc875SVivien Didelot 	memcpy(&policy->fs, fs, sizeof(*fs));
1792da7dc875SVivien Didelot 	ether_addr_copy(policy->addr, addr);
1793da7dc875SVivien Didelot 	policy->mapping = mapping;
1794da7dc875SVivien Didelot 	policy->action = action;
1795da7dc875SVivien Didelot 	policy->port = port;
1796da7dc875SVivien Didelot 	policy->vid = vid;
1797da7dc875SVivien Didelot 
1798da7dc875SVivien Didelot 	err = mv88e6xxx_policy_apply(chip, port, policy);
1799da7dc875SVivien Didelot 	if (err) {
1800da7dc875SVivien Didelot 		idr_remove(&chip->policies, fs->location);
1801da7dc875SVivien Didelot 		devm_kfree(chip->dev, policy);
1802da7dc875SVivien Didelot 		return err;
1803da7dc875SVivien Didelot 	}
1804da7dc875SVivien Didelot 
1805da7dc875SVivien Didelot 	return 0;
1806da7dc875SVivien Didelot }
1807da7dc875SVivien Didelot 
1808da7dc875SVivien Didelot static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,
1809da7dc875SVivien Didelot 			       struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
1810da7dc875SVivien Didelot {
1811da7dc875SVivien Didelot 	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
1812da7dc875SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1813da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1814da7dc875SVivien Didelot 	int err;
1815da7dc875SVivien Didelot 	int id;
1816da7dc875SVivien Didelot 
1817da7dc875SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1818da7dc875SVivien Didelot 
1819da7dc875SVivien Didelot 	switch (rxnfc->cmd) {
1820da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRLCNT:
1821da7dc875SVivien Didelot 		rxnfc->data = 0;
1822da7dc875SVivien Didelot 		rxnfc->data |= RX_CLS_LOC_SPECIAL;
1823da7dc875SVivien Didelot 		rxnfc->rule_cnt = 0;
1824da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1825da7dc875SVivien Didelot 			if (policy->port == port)
1826da7dc875SVivien Didelot 				rxnfc->rule_cnt++;
1827da7dc875SVivien Didelot 		err = 0;
1828da7dc875SVivien Didelot 		break;
1829da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRULE:
1830da7dc875SVivien Didelot 		err = -ENOENT;
1831da7dc875SVivien Didelot 		policy = idr_find(&chip->policies, fs->location);
1832da7dc875SVivien Didelot 		if (policy) {
1833da7dc875SVivien Didelot 			memcpy(fs, &policy->fs, sizeof(*fs));
1834da7dc875SVivien Didelot 			err = 0;
1835da7dc875SVivien Didelot 		}
1836da7dc875SVivien Didelot 		break;
1837da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRLALL:
1838da7dc875SVivien Didelot 		rxnfc->data = 0;
1839da7dc875SVivien Didelot 		rxnfc->rule_cnt = 0;
1840da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1841da7dc875SVivien Didelot 			if (policy->port == port)
1842da7dc875SVivien Didelot 				rule_locs[rxnfc->rule_cnt++] = id;
1843da7dc875SVivien Didelot 		err = 0;
1844da7dc875SVivien Didelot 		break;
1845da7dc875SVivien Didelot 	default:
1846da7dc875SVivien Didelot 		err = -EOPNOTSUPP;
1847da7dc875SVivien Didelot 		break;
1848da7dc875SVivien Didelot 	}
1849da7dc875SVivien Didelot 
1850da7dc875SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1851da7dc875SVivien Didelot 
1852da7dc875SVivien Didelot 	return err;
1853da7dc875SVivien Didelot }
1854da7dc875SVivien Didelot 
1855da7dc875SVivien Didelot static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port,
1856da7dc875SVivien Didelot 			       struct ethtool_rxnfc *rxnfc)
1857da7dc875SVivien Didelot {
1858da7dc875SVivien Didelot 	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
1859da7dc875SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1860da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1861da7dc875SVivien Didelot 	int err;
1862da7dc875SVivien Didelot 
1863da7dc875SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1864da7dc875SVivien Didelot 
1865da7dc875SVivien Didelot 	switch (rxnfc->cmd) {
1866da7dc875SVivien Didelot 	case ETHTOOL_SRXCLSRLINS:
1867da7dc875SVivien Didelot 		err = mv88e6xxx_policy_insert(chip, port, fs);
1868da7dc875SVivien Didelot 		break;
1869da7dc875SVivien Didelot 	case ETHTOOL_SRXCLSRLDEL:
1870da7dc875SVivien Didelot 		err = -ENOENT;
1871da7dc875SVivien Didelot 		policy = idr_remove(&chip->policies, fs->location);
1872da7dc875SVivien Didelot 		if (policy) {
1873da7dc875SVivien Didelot 			policy->action = MV88E6XXX_POLICY_ACTION_NORMAL;
1874da7dc875SVivien Didelot 			err = mv88e6xxx_policy_apply(chip, port, policy);
1875da7dc875SVivien Didelot 			devm_kfree(chip->dev, policy);
1876da7dc875SVivien Didelot 		}
1877da7dc875SVivien Didelot 		break;
1878da7dc875SVivien Didelot 	default:
1879da7dc875SVivien Didelot 		err = -EOPNOTSUPP;
1880da7dc875SVivien Didelot 		break;
1881da7dc875SVivien Didelot 	}
1882da7dc875SVivien Didelot 
1883da7dc875SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1884da7dc875SVivien Didelot 
1885da7dc875SVivien Didelot 	return err;
1886da7dc875SVivien Didelot }
1887da7dc875SVivien Didelot 
188887fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
188987fa886eSAndrew Lunn 					u16 vid)
189087fa886eSAndrew Lunn {
189187fa886eSAndrew Lunn 	const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
189287fa886eSAndrew Lunn 	u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
189387fa886eSAndrew Lunn 
189487fa886eSAndrew Lunn 	return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
189587fa886eSAndrew Lunn }
189687fa886eSAndrew Lunn 
189787fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
189887fa886eSAndrew Lunn {
189987fa886eSAndrew Lunn 	int port;
190087fa886eSAndrew Lunn 	int err;
190187fa886eSAndrew Lunn 
190287fa886eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
190387fa886eSAndrew Lunn 		err = mv88e6xxx_port_add_broadcast(chip, port, vid);
190487fa886eSAndrew Lunn 		if (err)
190587fa886eSAndrew Lunn 			return err;
190687fa886eSAndrew Lunn 	}
190787fa886eSAndrew Lunn 
190887fa886eSAndrew Lunn 	return 0;
190987fa886eSAndrew Lunn }
191087fa886eSAndrew Lunn 
1911b1ac6fb4SVivien Didelot static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port,
1912933b4425SRussell King 				    u16 vid, u8 member, bool warn)
1913fad09c73SVivien Didelot {
1914b1ac6fb4SVivien Didelot 	const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1915b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1916b1ac6fb4SVivien Didelot 	int i, err;
1917fad09c73SVivien Didelot 
1918b1ac6fb4SVivien Didelot 	if (!vid)
1919b1ac6fb4SVivien Didelot 		return -EOPNOTSUPP;
1920b1ac6fb4SVivien Didelot 
1921b1ac6fb4SVivien Didelot 	vlan.vid = vid - 1;
1922b1ac6fb4SVivien Didelot 	vlan.valid = false;
1923b1ac6fb4SVivien Didelot 
1924b1ac6fb4SVivien Didelot 	err = mv88e6xxx_vtu_getnext(chip, &vlan);
1925fad09c73SVivien Didelot 	if (err)
1926fad09c73SVivien Didelot 		return err;
1927fad09c73SVivien Didelot 
1928b1ac6fb4SVivien Didelot 	if (vlan.vid != vid || !vlan.valid) {
1929b1ac6fb4SVivien Didelot 		memset(&vlan, 0, sizeof(vlan));
1930b1ac6fb4SVivien Didelot 
1931b1ac6fb4SVivien Didelot 		err = mv88e6xxx_atu_new(chip, &vlan.fid);
1932b1ac6fb4SVivien Didelot 		if (err)
1933b1ac6fb4SVivien Didelot 			return err;
1934b1ac6fb4SVivien Didelot 
1935b1ac6fb4SVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
1936b1ac6fb4SVivien Didelot 			if (i == port)
1937b1ac6fb4SVivien Didelot 				vlan.member[i] = member;
1938b1ac6fb4SVivien Didelot 			else
1939b1ac6fb4SVivien Didelot 				vlan.member[i] = non_member;
1940b1ac6fb4SVivien Didelot 
1941b1ac6fb4SVivien Didelot 		vlan.vid = vid;
19421cb9dfcaSRasmus Villemoes 		vlan.valid = true;
1943fad09c73SVivien Didelot 
194487fa886eSAndrew Lunn 		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
194587fa886eSAndrew Lunn 		if (err)
194687fa886eSAndrew Lunn 			return err;
194787fa886eSAndrew Lunn 
1948b1ac6fb4SVivien Didelot 		err = mv88e6xxx_broadcast_setup(chip, vlan.vid);
1949b1ac6fb4SVivien Didelot 		if (err)
1950b1ac6fb4SVivien Didelot 			return err;
1951b1ac6fb4SVivien Didelot 	} else if (vlan.member[port] != member) {
1952b1ac6fb4SVivien Didelot 		vlan.member[port] = member;
1953b1ac6fb4SVivien Didelot 
1954b1ac6fb4SVivien Didelot 		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
1955b1ac6fb4SVivien Didelot 		if (err)
1956b1ac6fb4SVivien Didelot 			return err;
1957933b4425SRussell King 	} else if (warn) {
1958b1ac6fb4SVivien Didelot 		dev_info(chip->dev, "p%d: already a member of VLAN %d\n",
1959b1ac6fb4SVivien Didelot 			 port, vid);
1960b1ac6fb4SVivien Didelot 	}
1961b1ac6fb4SVivien Didelot 
1962b1ac6fb4SVivien Didelot 	return 0;
1963fad09c73SVivien Didelot }
1964fad09c73SVivien Didelot 
1965fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
196680e02360SVivien Didelot 				    const struct switchdev_obj_port_vlan *vlan)
1967fad09c73SVivien Didelot {
196804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1969fad09c73SVivien Didelot 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1970fad09c73SVivien Didelot 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1971933b4425SRussell King 	bool warn;
1972c91498e1SVivien Didelot 	u8 member;
1973fad09c73SVivien Didelot 	u16 vid;
1974fad09c73SVivien Didelot 
19753cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1976fad09c73SVivien Didelot 		return;
1977fad09c73SVivien Didelot 
1978c91498e1SVivien Didelot 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
19797ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED;
1980c91498e1SVivien Didelot 	else if (untagged)
19817ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED;
1982c91498e1SVivien Didelot 	else
19837ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
1984c91498e1SVivien Didelot 
1985933b4425SRussell King 	/* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port
1986933b4425SRussell King 	 * and then the CPU port. Do not warn for duplicates for the CPU port.
1987933b4425SRussell King 	 */
1988933b4425SRussell King 	warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port);
1989933b4425SRussell King 
1990c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1991fad09c73SVivien Didelot 
1992fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
1993933b4425SRussell King 		if (mv88e6xxx_port_vlan_join(chip, port, vid, member, warn))
1994774439e5SVivien Didelot 			dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
1995fad09c73SVivien Didelot 				vid, untagged ? 'u' : 't');
1996fad09c73SVivien Didelot 
199777064f37SVivien Didelot 	if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end))
1998774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to set PVID %d\n", port,
1999fad09c73SVivien Didelot 			vlan->vid_end);
2000fad09c73SVivien Didelot 
2001c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2002fad09c73SVivien Didelot }
2003fad09c73SVivien Didelot 
200452109892SVivien Didelot static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip,
2005fad09c73SVivien Didelot 				     int port, u16 vid)
2006fad09c73SVivien Didelot {
2007b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
2008fad09c73SVivien Didelot 	int i, err;
2009fad09c73SVivien Didelot 
201052109892SVivien Didelot 	if (!vid)
201152109892SVivien Didelot 		return -EOPNOTSUPP;
201252109892SVivien Didelot 
201352109892SVivien Didelot 	vlan.vid = vid - 1;
201452109892SVivien Didelot 	vlan.valid = false;
201552109892SVivien Didelot 
201652109892SVivien Didelot 	err = mv88e6xxx_vtu_getnext(chip, &vlan);
2017fad09c73SVivien Didelot 	if (err)
2018fad09c73SVivien Didelot 		return err;
2019fad09c73SVivien Didelot 
202052109892SVivien Didelot 	/* If the VLAN doesn't exist in hardware or the port isn't a member,
202152109892SVivien Didelot 	 * tell switchdev that this VLAN is likely handled in software.
202252109892SVivien Didelot 	 */
202352109892SVivien Didelot 	if (vlan.vid != vid || !vlan.valid ||
202452109892SVivien Didelot 	    vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
2025fad09c73SVivien Didelot 		return -EOPNOTSUPP;
2026fad09c73SVivien Didelot 
20277ec60d6eSVivien Didelot 	vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
2028fad09c73SVivien Didelot 
2029fad09c73SVivien Didelot 	/* keep the VLAN unless all ports are excluded */
2030fad09c73SVivien Didelot 	vlan.valid = false;
2031370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
20327ec60d6eSVivien Didelot 		if (vlan.member[i] !=
20337ec60d6eSVivien Didelot 		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
2034fad09c73SVivien Didelot 			vlan.valid = true;
2035fad09c73SVivien Didelot 			break;
2036fad09c73SVivien Didelot 		}
2037fad09c73SVivien Didelot 	}
2038fad09c73SVivien Didelot 
20390ad5daf6SVivien Didelot 	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
2040fad09c73SVivien Didelot 	if (err)
2041fad09c73SVivien Didelot 		return err;
2042fad09c73SVivien Didelot 
2043e606ca36SVivien Didelot 	return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
2044fad09c73SVivien Didelot }
2045fad09c73SVivien Didelot 
2046fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
2047fad09c73SVivien Didelot 				   const struct switchdev_obj_port_vlan *vlan)
2048fad09c73SVivien Didelot {
204904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2050fad09c73SVivien Didelot 	u16 pvid, vid;
2051fad09c73SVivien Didelot 	int err = 0;
2052fad09c73SVivien Didelot 
20533cf3c846SVivien Didelot 	if (!chip->info->max_vid)
2054fad09c73SVivien Didelot 		return -EOPNOTSUPP;
2055fad09c73SVivien Didelot 
2056c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2057fad09c73SVivien Didelot 
205877064f37SVivien Didelot 	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
2059fad09c73SVivien Didelot 	if (err)
2060fad09c73SVivien Didelot 		goto unlock;
2061fad09c73SVivien Didelot 
2062fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
206352109892SVivien Didelot 		err = mv88e6xxx_port_vlan_leave(chip, port, vid);
2064fad09c73SVivien Didelot 		if (err)
2065fad09c73SVivien Didelot 			goto unlock;
2066fad09c73SVivien Didelot 
2067fad09c73SVivien Didelot 		if (vid == pvid) {
206877064f37SVivien Didelot 			err = mv88e6xxx_port_set_pvid(chip, port, 0);
2069fad09c73SVivien Didelot 			if (err)
2070fad09c73SVivien Didelot 				goto unlock;
2071fad09c73SVivien Didelot 		}
2072fad09c73SVivien Didelot 	}
2073fad09c73SVivien Didelot 
2074fad09c73SVivien Didelot unlock:
2075c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2076fad09c73SVivien Didelot 
2077fad09c73SVivien Didelot 	return err;
2078fad09c73SVivien Didelot }
2079fad09c73SVivien Didelot 
20801b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
20816c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
2082fad09c73SVivien Didelot {
208304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
20841b6dd556SArkadi Sharshevsky 	int err;
2085fad09c73SVivien Didelot 
2086c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
20871b6dd556SArkadi Sharshevsky 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
20881b6dd556SArkadi Sharshevsky 					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
2089c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
20901b6dd556SArkadi Sharshevsky 
20911b6dd556SArkadi Sharshevsky 	return err;
2092fad09c73SVivien Didelot }
2093fad09c73SVivien Didelot 
2094fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
20956c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
2096fad09c73SVivien Didelot {
209704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
209883dabd1fSVivien Didelot 	int err;
2099fad09c73SVivien Didelot 
2100c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2101d8291a95SVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
2102c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2103fad09c73SVivien Didelot 
210483dabd1fSVivien Didelot 	return err;
2105fad09c73SVivien Didelot }
2106fad09c73SVivien Didelot 
210783dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
2108fad09c73SVivien Didelot 				      u16 fid, u16 vid, int port,
21092bedde1aSArkadi Sharshevsky 				      dsa_fdb_dump_cb_t *cb, void *data)
2110fad09c73SVivien Didelot {
2111dabc1a96SVivien Didelot 	struct mv88e6xxx_atu_entry addr;
21122bedde1aSArkadi Sharshevsky 	bool is_static;
2113fad09c73SVivien Didelot 	int err;
2114fad09c73SVivien Didelot 
2115d8291a95SVivien Didelot 	addr.state = 0;
2116dabc1a96SVivien Didelot 	eth_broadcast_addr(addr.mac);
2117fad09c73SVivien Didelot 
2118fad09c73SVivien Didelot 	do {
2119dabc1a96SVivien Didelot 		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
2120fad09c73SVivien Didelot 		if (err)
212183dabd1fSVivien Didelot 			return err;
2122fad09c73SVivien Didelot 
2123d8291a95SVivien Didelot 		if (!addr.state)
2124fad09c73SVivien Didelot 			break;
2125fad09c73SVivien Didelot 
212601bd96c8SVivien Didelot 		if (addr.trunk || (addr.portvec & BIT(port)) == 0)
212783dabd1fSVivien Didelot 			continue;
2128fad09c73SVivien Didelot 
212983dabd1fSVivien Didelot 		if (!is_unicast_ether_addr(addr.mac))
213083dabd1fSVivien Didelot 			continue;
213183dabd1fSVivien Didelot 
21322bedde1aSArkadi Sharshevsky 		is_static = (addr.state ==
21332bedde1aSArkadi Sharshevsky 			     MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
21342bedde1aSArkadi Sharshevsky 		err = cb(addr.mac, vid, is_static, data);
213583dabd1fSVivien Didelot 		if (err)
213683dabd1fSVivien Didelot 			return err;
2137fad09c73SVivien Didelot 	} while (!is_broadcast_ether_addr(addr.mac));
2138fad09c73SVivien Didelot 
2139fad09c73SVivien Didelot 	return err;
2140fad09c73SVivien Didelot }
2141fad09c73SVivien Didelot 
214283dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
21432bedde1aSArkadi Sharshevsky 				  dsa_fdb_dump_cb_t *cb, void *data)
214483dabd1fSVivien Didelot {
2145425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
214683dabd1fSVivien Didelot 	u16 fid;
214783dabd1fSVivien Didelot 	int err;
214883dabd1fSVivien Didelot 
214983dabd1fSVivien Didelot 	/* Dump port's default Filtering Information Database (VLAN ID 0) */
2150b4e48c50SVivien Didelot 	err = mv88e6xxx_port_get_fid(chip, port, &fid);
215183dabd1fSVivien Didelot 	if (err)
215283dabd1fSVivien Didelot 		return err;
215383dabd1fSVivien Didelot 
21542bedde1aSArkadi Sharshevsky 	err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data);
215583dabd1fSVivien Didelot 	if (err)
215683dabd1fSVivien Didelot 		return err;
215783dabd1fSVivien Didelot 
215883dabd1fSVivien Didelot 	/* Dump VLANs' Filtering Information Databases */
2159425d2d37SVivien Didelot 	vlan.vid = chip->info->max_vid;
2160425d2d37SVivien Didelot 	vlan.valid = false;
2161425d2d37SVivien Didelot 
216283dabd1fSVivien Didelot 	do {
2163f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
216483dabd1fSVivien Didelot 		if (err)
216583dabd1fSVivien Didelot 			return err;
216683dabd1fSVivien Didelot 
216783dabd1fSVivien Didelot 		if (!vlan.valid)
216883dabd1fSVivien Didelot 			break;
216983dabd1fSVivien Didelot 
217083dabd1fSVivien Didelot 		err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port,
21712bedde1aSArkadi Sharshevsky 						 cb, data);
217283dabd1fSVivien Didelot 		if (err)
217383dabd1fSVivien Didelot 			return err;
21743cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
217583dabd1fSVivien Didelot 
217683dabd1fSVivien Didelot 	return err;
217783dabd1fSVivien Didelot }
217883dabd1fSVivien Didelot 
2179fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
21802bedde1aSArkadi Sharshevsky 				   dsa_fdb_dump_cb_t *cb, void *data)
2181fad09c73SVivien Didelot {
218204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2183fcf15367SVivien Didelot 	int err;
2184fad09c73SVivien Didelot 
2185c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2186fcf15367SVivien Didelot 	err = mv88e6xxx_port_db_dump(chip, port, cb, data);
2187c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2188fcf15367SVivien Didelot 
2189fcf15367SVivien Didelot 	return err;
2190fad09c73SVivien Didelot }
2191fad09c73SVivien Didelot 
2192240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
2193240ea3efSVivien Didelot 				struct net_device *br)
2194240ea3efSVivien Didelot {
2195ef2025ecSVivien Didelot 	struct dsa_switch *ds = chip->ds;
2196ef2025ecSVivien Didelot 	struct dsa_switch_tree *dst = ds->dst;
2197ef2025ecSVivien Didelot 	struct dsa_port *dp;
2198240ea3efSVivien Didelot 	int err;
2199240ea3efSVivien Didelot 
2200ef2025ecSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list) {
2201ef2025ecSVivien Didelot 		if (dp->bridge_dev == br) {
2202ef2025ecSVivien Didelot 			if (dp->ds == ds) {
2203ef2025ecSVivien Didelot 				/* This is a local bridge group member,
2204ef2025ecSVivien Didelot 				 * remap its Port VLAN Map.
2205ef2025ecSVivien Didelot 				 */
2206ef2025ecSVivien Didelot 				err = mv88e6xxx_port_vlan_map(chip, dp->index);
2207240ea3efSVivien Didelot 				if (err)
2208240ea3efSVivien Didelot 					return err;
2209ef2025ecSVivien Didelot 			} else {
2210ef2025ecSVivien Didelot 				/* This is an external bridge group member,
2211ef2025ecSVivien Didelot 				 * remap its cross-chip Port VLAN Table entry.
2212ef2025ecSVivien Didelot 				 */
2213ef2025ecSVivien Didelot 				err = mv88e6xxx_pvt_map(chip, dp->ds->index,
2214ef2025ecSVivien Didelot 							dp->index);
2215e96a6e02SVivien Didelot 				if (err)
2216e96a6e02SVivien Didelot 					return err;
2217e96a6e02SVivien Didelot 			}
2218e96a6e02SVivien Didelot 		}
2219e96a6e02SVivien Didelot 	}
2220e96a6e02SVivien Didelot 
2221240ea3efSVivien Didelot 	return 0;
2222240ea3efSVivien Didelot }
2223240ea3efSVivien Didelot 
2224fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
2225fae8a25eSVivien Didelot 				      struct net_device *br)
2226fad09c73SVivien Didelot {
222704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2228240ea3efSVivien Didelot 	int err;
2229fad09c73SVivien Didelot 
2230c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2231240ea3efSVivien Didelot 	err = mv88e6xxx_bridge_map(chip, br);
2232c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2233fad09c73SVivien Didelot 
2234fad09c73SVivien Didelot 	return err;
2235fad09c73SVivien Didelot }
2236fad09c73SVivien Didelot 
2237f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
2238f123f2fbSVivien Didelot 					struct net_device *br)
2239fad09c73SVivien Didelot {
224004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2241fad09c73SVivien Didelot 
2242c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2243240ea3efSVivien Didelot 	if (mv88e6xxx_bridge_map(chip, br) ||
2244240ea3efSVivien Didelot 	    mv88e6xxx_port_vlan_map(chip, port))
2245240ea3efSVivien Didelot 		dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
2246c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2247fad09c73SVivien Didelot }
2248fad09c73SVivien Didelot 
2249f66a6a69SVladimir Oltean static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds,
2250f66a6a69SVladimir Oltean 					   int tree_index, int sw_index,
2251aec5ac88SVivien Didelot 					   int port, struct net_device *br)
2252aec5ac88SVivien Didelot {
2253aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2254aec5ac88SVivien Didelot 	int err;
2255aec5ac88SVivien Didelot 
2256f66a6a69SVladimir Oltean 	if (tree_index != ds->dst->index)
2257f66a6a69SVladimir Oltean 		return 0;
2258f66a6a69SVladimir Oltean 
2259c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2260f66a6a69SVladimir Oltean 	err = mv88e6xxx_pvt_map(chip, sw_index, port);
2261c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2262aec5ac88SVivien Didelot 
2263aec5ac88SVivien Didelot 	return err;
2264aec5ac88SVivien Didelot }
2265aec5ac88SVivien Didelot 
2266f66a6a69SVladimir Oltean static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds,
2267f66a6a69SVladimir Oltean 					     int tree_index, int sw_index,
2268aec5ac88SVivien Didelot 					     int port, struct net_device *br)
2269aec5ac88SVivien Didelot {
2270aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2271aec5ac88SVivien Didelot 
2272f66a6a69SVladimir Oltean 	if (tree_index != ds->dst->index)
2273f66a6a69SVladimir Oltean 		return;
2274f66a6a69SVladimir Oltean 
2275c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2276f66a6a69SVladimir Oltean 	if (mv88e6xxx_pvt_map(chip, sw_index, port))
2277aec5ac88SVivien Didelot 		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
2278c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2279aec5ac88SVivien Didelot }
2280aec5ac88SVivien Didelot 
228117e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
228217e708baSVivien Didelot {
228317e708baSVivien Didelot 	if (chip->info->ops->reset)
228417e708baSVivien Didelot 		return chip->info->ops->reset(chip);
228517e708baSVivien Didelot 
228617e708baSVivien Didelot 	return 0;
228717e708baSVivien Didelot }
228817e708baSVivien Didelot 
2289309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
2290309eca6dSVivien Didelot {
2291309eca6dSVivien Didelot 	struct gpio_desc *gpiod = chip->reset;
2292309eca6dSVivien Didelot 
2293309eca6dSVivien Didelot 	/* If there is a GPIO connected to the reset pin, toggle it */
2294309eca6dSVivien Didelot 	if (gpiod) {
2295309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 1);
2296309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2297309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 0);
2298309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2299309eca6dSVivien Didelot 	}
2300309eca6dSVivien Didelot }
2301309eca6dSVivien Didelot 
23024ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
23034ac4b5a6SVivien Didelot {
23044ac4b5a6SVivien Didelot 	int i, err;
23054ac4b5a6SVivien Didelot 
23064ac4b5a6SVivien Didelot 	/* Set all ports to the Disabled state */
23074ac4b5a6SVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2308f894c29cSVivien Didelot 		err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED);
23094ac4b5a6SVivien Didelot 		if (err)
23104ac4b5a6SVivien Didelot 			return err;
23114ac4b5a6SVivien Didelot 	}
23124ac4b5a6SVivien Didelot 
23134ac4b5a6SVivien Didelot 	/* Wait for transmit queues to drain,
23144ac4b5a6SVivien Didelot 	 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
23154ac4b5a6SVivien Didelot 	 */
23164ac4b5a6SVivien Didelot 	usleep_range(2000, 4000);
23174ac4b5a6SVivien Didelot 
23184ac4b5a6SVivien Didelot 	return 0;
23194ac4b5a6SVivien Didelot }
23204ac4b5a6SVivien Didelot 
2321fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
2322fad09c73SVivien Didelot {
2323a935c052SVivien Didelot 	int err;
2324fad09c73SVivien Didelot 
23254ac4b5a6SVivien Didelot 	err = mv88e6xxx_disable_ports(chip);
23260e7b9925SAndrew Lunn 	if (err)
23270e7b9925SAndrew Lunn 		return err;
2328fad09c73SVivien Didelot 
2329309eca6dSVivien Didelot 	mv88e6xxx_hardware_reset(chip);
2330fad09c73SVivien Didelot 
233117e708baSVivien Didelot 	return mv88e6xxx_software_reset(chip);
2332fad09c73SVivien Didelot }
2333fad09c73SVivien Didelot 
23344314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
233531bef4e9SVivien Didelot 				   enum mv88e6xxx_frame_mode frame,
233631bef4e9SVivien Didelot 				   enum mv88e6xxx_egress_mode egress, u16 etype)
233756995cbcSAndrew Lunn {
233856995cbcSAndrew Lunn 	int err;
233956995cbcSAndrew Lunn 
23404314557cSVivien Didelot 	if (!chip->info->ops->port_set_frame_mode)
23414314557cSVivien Didelot 		return -EOPNOTSUPP;
23424314557cSVivien Didelot 
23434314557cSVivien Didelot 	err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
234456995cbcSAndrew Lunn 	if (err)
234556995cbcSAndrew Lunn 		return err;
234656995cbcSAndrew Lunn 
23474314557cSVivien Didelot 	err = chip->info->ops->port_set_frame_mode(chip, port, frame);
23484314557cSVivien Didelot 	if (err)
23494314557cSVivien Didelot 		return err;
23504314557cSVivien Didelot 
23514314557cSVivien Didelot 	if (chip->info->ops->port_set_ether_type)
23524314557cSVivien Didelot 		return chip->info->ops->port_set_ether_type(chip, port, etype);
23534314557cSVivien Didelot 
23544314557cSVivien Didelot 	return 0;
23554314557cSVivien Didelot }
23564314557cSVivien Didelot 
23574314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
23584314557cSVivien Didelot {
23594314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
236031bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2361b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
23624314557cSVivien Didelot }
23634314557cSVivien Didelot 
23644314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
23654314557cSVivien Didelot {
23664314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
236731bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2368b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
23694314557cSVivien Didelot }
23704314557cSVivien Didelot 
23714314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
23724314557cSVivien Didelot {
23734314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port,
23744314557cSVivien Didelot 				       MV88E6XXX_FRAME_MODE_ETHERTYPE,
237531bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_ETHERTYPE,
237631bef4e9SVivien Didelot 				       ETH_P_EDSA);
23774314557cSVivien Didelot }
23784314557cSVivien Didelot 
23794314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port)
23804314557cSVivien Didelot {
23814314557cSVivien Didelot 	if (dsa_is_dsa_port(chip->ds, port))
23824314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
23834314557cSVivien Didelot 
23842b3e9891SVivien Didelot 	if (dsa_is_user_port(chip->ds, port))
23854314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_normal(chip, port);
23864314557cSVivien Didelot 
23874314557cSVivien Didelot 	/* Setup CPU port mode depending on its supported tag format */
23884314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA)
23894314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
23904314557cSVivien Didelot 
23914314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA)
23924314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_edsa(chip, port);
23934314557cSVivien Didelot 
23944314557cSVivien Didelot 	return -EINVAL;
23954314557cSVivien Didelot }
23964314557cSVivien Didelot 
2397ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
2398ea698f4fSVivien Didelot {
2399ea698f4fSVivien Didelot 	bool message = dsa_is_dsa_port(chip->ds, port);
2400ea698f4fSVivien Didelot 
2401ea698f4fSVivien Didelot 	return mv88e6xxx_port_set_message_port(chip, port, message);
2402ea698f4fSVivien Didelot }
2403ea698f4fSVivien Didelot 
2404601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
2405601aeed3SVivien Didelot {
24063ee50cbfSVivien Didelot 	struct dsa_switch *ds = chip->ds;
2407407308f6SDavid S. Miller 	bool flood;
2408601aeed3SVivien Didelot 
2409407308f6SDavid S. Miller 	/* Upstream ports flood frames with unknown unicast or multicast DA */
2410407308f6SDavid S. Miller 	flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port);
2411407308f6SDavid S. Miller 	if (chip->info->ops->port_set_egress_floods)
2412407308f6SDavid S. Miller 		return chip->info->ops->port_set_egress_floods(chip, port,
2413407308f6SDavid S. Miller 							       flood, flood);
2414407308f6SDavid S. Miller 
2415601aeed3SVivien Didelot 	return 0;
2416601aeed3SVivien Didelot }
2417601aeed3SVivien Didelot 
241845de77ffSVivien Didelot static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
241945de77ffSVivien Didelot {
242045de77ffSVivien Didelot 	struct mv88e6xxx_port *mvp = dev_id;
242145de77ffSVivien Didelot 	struct mv88e6xxx_chip *chip = mvp->chip;
242245de77ffSVivien Didelot 	irqreturn_t ret = IRQ_NONE;
242345de77ffSVivien Didelot 	int port = mvp->port;
242445de77ffSVivien Didelot 	u8 lane;
242545de77ffSVivien Didelot 
242645de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
242745de77ffSVivien Didelot 	lane = mv88e6xxx_serdes_get_lane(chip, port);
242845de77ffSVivien Didelot 	if (lane)
242945de77ffSVivien Didelot 		ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
243045de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
243145de77ffSVivien Didelot 
243245de77ffSVivien Didelot 	return ret;
243345de77ffSVivien Didelot }
243445de77ffSVivien Didelot 
243545de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
243645de77ffSVivien Didelot 					u8 lane)
243745de77ffSVivien Didelot {
243845de77ffSVivien Didelot 	struct mv88e6xxx_port *dev_id = &chip->ports[port];
243945de77ffSVivien Didelot 	unsigned int irq;
244045de77ffSVivien Didelot 	int err;
244145de77ffSVivien Didelot 
244245de77ffSVivien Didelot 	/* Nothing to request if this SERDES port has no IRQ */
244345de77ffSVivien Didelot 	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
244445de77ffSVivien Didelot 	if (!irq)
244545de77ffSVivien Didelot 		return 0;
244645de77ffSVivien Didelot 
2447e6f2f6b8SAndrew Lunn 	snprintf(dev_id->serdes_irq_name, sizeof(dev_id->serdes_irq_name),
2448e6f2f6b8SAndrew Lunn 		 "mv88e6xxx-%s-serdes-%d", dev_name(chip->dev), port);
2449e6f2f6b8SAndrew Lunn 
245045de77ffSVivien Didelot 	/* Requesting the IRQ will trigger IRQ callbacks, so release the lock */
245145de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
245245de77ffSVivien Didelot 	err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn,
2453e6f2f6b8SAndrew Lunn 				   IRQF_ONESHOT, dev_id->serdes_irq_name,
2454e6f2f6b8SAndrew Lunn 				   dev_id);
245545de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
245645de77ffSVivien Didelot 	if (err)
245745de77ffSVivien Didelot 		return err;
245845de77ffSVivien Didelot 
245945de77ffSVivien Didelot 	dev_id->serdes_irq = irq;
246045de77ffSVivien Didelot 
246145de77ffSVivien Didelot 	return mv88e6xxx_serdes_irq_enable(chip, port, lane);
246245de77ffSVivien Didelot }
246345de77ffSVivien Didelot 
246445de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
246545de77ffSVivien Didelot 				     u8 lane)
246645de77ffSVivien Didelot {
246745de77ffSVivien Didelot 	struct mv88e6xxx_port *dev_id = &chip->ports[port];
246845de77ffSVivien Didelot 	unsigned int irq = dev_id->serdes_irq;
246945de77ffSVivien Didelot 	int err;
247045de77ffSVivien Didelot 
247145de77ffSVivien Didelot 	/* Nothing to free if no IRQ has been requested */
247245de77ffSVivien Didelot 	if (!irq)
247345de77ffSVivien Didelot 		return 0;
247445de77ffSVivien Didelot 
247545de77ffSVivien Didelot 	err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
247645de77ffSVivien Didelot 
247745de77ffSVivien Didelot 	/* Freeing the IRQ will trigger IRQ callbacks, so release the lock */
247845de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
247945de77ffSVivien Didelot 	free_irq(irq, dev_id);
248045de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
248145de77ffSVivien Didelot 
248245de77ffSVivien Didelot 	dev_id->serdes_irq = 0;
248345de77ffSVivien Didelot 
248445de77ffSVivien Didelot 	return err;
248545de77ffSVivien Didelot }
248645de77ffSVivien Didelot 
24876d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
24886d91782fSAndrew Lunn 				  bool on)
24896d91782fSAndrew Lunn {
2490dc272f60SVivien Didelot 	u8 lane;
2491fc0bc019SVivien Didelot 	int err;
24926d91782fSAndrew Lunn 
2493dc272f60SVivien Didelot 	lane = mv88e6xxx_serdes_get_lane(chip, port);
2494dc272f60SVivien Didelot 	if (!lane)
2495523a8904SVivien Didelot 		return 0;
2496fc0bc019SVivien Didelot 
2497fc0bc019SVivien Didelot 	if (on) {
2498dc272f60SVivien Didelot 		err = mv88e6xxx_serdes_power_up(chip, port, lane);
2499fc0bc019SVivien Didelot 		if (err)
2500fc0bc019SVivien Didelot 			return err;
2501fc0bc019SVivien Didelot 
250245de77ffSVivien Didelot 		err = mv88e6xxx_serdes_irq_request(chip, port, lane);
2503fc0bc019SVivien Didelot 	} else {
250445de77ffSVivien Didelot 		err = mv88e6xxx_serdes_irq_free(chip, port, lane);
250545de77ffSVivien Didelot 		if (err)
250645de77ffSVivien Didelot 			return err;
2507fc0bc019SVivien Didelot 
2508dc272f60SVivien Didelot 		err = mv88e6xxx_serdes_power_down(chip, port, lane);
2509fc0bc019SVivien Didelot 	}
2510fc0bc019SVivien Didelot 
2511fc0bc019SVivien Didelot 	return err;
25126d91782fSAndrew Lunn }
25136d91782fSAndrew Lunn 
2514fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
2515fa371c80SVivien Didelot {
2516fa371c80SVivien Didelot 	struct dsa_switch *ds = chip->ds;
2517fa371c80SVivien Didelot 	int upstream_port;
2518fa371c80SVivien Didelot 	int err;
2519fa371c80SVivien Didelot 
252007073c79SVivien Didelot 	upstream_port = dsa_upstream_port(ds, port);
2521fa371c80SVivien Didelot 	if (chip->info->ops->port_set_upstream_port) {
2522fa371c80SVivien Didelot 		err = chip->info->ops->port_set_upstream_port(chip, port,
2523fa371c80SVivien Didelot 							      upstream_port);
2524fa371c80SVivien Didelot 		if (err)
2525fa371c80SVivien Didelot 			return err;
2526fa371c80SVivien Didelot 	}
2527fa371c80SVivien Didelot 
25280ea54ddaSVivien Didelot 	if (port == upstream_port) {
25290ea54ddaSVivien Didelot 		if (chip->info->ops->set_cpu_port) {
25300ea54ddaSVivien Didelot 			err = chip->info->ops->set_cpu_port(chip,
25310ea54ddaSVivien Didelot 							    upstream_port);
25320ea54ddaSVivien Didelot 			if (err)
25330ea54ddaSVivien Didelot 				return err;
25340ea54ddaSVivien Didelot 		}
25350ea54ddaSVivien Didelot 
25360ea54ddaSVivien Didelot 		if (chip->info->ops->set_egress_port) {
25370ea54ddaSVivien Didelot 			err = chip->info->ops->set_egress_port(chip,
25385c74c54cSIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS,
25395c74c54cSIwan R Timmer 						upstream_port);
25405c74c54cSIwan R Timmer 			if (err)
25415c74c54cSIwan R Timmer 				return err;
25425c74c54cSIwan R Timmer 
25435c74c54cSIwan R Timmer 			err = chip->info->ops->set_egress_port(chip,
25445c74c54cSIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS,
25450ea54ddaSVivien Didelot 						upstream_port);
25460ea54ddaSVivien Didelot 			if (err)
25470ea54ddaSVivien Didelot 				return err;
25480ea54ddaSVivien Didelot 		}
25490ea54ddaSVivien Didelot 	}
25500ea54ddaSVivien Didelot 
2551fa371c80SVivien Didelot 	return 0;
2552fa371c80SVivien Didelot }
2553fa371c80SVivien Didelot 
2554fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
2555fad09c73SVivien Didelot {
2556fad09c73SVivien Didelot 	struct dsa_switch *ds = chip->ds;
25570e7b9925SAndrew Lunn 	int err;
2558fad09c73SVivien Didelot 	u16 reg;
2559fad09c73SVivien Didelot 
25607b898469SAndrew Lunn 	chip->ports[port].chip = chip;
25617b898469SAndrew Lunn 	chip->ports[port].port = port;
25627b898469SAndrew Lunn 
2563d78343d2SVivien Didelot 	/* MAC Forcing register: don't force link, speed, duplex or flow control
2564d78343d2SVivien Didelot 	 * state to any particular values on physical ports, but force the CPU
2565d78343d2SVivien Didelot 	 * port and all DSA ports to their maximum bandwidth and full duplex.
2566fad09c73SVivien Didelot 	 */
2567d78343d2SVivien Didelot 	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
2568d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
2569d78343d2SVivien Didelot 					       SPEED_MAX, DUPLEX_FULL,
257054186b91SAndrew Lunn 					       PAUSE_OFF,
2571d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
2572fad09c73SVivien Didelot 	else
2573d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
2574d78343d2SVivien Didelot 					       SPEED_UNFORCED, DUPLEX_UNFORCED,
257554186b91SAndrew Lunn 					       PAUSE_ON,
2576d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
25770e7b9925SAndrew Lunn 	if (err)
25780e7b9925SAndrew Lunn 		return err;
2579fad09c73SVivien Didelot 
2580fad09c73SVivien Didelot 	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
2581fad09c73SVivien Didelot 	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
2582fad09c73SVivien Didelot 	 * tunneling, determine priority by looking at 802.1p and IP
2583fad09c73SVivien Didelot 	 * priority fields (IP prio has precedence), and set STP state
2584fad09c73SVivien Didelot 	 * to Forwarding.
2585fad09c73SVivien Didelot 	 *
2586fad09c73SVivien Didelot 	 * If this is the CPU link, use DSA or EDSA tagging depending
2587fad09c73SVivien Didelot 	 * on which tagging mode was configured.
2588fad09c73SVivien Didelot 	 *
2589fad09c73SVivien Didelot 	 * If this is a link to another switch, use DSA tagging mode.
2590fad09c73SVivien Didelot 	 *
2591fad09c73SVivien Didelot 	 * If this is the upstream port for this switch, enable
2592fad09c73SVivien Didelot 	 * forwarding of unknown unicasts and multicasts.
2593fad09c73SVivien Didelot 	 */
2594a89b433bSVivien Didelot 	reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP |
2595a89b433bSVivien Didelot 		MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
2596a89b433bSVivien Didelot 		MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
2597a89b433bSVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
25980e7b9925SAndrew Lunn 	if (err)
25990e7b9925SAndrew Lunn 		return err;
260056995cbcSAndrew Lunn 
2601601aeed3SVivien Didelot 	err = mv88e6xxx_setup_port_mode(chip, port);
260256995cbcSAndrew Lunn 	if (err)
260356995cbcSAndrew Lunn 		return err;
2604fad09c73SVivien Didelot 
2605601aeed3SVivien Didelot 	err = mv88e6xxx_setup_egress_floods(chip, port);
26064314557cSVivien Didelot 	if (err)
26074314557cSVivien Didelot 		return err;
26084314557cSVivien Didelot 
2609fad09c73SVivien Didelot 	/* Port Control 2: don't force a good FCS, set the maximum frame size to
2610fad09c73SVivien Didelot 	 * 10240 bytes, disable 802.1q tags checking, don't discard tagged or
2611fad09c73SVivien Didelot 	 * untagged frames on this port, do a destination address lookup on all
2612fad09c73SVivien Didelot 	 * received packets as usual, disable ARP mirroring and don't send a
2613fad09c73SVivien Didelot 	 * copy of all transmitted/received frames on this port to the CPU.
2614fad09c73SVivien Didelot 	 */
2615a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_map_da(chip, port);
2616a23b2961SAndrew Lunn 	if (err)
2617a23b2961SAndrew Lunn 		return err;
2618a23b2961SAndrew Lunn 
2619fa371c80SVivien Didelot 	err = mv88e6xxx_setup_upstream_port(chip, port);
26200e7b9925SAndrew Lunn 	if (err)
26210e7b9925SAndrew Lunn 		return err;
2622fad09c73SVivien Didelot 
2623a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_8021q_mode(chip, port,
262481c6edb2SVivien Didelot 				MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED);
2625a23b2961SAndrew Lunn 	if (err)
2626a23b2961SAndrew Lunn 		return err;
2627a23b2961SAndrew Lunn 
2628cd782656SVivien Didelot 	if (chip->info->ops->port_set_jumbo_size) {
2629cd782656SVivien Didelot 		err = chip->info->ops->port_set_jumbo_size(chip, port, 10240);
26305f436666SAndrew Lunn 		if (err)
26315f436666SAndrew Lunn 			return err;
26325f436666SAndrew Lunn 	}
26335f436666SAndrew Lunn 
2634fad09c73SVivien Didelot 	/* Port Association Vector: when learning source addresses
2635fad09c73SVivien Didelot 	 * of packets, add the address to the address database using
2636fad09c73SVivien Didelot 	 * a port bitmap that has only the bit for this port set and
2637fad09c73SVivien Didelot 	 * the other bits clear.
2638fad09c73SVivien Didelot 	 */
2639fad09c73SVivien Didelot 	reg = 1 << port;
2640fad09c73SVivien Didelot 	/* Disable learning for CPU port */
2641fad09c73SVivien Didelot 	if (dsa_is_cpu_port(ds, port))
2642fad09c73SVivien Didelot 		reg = 0;
2643fad09c73SVivien Didelot 
26442a4614e4SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
26452a4614e4SVivien Didelot 				   reg);
26460e7b9925SAndrew Lunn 	if (err)
26470e7b9925SAndrew Lunn 		return err;
2648fad09c73SVivien Didelot 
2649fad09c73SVivien Didelot 	/* Egress rate control 2: disable egress rate control. */
26502cb8cb14SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2,
26512cb8cb14SVivien Didelot 				   0x0000);
26520e7b9925SAndrew Lunn 	if (err)
26530e7b9925SAndrew Lunn 		return err;
2654fad09c73SVivien Didelot 
26550898432cSVivien Didelot 	if (chip->info->ops->port_pause_limit) {
26560898432cSVivien Didelot 		err = chip->info->ops->port_pause_limit(chip, port, 0, 0);
2657b35d322aSAndrew Lunn 		if (err)
2658b35d322aSAndrew Lunn 			return err;
2659b35d322aSAndrew Lunn 	}
2660b35d322aSAndrew Lunn 
2661c8c94891SVivien Didelot 	if (chip->info->ops->port_disable_learn_limit) {
2662c8c94891SVivien Didelot 		err = chip->info->ops->port_disable_learn_limit(chip, port);
2663c8c94891SVivien Didelot 		if (err)
2664c8c94891SVivien Didelot 			return err;
2665c8c94891SVivien Didelot 	}
2666c8c94891SVivien Didelot 
26679dbfb4e1SVivien Didelot 	if (chip->info->ops->port_disable_pri_override) {
26689dbfb4e1SVivien Didelot 		err = chip->info->ops->port_disable_pri_override(chip, port);
26690e7b9925SAndrew Lunn 		if (err)
26700e7b9925SAndrew Lunn 			return err;
2671ef0a7318SAndrew Lunn 	}
26722bbb33beSAndrew Lunn 
2673ef0a7318SAndrew Lunn 	if (chip->info->ops->port_tag_remap) {
2674ef0a7318SAndrew Lunn 		err = chip->info->ops->port_tag_remap(chip, port);
26750e7b9925SAndrew Lunn 		if (err)
26760e7b9925SAndrew Lunn 			return err;
2677fad09c73SVivien Didelot 	}
2678fad09c73SVivien Didelot 
2679ef70b111SAndrew Lunn 	if (chip->info->ops->port_egress_rate_limiting) {
2680ef70b111SAndrew Lunn 		err = chip->info->ops->port_egress_rate_limiting(chip, port);
26810e7b9925SAndrew Lunn 		if (err)
26820e7b9925SAndrew Lunn 			return err;
2683fad09c73SVivien Didelot 	}
2684fad09c73SVivien Didelot 
2685121b8fe2SHubert Feurstein 	if (chip->info->ops->port_setup_message_port) {
2686121b8fe2SHubert Feurstein 		err = chip->info->ops->port_setup_message_port(chip, port);
26870e7b9925SAndrew Lunn 		if (err)
26880e7b9925SAndrew Lunn 			return err;
2689121b8fe2SHubert Feurstein 	}
2690fad09c73SVivien Didelot 
2691fad09c73SVivien Didelot 	/* Port based VLAN map: give each port the same default address
2692fad09c73SVivien Didelot 	 * database, and allow bidirectional communication between the
2693fad09c73SVivien Didelot 	 * CPU and DSA port(s), and the other ports.
2694fad09c73SVivien Didelot 	 */
2695b4e48c50SVivien Didelot 	err = mv88e6xxx_port_set_fid(chip, port, 0);
26960e7b9925SAndrew Lunn 	if (err)
26970e7b9925SAndrew Lunn 		return err;
2698fad09c73SVivien Didelot 
2699240ea3efSVivien Didelot 	err = mv88e6xxx_port_vlan_map(chip, port);
27000e7b9925SAndrew Lunn 	if (err)
27010e7b9925SAndrew Lunn 		return err;
2702fad09c73SVivien Didelot 
2703fad09c73SVivien Didelot 	/* Default VLAN ID and priority: don't set a default VLAN
2704fad09c73SVivien Didelot 	 * ID, and set the default packet priority to zero.
2705fad09c73SVivien Didelot 	 */
2706b7929fb3SVivien Didelot 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0);
2707fad09c73SVivien Didelot }
2708fad09c73SVivien Didelot 
27092a550aecSAndrew Lunn static int mv88e6xxx_get_max_mtu(struct dsa_switch *ds, int port)
27102a550aecSAndrew Lunn {
27112a550aecSAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
27122a550aecSAndrew Lunn 
27132a550aecSAndrew Lunn 	if (chip->info->ops->port_set_jumbo_size)
27142a550aecSAndrew Lunn 		return 10240;
27151baf0facSChris Packham 	else if (chip->info->ops->set_max_frame_size)
27161baf0facSChris Packham 		return 1632;
27172a550aecSAndrew Lunn 	return 1522;
27182a550aecSAndrew Lunn }
27192a550aecSAndrew Lunn 
27202a550aecSAndrew Lunn static int mv88e6xxx_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
27212a550aecSAndrew Lunn {
27222a550aecSAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
27232a550aecSAndrew Lunn 	int ret = 0;
27242a550aecSAndrew Lunn 
27252a550aecSAndrew Lunn 	mv88e6xxx_reg_lock(chip);
27262a550aecSAndrew Lunn 	if (chip->info->ops->port_set_jumbo_size)
27272a550aecSAndrew Lunn 		ret = chip->info->ops->port_set_jumbo_size(chip, port, new_mtu);
27281baf0facSChris Packham 	else if (chip->info->ops->set_max_frame_size)
27291baf0facSChris Packham 		ret = chip->info->ops->set_max_frame_size(chip, new_mtu);
27302a550aecSAndrew Lunn 	else
27312a550aecSAndrew Lunn 		if (new_mtu > 1522)
27322a550aecSAndrew Lunn 			ret = -EINVAL;
27332a550aecSAndrew Lunn 	mv88e6xxx_reg_unlock(chip);
27342a550aecSAndrew Lunn 
27352a550aecSAndrew Lunn 	return ret;
27362a550aecSAndrew Lunn }
27372a550aecSAndrew Lunn 
273804aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
273904aca993SAndrew Lunn 				 struct phy_device *phydev)
274004aca993SAndrew Lunn {
274104aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
2742523a8904SVivien Didelot 	int err;
274304aca993SAndrew Lunn 
2744c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2745523a8904SVivien Didelot 	err = mv88e6xxx_serdes_power(chip, port, true);
2746c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
274704aca993SAndrew Lunn 
274804aca993SAndrew Lunn 	return err;
274904aca993SAndrew Lunn }
275004aca993SAndrew Lunn 
275175104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
275204aca993SAndrew Lunn {
275304aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
275404aca993SAndrew Lunn 
2755c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2756523a8904SVivien Didelot 	if (mv88e6xxx_serdes_power(chip, port, false))
2757523a8904SVivien Didelot 		dev_err(chip->dev, "failed to power off SERDES\n");
2758c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
275904aca993SAndrew Lunn }
276004aca993SAndrew Lunn 
27612cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
27622cfcd964SVivien Didelot 				     unsigned int ageing_time)
27632cfcd964SVivien Didelot {
276404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
27652cfcd964SVivien Didelot 	int err;
27662cfcd964SVivien Didelot 
2767c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2768720c6343SVivien Didelot 	err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
2769c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
27702cfcd964SVivien Didelot 
27712cfcd964SVivien Didelot 	return err;
27722cfcd964SVivien Didelot }
27732cfcd964SVivien Didelot 
2774447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
2775fad09c73SVivien Didelot {
2776fad09c73SVivien Didelot 	int err;
2777fad09c73SVivien Didelot 
2778de227387SAndrew Lunn 	/* Initialize the statistics unit */
2779447b1bb8SVivien Didelot 	if (chip->info->ops->stats_set_histogram) {
2780447b1bb8SVivien Didelot 		err = chip->info->ops->stats_set_histogram(chip);
2781de227387SAndrew Lunn 		if (err)
2782de227387SAndrew Lunn 			return err;
2783447b1bb8SVivien Didelot 	}
2784de227387SAndrew Lunn 
278540cff8fcSAndrew Lunn 	return mv88e6xxx_g1_stats_clear(chip);
27869729934cSVivien Didelot }
27879729934cSVivien Didelot 
2788ea89098eSAndrew Lunn /* Check if the errata has already been applied. */
2789ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
2790ea89098eSAndrew Lunn {
2791ea89098eSAndrew Lunn 	int port;
2792ea89098eSAndrew Lunn 	int err;
2793ea89098eSAndrew Lunn 	u16 val;
2794ea89098eSAndrew Lunn 
2795ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
279660907013SMarek Behún 		err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val);
2797ea89098eSAndrew Lunn 		if (err) {
2798ea89098eSAndrew Lunn 			dev_err(chip->dev,
2799ea89098eSAndrew Lunn 				"Error reading hidden register: %d\n", err);
2800ea89098eSAndrew Lunn 			return false;
2801ea89098eSAndrew Lunn 		}
2802ea89098eSAndrew Lunn 		if (val != 0x01c0)
2803ea89098eSAndrew Lunn 			return false;
2804ea89098eSAndrew Lunn 	}
2805ea89098eSAndrew Lunn 
2806ea89098eSAndrew Lunn 	return true;
2807ea89098eSAndrew Lunn }
2808ea89098eSAndrew Lunn 
2809ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic
2810ea89098eSAndrew Lunn  * values into undocumented hidden registers and then performing a
2811ea89098eSAndrew Lunn  * software reset.
2812ea89098eSAndrew Lunn  */
2813ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
2814ea89098eSAndrew Lunn {
2815ea89098eSAndrew Lunn 	int port;
2816ea89098eSAndrew Lunn 	int err;
2817ea89098eSAndrew Lunn 
2818ea89098eSAndrew Lunn 	if (mv88e6390_setup_errata_applied(chip))
2819ea89098eSAndrew Lunn 		return 0;
2820ea89098eSAndrew Lunn 
2821ea89098eSAndrew Lunn 	/* Set the ports into blocking mode */
2822ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
2823ea89098eSAndrew Lunn 		err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED);
2824ea89098eSAndrew Lunn 		if (err)
2825ea89098eSAndrew Lunn 			return err;
2826ea89098eSAndrew Lunn 	}
2827ea89098eSAndrew Lunn 
2828ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
282960907013SMarek Behún 		err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0);
2830ea89098eSAndrew Lunn 		if (err)
2831ea89098eSAndrew Lunn 			return err;
2832ea89098eSAndrew Lunn 	}
2833ea89098eSAndrew Lunn 
2834ea89098eSAndrew Lunn 	return mv88e6xxx_software_reset(chip);
2835ea89098eSAndrew Lunn }
2836ea89098eSAndrew Lunn 
283723e8b470SAndrew Lunn static void mv88e6xxx_teardown(struct dsa_switch *ds)
283823e8b470SAndrew Lunn {
283923e8b470SAndrew Lunn 	mv88e6xxx_teardown_devlink_params(ds);
2840e0c69ca7SAndrew Lunn 	dsa_devlink_resources_unregister(ds);
2841bfb25542SAndrew Lunn 	mv88e6xxx_teardown_devlink_regions(ds);
284223e8b470SAndrew Lunn }
284323e8b470SAndrew Lunn 
2844fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds)
2845fad09c73SVivien Didelot {
284604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
28472d2e1dd2SAndrew Lunn 	u8 cmode;
2848fad09c73SVivien Didelot 	int err;
2849fad09c73SVivien Didelot 	int i;
2850fad09c73SVivien Didelot 
2851fad09c73SVivien Didelot 	chip->ds = ds;
2852a3c53be5SAndrew Lunn 	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
2853fad09c73SVivien Didelot 
2854c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2855fad09c73SVivien Didelot 
2856ea89098eSAndrew Lunn 	if (chip->info->ops->setup_errata) {
2857ea89098eSAndrew Lunn 		err = chip->info->ops->setup_errata(chip);
2858ea89098eSAndrew Lunn 		if (err)
2859ea89098eSAndrew Lunn 			goto unlock;
2860ea89098eSAndrew Lunn 	}
2861ea89098eSAndrew Lunn 
28622d2e1dd2SAndrew Lunn 	/* Cache the cmode of each port. */
28632d2e1dd2SAndrew Lunn 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
28642d2e1dd2SAndrew Lunn 		if (chip->info->ops->port_get_cmode) {
28652d2e1dd2SAndrew Lunn 			err = chip->info->ops->port_get_cmode(chip, i, &cmode);
28662d2e1dd2SAndrew Lunn 			if (err)
2867e29129fcSDan Carpenter 				goto unlock;
28682d2e1dd2SAndrew Lunn 
28692d2e1dd2SAndrew Lunn 			chip->ports[i].cmode = cmode;
28702d2e1dd2SAndrew Lunn 		}
28712d2e1dd2SAndrew Lunn 	}
28722d2e1dd2SAndrew Lunn 
28739729934cSVivien Didelot 	/* Setup Switch Port Registers */
2874370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2875b759f528SVivien Didelot 		if (dsa_is_unused_port(ds, i))
2876b759f528SVivien Didelot 			continue;
2877b759f528SVivien Didelot 
2878c857486aSHubert Feurstein 		/* Prevent the use of an invalid port. */
2879b759f528SVivien Didelot 		if (mv88e6xxx_is_invalid_port(chip, i)) {
2880c857486aSHubert Feurstein 			dev_err(chip->dev, "port %d is invalid\n", i);
2881c857486aSHubert Feurstein 			err = -EINVAL;
2882c857486aSHubert Feurstein 			goto unlock;
2883c857486aSHubert Feurstein 		}
2884c857486aSHubert Feurstein 
28859729934cSVivien Didelot 		err = mv88e6xxx_setup_port(chip, i);
28869729934cSVivien Didelot 		if (err)
28879729934cSVivien Didelot 			goto unlock;
28889729934cSVivien Didelot 	}
28899729934cSVivien Didelot 
2890cd8da8bbSVivien Didelot 	err = mv88e6xxx_irl_setup(chip);
2891cd8da8bbSVivien Didelot 	if (err)
2892cd8da8bbSVivien Didelot 		goto unlock;
2893cd8da8bbSVivien Didelot 
289404a69a17SVivien Didelot 	err = mv88e6xxx_mac_setup(chip);
289504a69a17SVivien Didelot 	if (err)
289604a69a17SVivien Didelot 		goto unlock;
289704a69a17SVivien Didelot 
28981b17aedfSVivien Didelot 	err = mv88e6xxx_phy_setup(chip);
28991b17aedfSVivien Didelot 	if (err)
29001b17aedfSVivien Didelot 		goto unlock;
29011b17aedfSVivien Didelot 
2902b486d7c9SVivien Didelot 	err = mv88e6xxx_vtu_setup(chip);
2903b486d7c9SVivien Didelot 	if (err)
2904b486d7c9SVivien Didelot 		goto unlock;
2905b486d7c9SVivien Didelot 
290681228996SVivien Didelot 	err = mv88e6xxx_pvt_setup(chip);
290781228996SVivien Didelot 	if (err)
290881228996SVivien Didelot 		goto unlock;
290981228996SVivien Didelot 
2910a2ac29d2SVivien Didelot 	err = mv88e6xxx_atu_setup(chip);
2911a2ac29d2SVivien Didelot 	if (err)
2912a2ac29d2SVivien Didelot 		goto unlock;
2913a2ac29d2SVivien Didelot 
291487fa886eSAndrew Lunn 	err = mv88e6xxx_broadcast_setup(chip, 0);
291587fa886eSAndrew Lunn 	if (err)
291687fa886eSAndrew Lunn 		goto unlock;
291787fa886eSAndrew Lunn 
29189e907d73SVivien Didelot 	err = mv88e6xxx_pot_setup(chip);
29199e907d73SVivien Didelot 	if (err)
29209e907d73SVivien Didelot 		goto unlock;
29219e907d73SVivien Didelot 
29229e5baf9bSVivien Didelot 	err = mv88e6xxx_rmu_setup(chip);
29239e5baf9bSVivien Didelot 	if (err)
29249e5baf9bSVivien Didelot 		goto unlock;
29259e5baf9bSVivien Didelot 
292651c901a7SVivien Didelot 	err = mv88e6xxx_rsvd2cpu_setup(chip);
29276e55f698SAndrew Lunn 	if (err)
29286e55f698SAndrew Lunn 		goto unlock;
29296e55f698SAndrew Lunn 
2930b28f872dSVivien Didelot 	err = mv88e6xxx_trunk_setup(chip);
2931b28f872dSVivien Didelot 	if (err)
2932b28f872dSVivien Didelot 		goto unlock;
2933b28f872dSVivien Didelot 
2934c7f047b6SVivien Didelot 	err = mv88e6xxx_devmap_setup(chip);
2935c7f047b6SVivien Didelot 	if (err)
2936c7f047b6SVivien Didelot 		goto unlock;
2937c7f047b6SVivien Didelot 
293893e18d61SVivien Didelot 	err = mv88e6xxx_pri_setup(chip);
293993e18d61SVivien Didelot 	if (err)
294093e18d61SVivien Didelot 		goto unlock;
294193e18d61SVivien Didelot 
2942c6fe0ad2SBrandon Streiff 	/* Setup PTP Hardware Clock and timestamping */
29432fa8d3afSBrandon Streiff 	if (chip->info->ptp_support) {
29442fa8d3afSBrandon Streiff 		err = mv88e6xxx_ptp_setup(chip);
29452fa8d3afSBrandon Streiff 		if (err)
29462fa8d3afSBrandon Streiff 			goto unlock;
2947c6fe0ad2SBrandon Streiff 
2948c6fe0ad2SBrandon Streiff 		err = mv88e6xxx_hwtstamp_setup(chip);
2949c6fe0ad2SBrandon Streiff 		if (err)
2950c6fe0ad2SBrandon Streiff 			goto unlock;
29512fa8d3afSBrandon Streiff 	}
29522fa8d3afSBrandon Streiff 
2953447b1bb8SVivien Didelot 	err = mv88e6xxx_stats_setup(chip);
2954447b1bb8SVivien Didelot 	if (err)
2955447b1bb8SVivien Didelot 		goto unlock;
2956447b1bb8SVivien Didelot 
2957fad09c73SVivien Didelot unlock:
2958c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2959fad09c73SVivien Didelot 
2960e0c69ca7SAndrew Lunn 	if (err)
2961e0c69ca7SAndrew Lunn 		return err;
2962e0c69ca7SAndrew Lunn 
2963e0c69ca7SAndrew Lunn 	/* Have to be called without holding the register lock, since
2964e0c69ca7SAndrew Lunn 	 * they take the devlink lock, and we later take the locks in
2965e0c69ca7SAndrew Lunn 	 * the reverse order when getting/setting parameters or
2966e0c69ca7SAndrew Lunn 	 * resource occupancy.
296723e8b470SAndrew Lunn 	 */
2968e0c69ca7SAndrew Lunn 	err = mv88e6xxx_setup_devlink_resources(ds);
2969e0c69ca7SAndrew Lunn 	if (err)
2970e0c69ca7SAndrew Lunn 		return err;
2971e0c69ca7SAndrew Lunn 
2972e0c69ca7SAndrew Lunn 	err = mv88e6xxx_setup_devlink_params(ds);
2973e0c69ca7SAndrew Lunn 	if (err)
2974bfb25542SAndrew Lunn 		goto out_resources;
2975bfb25542SAndrew Lunn 
2976bfb25542SAndrew Lunn 	err = mv88e6xxx_setup_devlink_regions(ds);
2977bfb25542SAndrew Lunn 	if (err)
2978bfb25542SAndrew Lunn 		goto out_params;
2979bfb25542SAndrew Lunn 
2980bfb25542SAndrew Lunn 	return 0;
2981bfb25542SAndrew Lunn 
2982bfb25542SAndrew Lunn out_params:
2983bfb25542SAndrew Lunn 	mv88e6xxx_teardown_devlink_params(ds);
2984bfb25542SAndrew Lunn out_resources:
2985e0c69ca7SAndrew Lunn 	dsa_devlink_resources_unregister(ds);
2986e0c69ca7SAndrew Lunn 
2987e0c69ca7SAndrew Lunn 	return err;
2988fad09c73SVivien Didelot }
2989fad09c73SVivien Didelot 
2990e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
2991fad09c73SVivien Didelot {
29920dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
29930dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
2994e57e5e77SVivien Didelot 	u16 val;
2995e57e5e77SVivien Didelot 	int err;
2996fad09c73SVivien Didelot 
2997ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_read)
2998ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
2999ee26a228SAndrew Lunn 
3000c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3001ee26a228SAndrew Lunn 	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
3002c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3003e57e5e77SVivien Didelot 
3004da9f3301SAndrew Lunn 	if (reg == MII_PHYSID2) {
3005ddc49acbSAndrew Lunn 		/* Some internal PHYs don't have a model number. */
3006ddc49acbSAndrew Lunn 		if (chip->info->family != MV88E6XXX_FAMILY_6165)
3007ddc49acbSAndrew Lunn 			/* Then there is the 6165 family. It gets is
3008ddc49acbSAndrew Lunn 			 * PHYs correct. But it can also have two
3009ddc49acbSAndrew Lunn 			 * SERDES interfaces in the PHY address
3010ddc49acbSAndrew Lunn 			 * space. And these don't have a model
3011ddc49acbSAndrew Lunn 			 * number. But they are not PHYs, so we don't
3012ddc49acbSAndrew Lunn 			 * want to give them something a PHY driver
3013ddc49acbSAndrew Lunn 			 * will recognise.
3014ddc49acbSAndrew Lunn 			 *
3015ddc49acbSAndrew Lunn 			 * Use the mv88e6390 family model number
3016ddc49acbSAndrew Lunn 			 * instead, for anything which really could be
3017ddc49acbSAndrew Lunn 			 * a PHY,
3018da9f3301SAndrew Lunn 			 */
3019da9f3301SAndrew Lunn 			if (!(val & 0x3f0))
3020107fcc10SVivien Didelot 				val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4;
3021da9f3301SAndrew Lunn 	}
3022da9f3301SAndrew Lunn 
3023e57e5e77SVivien Didelot 	return err ? err : val;
3024fad09c73SVivien Didelot }
3025fad09c73SVivien Didelot 
3026e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
3027fad09c73SVivien Didelot {
30280dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
30290dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
3030e57e5e77SVivien Didelot 	int err;
3031fad09c73SVivien Didelot 
3032ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_write)
3033ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
3034ee26a228SAndrew Lunn 
3035c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3036ee26a228SAndrew Lunn 	err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
3037c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3038e57e5e77SVivien Didelot 
3039e57e5e77SVivien Didelot 	return err;
3040fad09c73SVivien Didelot }
3041fad09c73SVivien Didelot 
3042fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
3043a3c53be5SAndrew Lunn 				   struct device_node *np,
3044a3c53be5SAndrew Lunn 				   bool external)
3045fad09c73SVivien Didelot {
3046fad09c73SVivien Didelot 	static int index;
30470dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
3048fad09c73SVivien Didelot 	struct mii_bus *bus;
3049fad09c73SVivien Didelot 	int err;
3050fad09c73SVivien Didelot 
30512510babcSAndrew Lunn 	if (external) {
3052c9acece0SRasmus Villemoes 		mv88e6xxx_reg_lock(chip);
30532510babcSAndrew Lunn 		err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
3054c9acece0SRasmus Villemoes 		mv88e6xxx_reg_unlock(chip);
30552510babcSAndrew Lunn 
30562510babcSAndrew Lunn 		if (err)
30572510babcSAndrew Lunn 			return err;
30582510babcSAndrew Lunn 	}
30592510babcSAndrew Lunn 
30600dd12d54SAndrew Lunn 	bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
3061fad09c73SVivien Didelot 	if (!bus)
3062fad09c73SVivien Didelot 		return -ENOMEM;
3063fad09c73SVivien Didelot 
30640dd12d54SAndrew Lunn 	mdio_bus = bus->priv;
3065a3c53be5SAndrew Lunn 	mdio_bus->bus = bus;
30660dd12d54SAndrew Lunn 	mdio_bus->chip = chip;
3067a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&mdio_bus->list);
3068a3c53be5SAndrew Lunn 	mdio_bus->external = external;
30690dd12d54SAndrew Lunn 
3070fad09c73SVivien Didelot 	if (np) {
3071fad09c73SVivien Didelot 		bus->name = np->full_name;
3072f7ce9103SRob Herring 		snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np);
3073fad09c73SVivien Didelot 	} else {
3074fad09c73SVivien Didelot 		bus->name = "mv88e6xxx SMI";
3075fad09c73SVivien Didelot 		snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
3076fad09c73SVivien Didelot 	}
3077fad09c73SVivien Didelot 
3078fad09c73SVivien Didelot 	bus->read = mv88e6xxx_mdio_read;
3079fad09c73SVivien Didelot 	bus->write = mv88e6xxx_mdio_write;
3080fad09c73SVivien Didelot 	bus->parent = chip->dev;
3081fad09c73SVivien Didelot 
30826f88284fSAndrew Lunn 	if (!external) {
30836f88284fSAndrew Lunn 		err = mv88e6xxx_g2_irq_mdio_setup(chip, bus);
30846f88284fSAndrew Lunn 		if (err)
30856f88284fSAndrew Lunn 			return err;
30866f88284fSAndrew Lunn 	}
30876f88284fSAndrew Lunn 
3088a3c53be5SAndrew Lunn 	err = of_mdiobus_register(bus, np);
3089fad09c73SVivien Didelot 	if (err) {
3090fad09c73SVivien Didelot 		dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
30916f88284fSAndrew Lunn 		mv88e6xxx_g2_irq_mdio_free(chip, bus);
3092fad09c73SVivien Didelot 		return err;
3093fad09c73SVivien Didelot 	}
3094fad09c73SVivien Didelot 
3095a3c53be5SAndrew Lunn 	if (external)
3096a3c53be5SAndrew Lunn 		list_add_tail(&mdio_bus->list, &chip->mdios);
3097a3c53be5SAndrew Lunn 	else
3098a3c53be5SAndrew Lunn 		list_add(&mdio_bus->list, &chip->mdios);
3099a3c53be5SAndrew Lunn 
3100a3c53be5SAndrew Lunn 	return 0;
3101a3c53be5SAndrew Lunn }
3102a3c53be5SAndrew Lunn 
31033126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
31043126aeecSAndrew Lunn 
31053126aeecSAndrew Lunn {
31063126aeecSAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
31073126aeecSAndrew Lunn 	struct mii_bus *bus;
31083126aeecSAndrew Lunn 
31093126aeecSAndrew Lunn 	list_for_each_entry(mdio_bus, &chip->mdios, list) {
31103126aeecSAndrew Lunn 		bus = mdio_bus->bus;
31113126aeecSAndrew Lunn 
31126f88284fSAndrew Lunn 		if (!mdio_bus->external)
31136f88284fSAndrew Lunn 			mv88e6xxx_g2_irq_mdio_free(chip, bus);
31146f88284fSAndrew Lunn 
31153126aeecSAndrew Lunn 		mdiobus_unregister(bus);
31163126aeecSAndrew Lunn 	}
31173126aeecSAndrew Lunn }
31183126aeecSAndrew Lunn 
3119a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
3120a3c53be5SAndrew Lunn 				    struct device_node *np)
3121a3c53be5SAndrew Lunn {
3122a3c53be5SAndrew Lunn 	struct device_node *child;
3123a3c53be5SAndrew Lunn 	int err;
3124a3c53be5SAndrew Lunn 
3125a3c53be5SAndrew Lunn 	/* Always register one mdio bus for the internal/default mdio
3126a3c53be5SAndrew Lunn 	 * bus. This maybe represented in the device tree, but is
3127a3c53be5SAndrew Lunn 	 * optional.
3128a3c53be5SAndrew Lunn 	 */
3129a3c53be5SAndrew Lunn 	child = of_get_child_by_name(np, "mdio");
3130a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdio_register(chip, child, false);
3131a3c53be5SAndrew Lunn 	if (err)
3132a3c53be5SAndrew Lunn 		return err;
3133a3c53be5SAndrew Lunn 
3134a3c53be5SAndrew Lunn 	/* Walk the device tree, and see if there are any other nodes
3135a3c53be5SAndrew Lunn 	 * which say they are compatible with the external mdio
3136a3c53be5SAndrew Lunn 	 * bus.
3137a3c53be5SAndrew Lunn 	 */
3138a3c53be5SAndrew Lunn 	for_each_available_child_of_node(np, child) {
3139ceb96faeSAndrew Lunn 		if (of_device_is_compatible(
3140ceb96faeSAndrew Lunn 			    child, "marvell,mv88e6xxx-mdio-external")) {
3141a3c53be5SAndrew Lunn 			err = mv88e6xxx_mdio_register(chip, child, true);
31423126aeecSAndrew Lunn 			if (err) {
31433126aeecSAndrew Lunn 				mv88e6xxx_mdios_unregister(chip);
314478e42040SNishka Dasgupta 				of_node_put(child);
3145a3c53be5SAndrew Lunn 				return err;
3146a3c53be5SAndrew Lunn 			}
3147a3c53be5SAndrew Lunn 		}
31483126aeecSAndrew Lunn 	}
3149a3c53be5SAndrew Lunn 
3150a3c53be5SAndrew Lunn 	return 0;
3151a3c53be5SAndrew Lunn }
3152a3c53be5SAndrew Lunn 
3153855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
3154855b1932SVivien Didelot {
315504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3156855b1932SVivien Didelot 
3157855b1932SVivien Didelot 	return chip->eeprom_len;
3158855b1932SVivien Didelot }
3159855b1932SVivien Didelot 
3160855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
3161855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
3162855b1932SVivien Didelot {
316304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3164855b1932SVivien Didelot 	int err;
3165855b1932SVivien Didelot 
3166ee4dc2e7SVivien Didelot 	if (!chip->info->ops->get_eeprom)
3167ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
3168ee4dc2e7SVivien Didelot 
3169c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3170ee4dc2e7SVivien Didelot 	err = chip->info->ops->get_eeprom(chip, eeprom, data);
3171c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3172855b1932SVivien Didelot 
3173855b1932SVivien Didelot 	if (err)
3174855b1932SVivien Didelot 		return err;
3175855b1932SVivien Didelot 
3176855b1932SVivien Didelot 	eeprom->magic = 0xc3ec4951;
3177855b1932SVivien Didelot 
3178855b1932SVivien Didelot 	return 0;
3179855b1932SVivien Didelot }
3180855b1932SVivien Didelot 
3181855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
3182855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
3183855b1932SVivien Didelot {
318404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3185855b1932SVivien Didelot 	int err;
3186855b1932SVivien Didelot 
3187ee4dc2e7SVivien Didelot 	if (!chip->info->ops->set_eeprom)
3188ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
3189ee4dc2e7SVivien Didelot 
3190855b1932SVivien Didelot 	if (eeprom->magic != 0xc3ec4951)
3191855b1932SVivien Didelot 		return -EINVAL;
3192855b1932SVivien Didelot 
3193c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3194ee4dc2e7SVivien Didelot 	err = chip->info->ops->set_eeprom(chip, eeprom, data);
3195c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3196855b1932SVivien Didelot 
3197855b1932SVivien Didelot 	return err;
3198855b1932SVivien Didelot }
3199855b1932SVivien Didelot 
3200b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = {
32014b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6097 */
320293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
320393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3204cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3205b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
32067e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
32077e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
320808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3209f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3210ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
321156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3212601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
321356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3214ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
32150898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3216c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
32179dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
32182d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3219121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3220a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
322140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3222dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3223dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3224052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3225fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3226fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3227fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
322851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
32299e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
3230a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3231a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
323217e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
32339e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
3234f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
32350ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
32366c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
32371baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
3238b3469dd8SVivien Didelot };
3239b3469dd8SVivien Didelot 
3240b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = {
32414b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6095 */
324293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
324393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3244b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
32457e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
32467e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
324708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3248f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
324956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3250601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
3251a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
32522d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3253121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3254a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
325540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3256dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3257dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3258052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
325951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3260a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3261a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
326217e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3263f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
32640ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
32656c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
32661baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
3267b3469dd8SVivien Didelot };
3268b3469dd8SVivien Didelot 
32697d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = {
327015da3cc8SStefan Eichenberger 	/* MV88E6XXX_FAMILY_6097 */
327193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
327293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3273cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
32747d381a02SStefan Eichenberger 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
32757d381a02SStefan Eichenberger 	.phy_read = mv88e6xxx_g2_smi_phy_read,
32767d381a02SStefan Eichenberger 	.phy_write = mv88e6xxx_g2_smi_phy_write,
32777d381a02SStefan Eichenberger 	.port_set_link = mv88e6xxx_port_set_link,
3278f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3279ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
328056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3281601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
328256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3283ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
32840898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3285c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
32869dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
32872d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3288121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
32897d381a02SStefan Eichenberger 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
329040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
32917d381a02SStefan Eichenberger 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
32927d381a02SStefan Eichenberger 	.stats_get_strings = mv88e6095_stats_get_strings,
32937d381a02SStefan Eichenberger 	.stats_get_stats = mv88e6095_stats_get_stats,
3294fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3295fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
329691eaa475SVolodymyr Bendiuga 	.watchdog_ops = &mv88e6097_watchdog_ops,
329751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
32989e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
329917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
33009e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
3301f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
33020ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
33036c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
33041baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
33057d381a02SStefan Eichenberger };
33067d381a02SStefan Eichenberger 
3307b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = {
33084b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
330993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
331093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3311cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3312b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3313ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3314ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
331508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3316f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
331756995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3318601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3319c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
33209dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
33212d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3322121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
33230ac64c39SAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
332440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3325dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3326dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3327052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3328fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3329fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3330fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
333151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
33329e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
333317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
333423e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
333523e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3336f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
33370ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
33386c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
33391baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
3340b3469dd8SVivien Didelot };
3341b3469dd8SVivien Didelot 
3342b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = {
33434b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
334493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
334593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3346b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
33477e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
33487e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
334908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3350f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3351ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
335256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3353601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
335456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3355a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
3356cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3357ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
33580898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
335954186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
33602d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3361121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3362a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
336340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3364dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3365dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3366052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3367fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3368fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3369fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
337051c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3371a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
337202317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3373a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
337417e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3375f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
33760ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
33776c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3378b3469dd8SVivien Didelot };
3379b3469dd8SVivien Didelot 
3380990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = {
3381990e27b0SVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
338293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
338393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3384cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3385990e27b0SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
3386990e27b0SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3387990e27b0SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3388990e27b0SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3389990e27b0SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
3390990e27b0SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3391990e27b0SVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3392f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
33937cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
3394990e27b0SVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
3395990e27b0SVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3396990e27b0SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3397990e27b0SVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3398cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3399990e27b0SVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
34000898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3401990e27b0SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3402990e27b0SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34032d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
34047a3007d2SMarek Behún 	.port_set_cmode = mv88e6341_port_set_cmode,
3405121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3406990e27b0SVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
340740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3408990e27b0SVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3409990e27b0SVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
3410990e27b0SVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
3411fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3412fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
3413990e27b0SVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
3414990e27b0SVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
34159e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
3416990e27b0SVivien Didelot 	.reset = mv88e6352_g1_reset,
3417f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
34180ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3419d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
3420d3cf7d8fSMarek Behún 	.serdes_get_lane = mv88e6341_serdes_get_lane,
3421a5a6858bSRussell King 	/* Check status register pause & lpa register */
3422a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
3423a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
3424a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
3425a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
34264241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
342761a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3428907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
3429a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
3430e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
3431990e27b0SVivien Didelot };
3432990e27b0SVivien Didelot 
3433b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = {
34344b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
343593e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
343693e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3437cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3438b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3439ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3440ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
344108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3442f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3443ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
344456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3445601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
344656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3447cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3448ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
34490898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3450c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
34519dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34522d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3453121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3454a6da21bbSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
345540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3456dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3457dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3458052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3459fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3460fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3461fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
346251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
34639e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
346417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
346523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
346623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3467f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
34680ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3469a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3470dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
34716c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3472b3469dd8SVivien Didelot };
3473b3469dd8SVivien Didelot 
3474b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = {
34754b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
347693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
347793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3478cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3479b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3480efb3e74dSAndrew Lunn 	.phy_read = mv88e6165_phy_read,
3481efb3e74dSAndrew Lunn 	.phy_write = mv88e6165_phy_write,
348208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3483f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3484c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
34859dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34862d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3487121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3488a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
348940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3490dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3491dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3492052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3493fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3494fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3495fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
349651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
34979e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
349817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
349923e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
350023e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3501f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
35020ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3503a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3504dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
35056c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3506b3469dd8SVivien Didelot };
3507b3469dd8SVivien Didelot 
3508b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = {
35094b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
351093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
351193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3512cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3513b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3514b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3515b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
351608ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
351794d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3518f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3519ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
352056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3521601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
352256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3523cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3524ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
35250898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3526c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
35279dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35282d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3529121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3530a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
353140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3532dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3533dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3534052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3535fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3536fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3537fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
353851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
35399e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
354017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
354123e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
354223e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3543f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
35440ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
35456c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3546b3469dd8SVivien Didelot };
3547b3469dd8SVivien Didelot 
3548b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = {
35494b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
355093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
355193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3552cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3553ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3554ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3555b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3556b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3557b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
355808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3559a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3560f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
3561ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
3562f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
356356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3564601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
356556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3566cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3567ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
35680898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3569c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
35709dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35712d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3572121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3573a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
357440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3575dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3576dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3577052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3578fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3579fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3580fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
358151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
35829e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
358317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
35849e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
358523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
358623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3587f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
35880ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
35899db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
3590a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
3591a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
3592a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
3593a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
35946d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
3595d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
3596d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
3597a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
35986c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3599b3469dd8SVivien Didelot };
3600b3469dd8SVivien Didelot 
3601b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = {
36024b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
360393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
360493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3605cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3606b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3607b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3608b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
360908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
361094d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3611f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3612ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
361356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3614601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
361556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3616cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3617ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36180898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3619c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36209dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36212d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3622121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3623a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
362440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3625dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3626dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3627052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3628fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3629fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3630fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
363151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
36329e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
363317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
363423e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
363523e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3636f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
36370ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
36386c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3639b3469dd8SVivien Didelot };
3640b3469dd8SVivien Didelot 
3641b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = {
36424b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
364393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
364493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3645cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3646ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3647ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3648b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3649b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3650b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
365108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3652a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3653f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
3654ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
3655f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
365656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3657601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
365856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3659cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3660ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36610898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3662c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36639dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36642d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3665121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3666a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
366740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3668dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3669dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3670052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3671fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3672fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3673fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
367451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
36759e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
367617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
36779e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
367823e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
367923e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3680f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
36810ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
36829db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
3683a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
3684a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
3685a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
3686a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
36876d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
36884241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
368961a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
3690907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
3691d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
3692d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
3693a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
36946c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3695b3469dd8SVivien Didelot };
3696b3469dd8SVivien Didelot 
3697b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = {
36984b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
369993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
370093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3701b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
37027e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
37037e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
370408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3705f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
370656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3707601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
3708ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
3709a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
371054186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
37112d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3712121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3713a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
371440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3715dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3716dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3717052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3718fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3719fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3720fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
372151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
372202317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3723a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3724a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
372517e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3726f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
37270ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
37286c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
37291baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
3730b3469dd8SVivien Didelot };
3731b3469dd8SVivien Didelot 
37321a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = {
37334b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3734ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3735cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
373698fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
373798fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
37381a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
37391a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
37401a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
37411a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
37421a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3743f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
37447cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
3745ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
3746f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
374756995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3748601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
374956995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3750e8b34c67SChris Packham 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
37510898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3752c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
37539dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37542d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3755fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
3756121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
375779523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3758de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3759dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3760dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3761e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3762fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3763fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
376461303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
37656e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
37669e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
376717e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
37689e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
376923e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
377023e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3771931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3772931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
37736335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
377417deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
3775a5a6858bSRussell King 	/* Check status register pause & lpa register */
3776a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
3777a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
3778a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
3779a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
37804241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
378161a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3782907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
37834262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
37844262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
3785bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
3786bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
3787a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
37886c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
37891a3b39ecSAndrew Lunn };
37901a3b39ecSAndrew Lunn 
37911a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = {
37924b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3793ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3794cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
379598fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
379698fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
37971a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
37981a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
37991a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
38001a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
38011a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3802f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
38037cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
3804ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
3805f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
380656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3807601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
380856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3809e8b34c67SChris Packham 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
38100898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3811c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38129dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38132d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3814fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
3815121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
381679523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3817de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3818dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3819dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3820e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3821fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3822fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
382361303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
38246e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
38259e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
382617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
38279e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
382823e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
382923e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3830931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3831931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
3832d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
383317deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390x_serdes_get_lane,
3834a5a6858bSRussell King 	/* Check status register pause & lpa register */
3835a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
3836a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
3837a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
3838a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
38394241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
384061a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3841907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
38424262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
38434262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
3844bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
3845bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
3846a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
38476c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
38481a3b39ecSAndrew Lunn };
38491a3b39ecSAndrew Lunn 
38501a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = {
38514b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3852ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3853cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
385498fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
385598fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
38561a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
38571a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
38581a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
38591a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
38601a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3861f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
38627cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
3863ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
386456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3865601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
386656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
38670898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3868c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38699dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38702d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3871fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
3872121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
387379523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3874de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3875dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3876dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3877e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3878fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3879fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
388061303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
38816e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
38829e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
388317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
38849e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
388523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
388623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3887931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3888931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
38896335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
389017deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
3891a5a6858bSRussell King 	/* Check status register pause & lpa register */
3892a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
3893a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
3894a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
3895a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
38964241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
389761a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3898907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
38994262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
39004262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
3901bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
3902bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
39036d2ac8eeSAndrew Lunn 	.avb_ops = &mv88e6390_avb_ops,
39046d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
39056c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
39061a3b39ecSAndrew Lunn };
39071a3b39ecSAndrew Lunn 
3908b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = {
39094b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
391093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
391193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3912cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3913ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3914ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3915b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3916b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3917b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
391808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3919a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3920f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
3921ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
3922f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
392356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3924601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
392556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3926cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3927ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
39280898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3929c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
39309dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
39312d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3932121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3933a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
393440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3935dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3936dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3937052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3938fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3939fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3940fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
394151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
39429e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
394317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
39449e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
394523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
394623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3947f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
39480ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
39499db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
3950a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
3951a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
3952a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
3953a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
39546d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
39554241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
395661a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
3957907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
3958d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
3959d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
3960a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
39610d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
39626d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
39636c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3964b3469dd8SVivien Didelot };
3965b3469dd8SVivien Didelot 
39661f71836fSRasmus Villemoes static const struct mv88e6xxx_ops mv88e6250_ops = {
39671f71836fSRasmus Villemoes 	/* MV88E6XXX_FAMILY_6250 */
39681f71836fSRasmus Villemoes 	.ieee_pri_map = mv88e6250_g1_ieee_pri_map,
39691f71836fSRasmus Villemoes 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
39701f71836fSRasmus Villemoes 	.irl_init_all = mv88e6352_g2_irl_init_all,
39711f71836fSRasmus Villemoes 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
39721f71836fSRasmus Villemoes 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
39731f71836fSRasmus Villemoes 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
39741f71836fSRasmus Villemoes 	.phy_read = mv88e6xxx_g2_smi_phy_read,
39751f71836fSRasmus Villemoes 	.phy_write = mv88e6xxx_g2_smi_phy_write,
39761f71836fSRasmus Villemoes 	.port_set_link = mv88e6xxx_port_set_link,
39771f71836fSRasmus Villemoes 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3978f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6250_port_set_speed_duplex,
39791f71836fSRasmus Villemoes 	.port_tag_remap = mv88e6095_port_tag_remap,
39801f71836fSRasmus Villemoes 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
39811f71836fSRasmus Villemoes 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
39821f71836fSRasmus Villemoes 	.port_set_ether_type = mv88e6351_port_set_ether_type,
39831f71836fSRasmus Villemoes 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
39841f71836fSRasmus Villemoes 	.port_pause_limit = mv88e6097_port_pause_limit,
39851f71836fSRasmus Villemoes 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
39861f71836fSRasmus Villemoes 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
39871f71836fSRasmus Villemoes 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
39881f71836fSRasmus Villemoes 	.stats_get_sset_count = mv88e6250_stats_get_sset_count,
39891f71836fSRasmus Villemoes 	.stats_get_strings = mv88e6250_stats_get_strings,
39901f71836fSRasmus Villemoes 	.stats_get_stats = mv88e6250_stats_get_stats,
39911f71836fSRasmus Villemoes 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
39921f71836fSRasmus Villemoes 	.set_egress_port = mv88e6095_g1_set_egress_port,
39931f71836fSRasmus Villemoes 	.watchdog_ops = &mv88e6250_watchdog_ops,
39941f71836fSRasmus Villemoes 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
39951f71836fSRasmus Villemoes 	.pot_clear = mv88e6xxx_g2_pot_clear,
39961f71836fSRasmus Villemoes 	.reset = mv88e6250_g1_reset,
39971f71836fSRasmus Villemoes 	.vtu_getnext = mv88e6250_g1_vtu_getnext,
39981f71836fSRasmus Villemoes 	.vtu_loadpurge = mv88e6250_g1_vtu_loadpurge,
399971509614SHubert Feurstein 	.avb_ops = &mv88e6352_avb_ops,
400071509614SHubert Feurstein 	.ptp_ops = &mv88e6250_ptp_ops,
40011f71836fSRasmus Villemoes 	.phylink_validate = mv88e6065_phylink_validate,
40021f71836fSRasmus Villemoes };
40031f71836fSRasmus Villemoes 
40041a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = {
40054b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4006ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4007cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
400898fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
400998fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
40101a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
40111a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
40121a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
40131a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
40141a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4015f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
40167cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4017ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4018f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
401956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4020601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
402156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
40220898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4023c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
40249dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
40252d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4026fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4027121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
402879523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4029de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4030dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4031dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4032e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4033fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4034fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
403561303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
40366e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
40379e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
403817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
40399e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
404023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
404123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4042931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4043931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
40446335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
404517deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
4046a5a6858bSRussell King 	/* Check status register pause & lpa register */
4047a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4048a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4049a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4050a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
40514241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
405261a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4053907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
40544262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
40554262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4056bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4057bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
4058a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
40590d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
40606d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
40616c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
40621a3b39ecSAndrew Lunn };
40631a3b39ecSAndrew Lunn 
4064b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = {
40654b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6320 */
406693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
406793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4068cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4069ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4070ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4071b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4072b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4073b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
407408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
4075f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4076ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
407756995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4078601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
407956995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4080cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4081ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
40820898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4083c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
40849dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
40852d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4086121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4087a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
408840cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4089dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4090dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4091052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
4092fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4093fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
40949c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
409551c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
40969e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
409717e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
4098f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
40990ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4100a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
41010d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
41026d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
41036c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4104b3469dd8SVivien Didelot };
4105b3469dd8SVivien Didelot 
4106b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = {
4107bd807204SVivien Didelot 	/* MV88E6XXX_FAMILY_6320 */
410893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
410993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4110cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4111ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4112ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4113b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4114b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4115b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
411608ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
4117f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4118ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
411956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4120601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
412156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4122cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4123ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
41240898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4125c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
41269dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
41272d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4128121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4129a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
413040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4131dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4132dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4133052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
4134fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4135fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
41369c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
413717e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
4138f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
41390ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4140a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
41410d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
41426d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
41436c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4144b3469dd8SVivien Didelot };
4145b3469dd8SVivien Didelot 
414616e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = {
414716e329aeSVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
414893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
414993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4150cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
415116e329aeSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
415216e329aeSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
415316e329aeSVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
415416e329aeSVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
415516e329aeSVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
415616e329aeSVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
415716e329aeSVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4158f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
41597cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
416016e329aeSVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
416116e329aeSVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
416216e329aeSVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
416316e329aeSVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4164cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
416516e329aeSVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
41660898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
416716e329aeSVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
416816e329aeSVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
41692d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
41707a3007d2SMarek Behún 	.port_set_cmode = mv88e6341_port_set_cmode,
4171121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
417216e329aeSVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
417340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
417416e329aeSVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
417516e329aeSVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
417616e329aeSVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
4177fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4178fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
417916e329aeSVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
418016e329aeSVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
41819e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
418216e329aeSVivien Didelot 	.reset = mv88e6352_g1_reset,
4183f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
41840ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4185d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
4186d3cf7d8fSMarek Behún 	.serdes_get_lane = mv88e6341_serdes_get_lane,
4187a5a6858bSRussell King 	/* Check status register pause & lpa register */
4188a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4189a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4190a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4191a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
41924241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
419361a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4194907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
4195a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
41960d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
41976d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
4198e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
419916e329aeSVivien Didelot };
420016e329aeSVivien Didelot 
4201b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = {
42024b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
420393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
420493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4205cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4206b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4207b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4208b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
420908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
421094d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4211f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4212ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
421356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4214601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
421556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4216cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4217ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
42180898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4219c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
42209dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
42212d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4222121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4223a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
422440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4225dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4226dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4227052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4228fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4229fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4230fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
423151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
42329e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
423317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
423423e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
423523e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4236f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
42370ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
42386c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4239b3469dd8SVivien Didelot };
4240b3469dd8SVivien Didelot 
4241b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = {
42424b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
424393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
424493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4245cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4246b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4247b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4248b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
424908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
425094d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4251f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4252ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
425356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4254601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
425556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4256cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4257ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
42580898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4259c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
42609dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
42612d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4262121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4263a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
426440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4265dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4266dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4267052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4268fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4269fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4270fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
427151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
42729e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
427317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
427423e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
427523e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4276f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
42770ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
42780d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
42796d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
42806c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4281b3469dd8SVivien Didelot };
4282b3469dd8SVivien Didelot 
4283b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = {
42844b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
428593e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
428693e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4287cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4288ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4289ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4290b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4291b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4292b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
429308ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
4294a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4295f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
4296ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
4297f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
429856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4299601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
430056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4301cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4302ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
43030898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4304c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
43059dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
43062d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4307121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4308a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
430940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4310dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4311dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4312052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4313fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4314fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4315fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
431651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
43179e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
431817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
43199e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
432023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
432123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4322f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
43230ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
43249db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
4325a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
4326a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
4327a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
4328a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
43296d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
43304241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
433161a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4332907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
4333a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
43340d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
43356d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
4336cda9f4aaSAndrew Lunn 	.serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
4337cda9f4aaSAndrew Lunn 	.serdes_get_strings = mv88e6352_serdes_get_strings,
4338cda9f4aaSAndrew Lunn 	.serdes_get_stats = mv88e6352_serdes_get_stats,
4339d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
4340d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
43416c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
4342b3469dd8SVivien Didelot };
4343b3469dd8SVivien Didelot 
43441a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = {
43454b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4346ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4347cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
434898fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
434998fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
43501a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
43511a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
43521a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
43531a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
43541a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4355f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
43567cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4357ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4358f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
435956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4360601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
436156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4362cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4363ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
43640898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4365c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
43669dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
43672d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4368fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4369121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
437079523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4371de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4372dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4373dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4374e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4375fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4376fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
437761303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
43786e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
43799e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
438017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
43819e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
438223e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
438323e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4384931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4385931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
43866335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
438717deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
4388a5a6858bSRussell King 	/* Check status register pause & lpa register */
4389a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4390a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4391a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4392a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
43934241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
439461a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4395907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
4396a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
43970d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
43986d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
43990df95287SNikita Yushchenko 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
44000df95287SNikita Yushchenko 	.serdes_get_strings = mv88e6390_serdes_get_strings,
44010df95287SNikita Yushchenko 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4402bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4403bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
44046c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
44051a3b39ecSAndrew Lunn };
44061a3b39ecSAndrew Lunn 
44071a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = {
44084b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4409ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4410cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
441198fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
441298fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
44131a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
44141a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
44151a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
44161a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
44171a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4418f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
44197cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
4420ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4421f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
442256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4423601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
442456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4425cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4426ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
44270898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4428c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
44299dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
44302d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4431b3dce4daSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
4432121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
443379523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4434de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4435dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4436dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4437e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4438fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4439fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
444061303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
44416e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
44429e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
444317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
44449e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
444523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
444623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4447931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4448931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4449d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
445017deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390x_serdes_get_lane,
4451a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4452a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4453a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4454a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
44554241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
445661a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4457907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
44584262c38dSAndrew Lunn 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
44594262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
44604262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4461bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4462bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
4463a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
44640d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
44656d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
44666c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
44671a3b39ecSAndrew Lunn };
44681a3b39ecSAndrew Lunn 
4469fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = {
4470fad09c73SVivien Didelot 	[MV88E6085] = {
4471107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
4472fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6097,
4473fad09c73SVivien Didelot 		.name = "Marvell 88E6085",
4474fad09c73SVivien Didelot 		.num_databases = 4096,
4475d9ea5620SAndrew Lunn 		.num_macs = 8192,
4476fad09c73SVivien Didelot 		.num_ports = 10,
4477bc393155SAndrew Lunn 		.num_internal_phys = 5,
44783cf3c846SVivien Didelot 		.max_vid = 4095,
4479fad09c73SVivien Didelot 		.port_base_addr = 0x10,
44809255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4481a935c052SVivien Didelot 		.global1_addr = 0x1b,
44829069c13aSVivien Didelot 		.global2_addr = 0x1c,
4483acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4484dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4485d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4486e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4487f3645652SVivien Didelot 		.pvt = true,
4488b3e05aa1SVivien Didelot 		.multi_chip = true,
4489443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4490b3469dd8SVivien Didelot 		.ops = &mv88e6085_ops,
4491fad09c73SVivien Didelot 	},
4492fad09c73SVivien Didelot 
4493fad09c73SVivien Didelot 	[MV88E6095] = {
4494107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095,
4495fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6095,
4496fad09c73SVivien Didelot 		.name = "Marvell 88E6095/88E6095F",
4497fad09c73SVivien Didelot 		.num_databases = 256,
4498d9ea5620SAndrew Lunn 		.num_macs = 8192,
4499fad09c73SVivien Didelot 		.num_ports = 11,
4500bc393155SAndrew Lunn 		.num_internal_phys = 0,
45013cf3c846SVivien Didelot 		.max_vid = 4095,
4502fad09c73SVivien Didelot 		.port_base_addr = 0x10,
45039255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4504a935c052SVivien Didelot 		.global1_addr = 0x1b,
45059069c13aSVivien Didelot 		.global2_addr = 0x1c,
4506acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4507dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4508e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4509b3e05aa1SVivien Didelot 		.multi_chip = true,
4510443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4511b3469dd8SVivien Didelot 		.ops = &mv88e6095_ops,
4512fad09c73SVivien Didelot 	},
4513fad09c73SVivien Didelot 
45147d381a02SStefan Eichenberger 	[MV88E6097] = {
4515107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097,
45167d381a02SStefan Eichenberger 		.family = MV88E6XXX_FAMILY_6097,
45177d381a02SStefan Eichenberger 		.name = "Marvell 88E6097/88E6097F",
45187d381a02SStefan Eichenberger 		.num_databases = 4096,
4519d9ea5620SAndrew Lunn 		.num_macs = 8192,
45207d381a02SStefan Eichenberger 		.num_ports = 11,
4521bc393155SAndrew Lunn 		.num_internal_phys = 8,
45223cf3c846SVivien Didelot 		.max_vid = 4095,
45237d381a02SStefan Eichenberger 		.port_base_addr = 0x10,
45249255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
45257d381a02SStefan Eichenberger 		.global1_addr = 0x1b,
45269069c13aSVivien Didelot 		.global2_addr = 0x1c,
45277d381a02SStefan Eichenberger 		.age_time_coeff = 15000,
4528c534178bSStefan Eichenberger 		.g1_irqs = 8,
4529d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4530e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4531f3645652SVivien Didelot 		.pvt = true,
4532b3e05aa1SVivien Didelot 		.multi_chip = true,
45332bfcfcd3SStefan Eichenberger 		.tag_protocol = DSA_TAG_PROTO_EDSA,
45347d381a02SStefan Eichenberger 		.ops = &mv88e6097_ops,
45357d381a02SStefan Eichenberger 	},
45367d381a02SStefan Eichenberger 
4537fad09c73SVivien Didelot 	[MV88E6123] = {
4538107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123,
4539fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4540fad09c73SVivien Didelot 		.name = "Marvell 88E6123",
4541fad09c73SVivien Didelot 		.num_databases = 4096,
4542d9ea5620SAndrew Lunn 		.num_macs = 1024,
4543fad09c73SVivien Didelot 		.num_ports = 3,
4544bc393155SAndrew Lunn 		.num_internal_phys = 5,
45453cf3c846SVivien Didelot 		.max_vid = 4095,
4546fad09c73SVivien Didelot 		.port_base_addr = 0x10,
45479255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4548a935c052SVivien Didelot 		.global1_addr = 0x1b,
45499069c13aSVivien Didelot 		.global2_addr = 0x1c,
4550acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4551dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4552d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4553e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4554f3645652SVivien Didelot 		.pvt = true,
4555b3e05aa1SVivien Didelot 		.multi_chip = true,
45565ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4557b3469dd8SVivien Didelot 		.ops = &mv88e6123_ops,
4558fad09c73SVivien Didelot 	},
4559fad09c73SVivien Didelot 
4560fad09c73SVivien Didelot 	[MV88E6131] = {
4561107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131,
4562fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
4563fad09c73SVivien Didelot 		.name = "Marvell 88E6131",
4564fad09c73SVivien Didelot 		.num_databases = 256,
4565d9ea5620SAndrew Lunn 		.num_macs = 8192,
4566fad09c73SVivien Didelot 		.num_ports = 8,
4567bc393155SAndrew Lunn 		.num_internal_phys = 0,
45683cf3c846SVivien Didelot 		.max_vid = 4095,
4569fad09c73SVivien Didelot 		.port_base_addr = 0x10,
45709255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4571a935c052SVivien Didelot 		.global1_addr = 0x1b,
45729069c13aSVivien Didelot 		.global2_addr = 0x1c,
4573acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4574dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4575e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4576b3e05aa1SVivien Didelot 		.multi_chip = true,
4577443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4578b3469dd8SVivien Didelot 		.ops = &mv88e6131_ops,
4579fad09c73SVivien Didelot 	},
4580fad09c73SVivien Didelot 
4581990e27b0SVivien Didelot 	[MV88E6141] = {
4582107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141,
4583990e27b0SVivien Didelot 		.family = MV88E6XXX_FAMILY_6341,
458479a68b26SUwe Kleine-König 		.name = "Marvell 88E6141",
4585990e27b0SVivien Didelot 		.num_databases = 4096,
4586d9ea5620SAndrew Lunn 		.num_macs = 2048,
4587990e27b0SVivien Didelot 		.num_ports = 6,
4588bc393155SAndrew Lunn 		.num_internal_phys = 5,
4589a73ccd61SBrandon Streiff 		.num_gpio = 11,
45903cf3c846SVivien Didelot 		.max_vid = 4095,
4591990e27b0SVivien Didelot 		.port_base_addr = 0x10,
45929255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
4593990e27b0SVivien Didelot 		.global1_addr = 0x1b,
45949069c13aSVivien Didelot 		.global2_addr = 0x1c,
4595990e27b0SVivien Didelot 		.age_time_coeff = 3750,
4596990e27b0SVivien Didelot 		.atu_move_port_mask = 0x1f,
4597adfccf11SAndrew Lunn 		.g1_irqs = 9,
4598d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4599f3645652SVivien Didelot 		.pvt = true,
4600b3e05aa1SVivien Didelot 		.multi_chip = true,
4601990e27b0SVivien Didelot 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4602990e27b0SVivien Didelot 		.ops = &mv88e6141_ops,
4603990e27b0SVivien Didelot 	},
4604990e27b0SVivien Didelot 
4605fad09c73SVivien Didelot 	[MV88E6161] = {
4606107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161,
4607fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4608fad09c73SVivien Didelot 		.name = "Marvell 88E6161",
4609fad09c73SVivien Didelot 		.num_databases = 4096,
4610d9ea5620SAndrew Lunn 		.num_macs = 1024,
4611fad09c73SVivien Didelot 		.num_ports = 6,
4612bc393155SAndrew Lunn 		.num_internal_phys = 5,
46133cf3c846SVivien Didelot 		.max_vid = 4095,
4614fad09c73SVivien Didelot 		.port_base_addr = 0x10,
46159255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4616a935c052SVivien Didelot 		.global1_addr = 0x1b,
46179069c13aSVivien Didelot 		.global2_addr = 0x1c,
4618acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4619dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4620d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4621e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4622f3645652SVivien Didelot 		.pvt = true,
4623b3e05aa1SVivien Didelot 		.multi_chip = true,
46245ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4625dfa54348SAndrew Lunn 		.ptp_support = true,
4626b3469dd8SVivien Didelot 		.ops = &mv88e6161_ops,
4627fad09c73SVivien Didelot 	},
4628fad09c73SVivien Didelot 
4629fad09c73SVivien Didelot 	[MV88E6165] = {
4630107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165,
4631fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4632fad09c73SVivien Didelot 		.name = "Marvell 88E6165",
4633fad09c73SVivien Didelot 		.num_databases = 4096,
4634d9ea5620SAndrew Lunn 		.num_macs = 8192,
4635fad09c73SVivien Didelot 		.num_ports = 6,
4636bc393155SAndrew Lunn 		.num_internal_phys = 0,
46373cf3c846SVivien Didelot 		.max_vid = 4095,
4638fad09c73SVivien Didelot 		.port_base_addr = 0x10,
46399255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4640a935c052SVivien Didelot 		.global1_addr = 0x1b,
46419069c13aSVivien Didelot 		.global2_addr = 0x1c,
4642acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4643dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4644d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4645e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4646f3645652SVivien Didelot 		.pvt = true,
4647b3e05aa1SVivien Didelot 		.multi_chip = true,
4648443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4649dfa54348SAndrew Lunn 		.ptp_support = true,
4650b3469dd8SVivien Didelot 		.ops = &mv88e6165_ops,
4651fad09c73SVivien Didelot 	},
4652fad09c73SVivien Didelot 
4653fad09c73SVivien Didelot 	[MV88E6171] = {
4654107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171,
4655fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4656fad09c73SVivien Didelot 		.name = "Marvell 88E6171",
4657fad09c73SVivien Didelot 		.num_databases = 4096,
4658d9ea5620SAndrew Lunn 		.num_macs = 8192,
4659fad09c73SVivien Didelot 		.num_ports = 7,
4660bc393155SAndrew Lunn 		.num_internal_phys = 5,
46613cf3c846SVivien Didelot 		.max_vid = 4095,
4662fad09c73SVivien Didelot 		.port_base_addr = 0x10,
46639255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4664a935c052SVivien Didelot 		.global1_addr = 0x1b,
46659069c13aSVivien Didelot 		.global2_addr = 0x1c,
4666acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4667dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4668d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4669e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4670f3645652SVivien Didelot 		.pvt = true,
4671b3e05aa1SVivien Didelot 		.multi_chip = true,
4672443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4673b3469dd8SVivien Didelot 		.ops = &mv88e6171_ops,
4674fad09c73SVivien Didelot 	},
4675fad09c73SVivien Didelot 
4676fad09c73SVivien Didelot 	[MV88E6172] = {
4677107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172,
4678fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4679fad09c73SVivien Didelot 		.name = "Marvell 88E6172",
4680fad09c73SVivien Didelot 		.num_databases = 4096,
4681d9ea5620SAndrew Lunn 		.num_macs = 8192,
4682fad09c73SVivien Didelot 		.num_ports = 7,
4683bc393155SAndrew Lunn 		.num_internal_phys = 5,
4684a73ccd61SBrandon Streiff 		.num_gpio = 15,
46853cf3c846SVivien Didelot 		.max_vid = 4095,
4686fad09c73SVivien Didelot 		.port_base_addr = 0x10,
46879255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4688a935c052SVivien Didelot 		.global1_addr = 0x1b,
46899069c13aSVivien Didelot 		.global2_addr = 0x1c,
4690acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4691dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4692d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4693e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4694f3645652SVivien Didelot 		.pvt = true,
4695b3e05aa1SVivien Didelot 		.multi_chip = true,
4696443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4697b3469dd8SVivien Didelot 		.ops = &mv88e6172_ops,
4698fad09c73SVivien Didelot 	},
4699fad09c73SVivien Didelot 
4700fad09c73SVivien Didelot 	[MV88E6175] = {
4701107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175,
4702fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4703fad09c73SVivien Didelot 		.name = "Marvell 88E6175",
4704fad09c73SVivien Didelot 		.num_databases = 4096,
4705d9ea5620SAndrew Lunn 		.num_macs = 8192,
4706fad09c73SVivien Didelot 		.num_ports = 7,
4707bc393155SAndrew Lunn 		.num_internal_phys = 5,
47083cf3c846SVivien Didelot 		.max_vid = 4095,
4709fad09c73SVivien Didelot 		.port_base_addr = 0x10,
47109255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4711a935c052SVivien Didelot 		.global1_addr = 0x1b,
47129069c13aSVivien Didelot 		.global2_addr = 0x1c,
4713acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4714dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4715d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4716e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4717f3645652SVivien Didelot 		.pvt = true,
4718b3e05aa1SVivien Didelot 		.multi_chip = true,
4719443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4720b3469dd8SVivien Didelot 		.ops = &mv88e6175_ops,
4721fad09c73SVivien Didelot 	},
4722fad09c73SVivien Didelot 
4723fad09c73SVivien Didelot 	[MV88E6176] = {
4724107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176,
4725fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4726fad09c73SVivien Didelot 		.name = "Marvell 88E6176",
4727fad09c73SVivien Didelot 		.num_databases = 4096,
4728d9ea5620SAndrew Lunn 		.num_macs = 8192,
4729fad09c73SVivien Didelot 		.num_ports = 7,
4730bc393155SAndrew Lunn 		.num_internal_phys = 5,
4731a73ccd61SBrandon Streiff 		.num_gpio = 15,
47323cf3c846SVivien Didelot 		.max_vid = 4095,
4733fad09c73SVivien Didelot 		.port_base_addr = 0x10,
47349255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4735a935c052SVivien Didelot 		.global1_addr = 0x1b,
47369069c13aSVivien Didelot 		.global2_addr = 0x1c,
4737acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4738dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4739d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4740e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4741f3645652SVivien Didelot 		.pvt = true,
4742b3e05aa1SVivien Didelot 		.multi_chip = true,
4743443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4744b3469dd8SVivien Didelot 		.ops = &mv88e6176_ops,
4745fad09c73SVivien Didelot 	},
4746fad09c73SVivien Didelot 
4747fad09c73SVivien Didelot 	[MV88E6185] = {
4748107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185,
4749fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
4750fad09c73SVivien Didelot 		.name = "Marvell 88E6185",
4751fad09c73SVivien Didelot 		.num_databases = 256,
4752d9ea5620SAndrew Lunn 		.num_macs = 8192,
4753fad09c73SVivien Didelot 		.num_ports = 10,
4754bc393155SAndrew Lunn 		.num_internal_phys = 0,
47553cf3c846SVivien Didelot 		.max_vid = 4095,
4756fad09c73SVivien Didelot 		.port_base_addr = 0x10,
47579255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4758a935c052SVivien Didelot 		.global1_addr = 0x1b,
47599069c13aSVivien Didelot 		.global2_addr = 0x1c,
4760acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4761dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4762e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4763b3e05aa1SVivien Didelot 		.multi_chip = true,
4764443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4765b3469dd8SVivien Didelot 		.ops = &mv88e6185_ops,
4766fad09c73SVivien Didelot 	},
4767fad09c73SVivien Didelot 
47681a3b39ecSAndrew Lunn 	[MV88E6190] = {
4769107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190,
47701a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
47711a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190",
47721a3b39ecSAndrew Lunn 		.num_databases = 4096,
4773d9ea5620SAndrew Lunn 		.num_macs = 16384,
47741a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
477595150f29SHeiner Kallweit 		.num_internal_phys = 9,
4776a73ccd61SBrandon Streiff 		.num_gpio = 16,
4777931d1822SVivien Didelot 		.max_vid = 8191,
47781a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
47799255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
47801a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
47819069c13aSVivien Didelot 		.global2_addr = 0x1c,
4782443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4783b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
47841a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4785d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4786f3645652SVivien Didelot 		.pvt = true,
4787b3e05aa1SVivien Didelot 		.multi_chip = true,
4788e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
47891a3b39ecSAndrew Lunn 		.ops = &mv88e6190_ops,
47901a3b39ecSAndrew Lunn 	},
47911a3b39ecSAndrew Lunn 
47921a3b39ecSAndrew Lunn 	[MV88E6190X] = {
4793107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X,
47941a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
47951a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190X",
47961a3b39ecSAndrew Lunn 		.num_databases = 4096,
4797d9ea5620SAndrew Lunn 		.num_macs = 16384,
47981a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
479995150f29SHeiner Kallweit 		.num_internal_phys = 9,
4800a73ccd61SBrandon Streiff 		.num_gpio = 16,
4801931d1822SVivien Didelot 		.max_vid = 8191,
48021a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
48039255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
48041a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
48059069c13aSVivien Didelot 		.global2_addr = 0x1c,
4806b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
48071a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4808d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4809e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4810f3645652SVivien Didelot 		.pvt = true,
4811b3e05aa1SVivien Didelot 		.multi_chip = true,
4812443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
48131a3b39ecSAndrew Lunn 		.ops = &mv88e6190x_ops,
48141a3b39ecSAndrew Lunn 	},
48151a3b39ecSAndrew Lunn 
48161a3b39ecSAndrew Lunn 	[MV88E6191] = {
4817107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191,
48181a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
48191a3b39ecSAndrew Lunn 		.name = "Marvell 88E6191",
48201a3b39ecSAndrew Lunn 		.num_databases = 4096,
4821d9ea5620SAndrew Lunn 		.num_macs = 16384,
48221a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
482395150f29SHeiner Kallweit 		.num_internal_phys = 9,
4824931d1822SVivien Didelot 		.max_vid = 8191,
48251a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
48269255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
48271a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
48289069c13aSVivien Didelot 		.global2_addr = 0x1c,
4829b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
4830443d5a1bSAndrew Lunn 		.g1_irqs = 9,
4831d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4832e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4833f3645652SVivien Didelot 		.pvt = true,
4834b3e05aa1SVivien Didelot 		.multi_chip = true,
4835443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
48362fa8d3afSBrandon Streiff 		.ptp_support = true,
48372cf4cefbSVivien Didelot 		.ops = &mv88e6191_ops,
48381a3b39ecSAndrew Lunn 	},
48391a3b39ecSAndrew Lunn 
484049022647SHubert Feurstein 	[MV88E6220] = {
484149022647SHubert Feurstein 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
484249022647SHubert Feurstein 		.family = MV88E6XXX_FAMILY_6250,
484349022647SHubert Feurstein 		.name = "Marvell 88E6220",
484449022647SHubert Feurstein 		.num_databases = 64,
484549022647SHubert Feurstein 
484649022647SHubert Feurstein 		/* Ports 2-4 are not routed to pins
484749022647SHubert Feurstein 		 * => usable ports 0, 1, 5, 6
484849022647SHubert Feurstein 		 */
484949022647SHubert Feurstein 		.num_ports = 7,
485049022647SHubert Feurstein 		.num_internal_phys = 2,
4851c857486aSHubert Feurstein 		.invalid_port_mask = BIT(2) | BIT(3) | BIT(4),
485249022647SHubert Feurstein 		.max_vid = 4095,
485349022647SHubert Feurstein 		.port_base_addr = 0x08,
485449022647SHubert Feurstein 		.phy_base_addr = 0x00,
485549022647SHubert Feurstein 		.global1_addr = 0x0f,
485649022647SHubert Feurstein 		.global2_addr = 0x07,
485749022647SHubert Feurstein 		.age_time_coeff = 15000,
485849022647SHubert Feurstein 		.g1_irqs = 9,
485949022647SHubert Feurstein 		.g2_irqs = 10,
486049022647SHubert Feurstein 		.atu_move_port_mask = 0xf,
486149022647SHubert Feurstein 		.dual_chip = true,
486249022647SHubert Feurstein 		.tag_protocol = DSA_TAG_PROTO_DSA,
486371509614SHubert Feurstein 		.ptp_support = true,
486449022647SHubert Feurstein 		.ops = &mv88e6250_ops,
486549022647SHubert Feurstein 	},
486649022647SHubert Feurstein 
4867fad09c73SVivien Didelot 	[MV88E6240] = {
4868107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240,
4869fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4870fad09c73SVivien Didelot 		.name = "Marvell 88E6240",
4871fad09c73SVivien Didelot 		.num_databases = 4096,
4872d9ea5620SAndrew Lunn 		.num_macs = 8192,
4873fad09c73SVivien Didelot 		.num_ports = 7,
4874bc393155SAndrew Lunn 		.num_internal_phys = 5,
4875a73ccd61SBrandon Streiff 		.num_gpio = 15,
48763cf3c846SVivien Didelot 		.max_vid = 4095,
4877fad09c73SVivien Didelot 		.port_base_addr = 0x10,
48789255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4879a935c052SVivien Didelot 		.global1_addr = 0x1b,
48809069c13aSVivien Didelot 		.global2_addr = 0x1c,
4881acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4882dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4883d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4884e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4885f3645652SVivien Didelot 		.pvt = true,
4886b3e05aa1SVivien Didelot 		.multi_chip = true,
4887443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
48882fa8d3afSBrandon Streiff 		.ptp_support = true,
4889b3469dd8SVivien Didelot 		.ops = &mv88e6240_ops,
4890fad09c73SVivien Didelot 	},
4891fad09c73SVivien Didelot 
48921f71836fSRasmus Villemoes 	[MV88E6250] = {
48931f71836fSRasmus Villemoes 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250,
48941f71836fSRasmus Villemoes 		.family = MV88E6XXX_FAMILY_6250,
48951f71836fSRasmus Villemoes 		.name = "Marvell 88E6250",
48961f71836fSRasmus Villemoes 		.num_databases = 64,
48971f71836fSRasmus Villemoes 		.num_ports = 7,
48981f71836fSRasmus Villemoes 		.num_internal_phys = 5,
48991f71836fSRasmus Villemoes 		.max_vid = 4095,
49001f71836fSRasmus Villemoes 		.port_base_addr = 0x08,
49011f71836fSRasmus Villemoes 		.phy_base_addr = 0x00,
49021f71836fSRasmus Villemoes 		.global1_addr = 0x0f,
49031f71836fSRasmus Villemoes 		.global2_addr = 0x07,
49041f71836fSRasmus Villemoes 		.age_time_coeff = 15000,
49051f71836fSRasmus Villemoes 		.g1_irqs = 9,
49061f71836fSRasmus Villemoes 		.g2_irqs = 10,
49071f71836fSRasmus Villemoes 		.atu_move_port_mask = 0xf,
49081f71836fSRasmus Villemoes 		.dual_chip = true,
49091f71836fSRasmus Villemoes 		.tag_protocol = DSA_TAG_PROTO_DSA,
491071509614SHubert Feurstein 		.ptp_support = true,
49111f71836fSRasmus Villemoes 		.ops = &mv88e6250_ops,
49121f71836fSRasmus Villemoes 	},
49131f71836fSRasmus Villemoes 
49141a3b39ecSAndrew Lunn 	[MV88E6290] = {
4915107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
49161a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
49171a3b39ecSAndrew Lunn 		.name = "Marvell 88E6290",
49181a3b39ecSAndrew Lunn 		.num_databases = 4096,
49191a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
492095150f29SHeiner Kallweit 		.num_internal_phys = 9,
4921a73ccd61SBrandon Streiff 		.num_gpio = 16,
4922931d1822SVivien Didelot 		.max_vid = 8191,
49231a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
49249255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
49251a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
49269069c13aSVivien Didelot 		.global2_addr = 0x1c,
4927b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
49281a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4929d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4930e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4931f3645652SVivien Didelot 		.pvt = true,
4932b3e05aa1SVivien Didelot 		.multi_chip = true,
4933443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
49342fa8d3afSBrandon Streiff 		.ptp_support = true,
49351a3b39ecSAndrew Lunn 		.ops = &mv88e6290_ops,
49361a3b39ecSAndrew Lunn 	},
49371a3b39ecSAndrew Lunn 
4938fad09c73SVivien Didelot 	[MV88E6320] = {
4939107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320,
4940fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
4941fad09c73SVivien Didelot 		.name = "Marvell 88E6320",
4942fad09c73SVivien Didelot 		.num_databases = 4096,
4943d9ea5620SAndrew Lunn 		.num_macs = 8192,
4944fad09c73SVivien Didelot 		.num_ports = 7,
4945bc393155SAndrew Lunn 		.num_internal_phys = 5,
4946a73ccd61SBrandon Streiff 		.num_gpio = 15,
49473cf3c846SVivien Didelot 		.max_vid = 4095,
4948fad09c73SVivien Didelot 		.port_base_addr = 0x10,
49499255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4950a935c052SVivien Didelot 		.global1_addr = 0x1b,
49519069c13aSVivien Didelot 		.global2_addr = 0x1c,
4952acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4953dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4954bc393155SAndrew Lunn 		.g2_irqs = 10,
4955e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4956f3645652SVivien Didelot 		.pvt = true,
4957b3e05aa1SVivien Didelot 		.multi_chip = true,
4958443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
49592fa8d3afSBrandon Streiff 		.ptp_support = true,
4960b3469dd8SVivien Didelot 		.ops = &mv88e6320_ops,
4961fad09c73SVivien Didelot 	},
4962fad09c73SVivien Didelot 
4963fad09c73SVivien Didelot 	[MV88E6321] = {
4964107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321,
4965fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
4966fad09c73SVivien Didelot 		.name = "Marvell 88E6321",
4967fad09c73SVivien Didelot 		.num_databases = 4096,
4968d9ea5620SAndrew Lunn 		.num_macs = 8192,
4969fad09c73SVivien Didelot 		.num_ports = 7,
4970bc393155SAndrew Lunn 		.num_internal_phys = 5,
4971a73ccd61SBrandon Streiff 		.num_gpio = 15,
49723cf3c846SVivien Didelot 		.max_vid = 4095,
4973fad09c73SVivien Didelot 		.port_base_addr = 0x10,
49749255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4975a935c052SVivien Didelot 		.global1_addr = 0x1b,
49769069c13aSVivien Didelot 		.global2_addr = 0x1c,
4977acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4978dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4979bc393155SAndrew Lunn 		.g2_irqs = 10,
4980e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4981b3e05aa1SVivien Didelot 		.multi_chip = true,
4982443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
49832fa8d3afSBrandon Streiff 		.ptp_support = true,
4984b3469dd8SVivien Didelot 		.ops = &mv88e6321_ops,
4985fad09c73SVivien Didelot 	},
4986fad09c73SVivien Didelot 
4987a75961d0SGregory CLEMENT 	[MV88E6341] = {
4988107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
4989a75961d0SGregory CLEMENT 		.family = MV88E6XXX_FAMILY_6341,
4990a75961d0SGregory CLEMENT 		.name = "Marvell 88E6341",
4991a75961d0SGregory CLEMENT 		.num_databases = 4096,
4992d9ea5620SAndrew Lunn 		.num_macs = 2048,
4993bc393155SAndrew Lunn 		.num_internal_phys = 5,
4994a75961d0SGregory CLEMENT 		.num_ports = 6,
4995a73ccd61SBrandon Streiff 		.num_gpio = 11,
49963cf3c846SVivien Didelot 		.max_vid = 4095,
4997a75961d0SGregory CLEMENT 		.port_base_addr = 0x10,
49989255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
4999a75961d0SGregory CLEMENT 		.global1_addr = 0x1b,
50009069c13aSVivien Didelot 		.global2_addr = 0x1c,
5001a75961d0SGregory CLEMENT 		.age_time_coeff = 3750,
5002e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5003adfccf11SAndrew Lunn 		.g1_irqs = 9,
5004d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5005f3645652SVivien Didelot 		.pvt = true,
5006b3e05aa1SVivien Didelot 		.multi_chip = true,
5007a75961d0SGregory CLEMENT 		.tag_protocol = DSA_TAG_PROTO_EDSA,
50082fa8d3afSBrandon Streiff 		.ptp_support = true,
5009a75961d0SGregory CLEMENT 		.ops = &mv88e6341_ops,
5010a75961d0SGregory CLEMENT 	},
5011a75961d0SGregory CLEMENT 
5012fad09c73SVivien Didelot 	[MV88E6350] = {
5013107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350,
5014fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5015fad09c73SVivien Didelot 		.name = "Marvell 88E6350",
5016fad09c73SVivien Didelot 		.num_databases = 4096,
5017d9ea5620SAndrew Lunn 		.num_macs = 8192,
5018fad09c73SVivien Didelot 		.num_ports = 7,
5019bc393155SAndrew Lunn 		.num_internal_phys = 5,
50203cf3c846SVivien Didelot 		.max_vid = 4095,
5021fad09c73SVivien Didelot 		.port_base_addr = 0x10,
50229255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5023a935c052SVivien Didelot 		.global1_addr = 0x1b,
50249069c13aSVivien Didelot 		.global2_addr = 0x1c,
5025acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5026dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5027d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5028e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5029f3645652SVivien Didelot 		.pvt = true,
5030b3e05aa1SVivien Didelot 		.multi_chip = true,
5031443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
5032b3469dd8SVivien Didelot 		.ops = &mv88e6350_ops,
5033fad09c73SVivien Didelot 	},
5034fad09c73SVivien Didelot 
5035fad09c73SVivien Didelot 	[MV88E6351] = {
5036107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351,
5037fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5038fad09c73SVivien Didelot 		.name = "Marvell 88E6351",
5039fad09c73SVivien Didelot 		.num_databases = 4096,
5040d9ea5620SAndrew Lunn 		.num_macs = 8192,
5041fad09c73SVivien Didelot 		.num_ports = 7,
5042bc393155SAndrew Lunn 		.num_internal_phys = 5,
50433cf3c846SVivien Didelot 		.max_vid = 4095,
5044fad09c73SVivien Didelot 		.port_base_addr = 0x10,
50459255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5046a935c052SVivien Didelot 		.global1_addr = 0x1b,
50479069c13aSVivien Didelot 		.global2_addr = 0x1c,
5048acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5049dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5050d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5051e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5052f3645652SVivien Didelot 		.pvt = true,
5053b3e05aa1SVivien Didelot 		.multi_chip = true,
5054443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
5055b3469dd8SVivien Didelot 		.ops = &mv88e6351_ops,
5056fad09c73SVivien Didelot 	},
5057fad09c73SVivien Didelot 
5058fad09c73SVivien Didelot 	[MV88E6352] = {
5059107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352,
5060fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
5061fad09c73SVivien Didelot 		.name = "Marvell 88E6352",
5062fad09c73SVivien Didelot 		.num_databases = 4096,
5063d9ea5620SAndrew Lunn 		.num_macs = 8192,
5064fad09c73SVivien Didelot 		.num_ports = 7,
5065bc393155SAndrew Lunn 		.num_internal_phys = 5,
5066a73ccd61SBrandon Streiff 		.num_gpio = 15,
50673cf3c846SVivien Didelot 		.max_vid = 4095,
5068fad09c73SVivien Didelot 		.port_base_addr = 0x10,
50699255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5070a935c052SVivien Didelot 		.global1_addr = 0x1b,
50719069c13aSVivien Didelot 		.global2_addr = 0x1c,
5072acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5073dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5074d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5075e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5076f3645652SVivien Didelot 		.pvt = true,
5077b3e05aa1SVivien Didelot 		.multi_chip = true,
5078443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
50792fa8d3afSBrandon Streiff 		.ptp_support = true,
5080b3469dd8SVivien Didelot 		.ops = &mv88e6352_ops,
5081fad09c73SVivien Didelot 	},
50821a3b39ecSAndrew Lunn 	[MV88E6390] = {
5083107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
50841a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
50851a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390",
50861a3b39ecSAndrew Lunn 		.num_databases = 4096,
5087d9ea5620SAndrew Lunn 		.num_macs = 16384,
50881a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
508995150f29SHeiner Kallweit 		.num_internal_phys = 9,
5090a73ccd61SBrandon Streiff 		.num_gpio = 16,
5091931d1822SVivien Didelot 		.max_vid = 8191,
50921a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
50939255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
50941a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
50959069c13aSVivien Didelot 		.global2_addr = 0x1c,
5096b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
50971a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5098d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5099e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5100f3645652SVivien Didelot 		.pvt = true,
5101b3e05aa1SVivien Didelot 		.multi_chip = true,
5102443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
51032fa8d3afSBrandon Streiff 		.ptp_support = true,
51041a3b39ecSAndrew Lunn 		.ops = &mv88e6390_ops,
51051a3b39ecSAndrew Lunn 	},
51061a3b39ecSAndrew Lunn 	[MV88E6390X] = {
5107107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X,
51081a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
51091a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390X",
51101a3b39ecSAndrew Lunn 		.num_databases = 4096,
5111d9ea5620SAndrew Lunn 		.num_macs = 16384,
51121a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
511395150f29SHeiner Kallweit 		.num_internal_phys = 9,
5114a73ccd61SBrandon Streiff 		.num_gpio = 16,
5115931d1822SVivien Didelot 		.max_vid = 8191,
51161a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
51179255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
51181a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
51199069c13aSVivien Didelot 		.global2_addr = 0x1c,
5120b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
51211a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5122d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5123e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5124f3645652SVivien Didelot 		.pvt = true,
5125b3e05aa1SVivien Didelot 		.multi_chip = true,
5126443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
51272fa8d3afSBrandon Streiff 		.ptp_support = true,
51281a3b39ecSAndrew Lunn 		.ops = &mv88e6390x_ops,
51291a3b39ecSAndrew Lunn 	},
5130fad09c73SVivien Didelot };
5131fad09c73SVivien Didelot 
5132fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
5133fad09c73SVivien Didelot {
5134fad09c73SVivien Didelot 	int i;
5135fad09c73SVivien Didelot 
5136fad09c73SVivien Didelot 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
5137fad09c73SVivien Didelot 		if (mv88e6xxx_table[i].prod_num == prod_num)
5138fad09c73SVivien Didelot 			return &mv88e6xxx_table[i];
5139fad09c73SVivien Didelot 
5140fad09c73SVivien Didelot 	return NULL;
5141fad09c73SVivien Didelot }
5142fad09c73SVivien Didelot 
5143fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
5144fad09c73SVivien Didelot {
5145fad09c73SVivien Didelot 	const struct mv88e6xxx_info *info;
51468f6345b2SVivien Didelot 	unsigned int prod_num, rev;
51478f6345b2SVivien Didelot 	u16 id;
51488f6345b2SVivien Didelot 	int err;
5149fad09c73SVivien Didelot 
5150c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5151107fcc10SVivien Didelot 	err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
5152c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
51538f6345b2SVivien Didelot 	if (err)
51548f6345b2SVivien Didelot 		return err;
5155fad09c73SVivien Didelot 
5156107fcc10SVivien Didelot 	prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK;
5157107fcc10SVivien Didelot 	rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK;
5158fad09c73SVivien Didelot 
5159fad09c73SVivien Didelot 	info = mv88e6xxx_lookup_info(prod_num);
5160fad09c73SVivien Didelot 	if (!info)
5161fad09c73SVivien Didelot 		return -ENODEV;
5162fad09c73SVivien Didelot 
5163fad09c73SVivien Didelot 	/* Update the compatible info with the probed one */
5164fad09c73SVivien Didelot 	chip->info = info;
5165fad09c73SVivien Didelot 
5166ca070c10SVivien Didelot 	err = mv88e6xxx_g2_require(chip);
5167ca070c10SVivien Didelot 	if (err)
5168ca070c10SVivien Didelot 		return err;
5169ca070c10SVivien Didelot 
5170fad09c73SVivien Didelot 	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
5171fad09c73SVivien Didelot 		 chip->info->prod_num, chip->info->name, rev);
5172fad09c73SVivien Didelot 
5173fad09c73SVivien Didelot 	return 0;
5174fad09c73SVivien Didelot }
5175fad09c73SVivien Didelot 
5176fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
5177fad09c73SVivien Didelot {
5178fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
5179fad09c73SVivien Didelot 
5180fad09c73SVivien Didelot 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
5181fad09c73SVivien Didelot 	if (!chip)
5182fad09c73SVivien Didelot 		return NULL;
5183fad09c73SVivien Didelot 
5184fad09c73SVivien Didelot 	chip->dev = dev;
5185fad09c73SVivien Didelot 
5186fad09c73SVivien Didelot 	mutex_init(&chip->reg_lock);
5187a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&chip->mdios);
5188da7dc875SVivien Didelot 	idr_init(&chip->policies);
5189fad09c73SVivien Didelot 
5190fad09c73SVivien Didelot 	return chip;
5191fad09c73SVivien Didelot }
5192fad09c73SVivien Didelot 
51935ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
51944d776482SFlorian Fainelli 							int port,
51954d776482SFlorian Fainelli 							enum dsa_tag_protocol m)
51967b314362SAndrew Lunn {
519704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
51982bbb33beSAndrew Lunn 
5199443d5a1bSAndrew Lunn 	return chip->info->tag_protocol;
52007b314362SAndrew Lunn }
52017b314362SAndrew Lunn 
52027df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port,
52033709aadcSVivien Didelot 				      const struct switchdev_obj_port_mdb *mdb)
52047df8fbddSVivien Didelot {
52057df8fbddSVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
52067df8fbddSVivien Didelot 	 * so skip the prepare phase.
52077df8fbddSVivien Didelot 	 */
52087df8fbddSVivien Didelot 
52097df8fbddSVivien Didelot 	return 0;
52107df8fbddSVivien Didelot }
52117df8fbddSVivien Didelot 
52127df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
52133709aadcSVivien Didelot 				   const struct switchdev_obj_port_mdb *mdb)
52147df8fbddSVivien Didelot {
521504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
52167df8fbddSVivien Didelot 
5217c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
52187df8fbddSVivien Didelot 	if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
521927c0e600SVivien Didelot 					 MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC))
5220774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to load multicast MAC address\n",
5221774439e5SVivien Didelot 			port);
5222c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
52237df8fbddSVivien Didelot }
52247df8fbddSVivien Didelot 
52257df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
52267df8fbddSVivien Didelot 				  const struct switchdev_obj_port_mdb *mdb)
52277df8fbddSVivien Didelot {
522804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
52297df8fbddSVivien Didelot 	int err;
52307df8fbddSVivien Didelot 
5231c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5232d8291a95SVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0);
5233c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
52347df8fbddSVivien Didelot 
52357df8fbddSVivien Didelot 	return err;
52367df8fbddSVivien Didelot }
52377df8fbddSVivien Didelot 
5238f0942e00SIwan R Timmer static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
5239f0942e00SIwan R Timmer 				     struct dsa_mall_mirror_tc_entry *mirror,
5240f0942e00SIwan R Timmer 				     bool ingress)
5241f0942e00SIwan R Timmer {
5242f0942e00SIwan R Timmer 	enum mv88e6xxx_egress_direction direction = ingress ?
5243f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS :
5244f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS;
5245f0942e00SIwan R Timmer 	struct mv88e6xxx_chip *chip = ds->priv;
5246f0942e00SIwan R Timmer 	bool other_mirrors = false;
5247f0942e00SIwan R Timmer 	int i;
5248f0942e00SIwan R Timmer 	int err;
5249f0942e00SIwan R Timmer 
5250f0942e00SIwan R Timmer 	if (!chip->info->ops->set_egress_port)
5251f0942e00SIwan R Timmer 		return -EOPNOTSUPP;
5252f0942e00SIwan R Timmer 
5253f0942e00SIwan R Timmer 	mutex_lock(&chip->reg_lock);
5254f0942e00SIwan R Timmer 	if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
5255f0942e00SIwan R Timmer 	    mirror->to_local_port) {
5256f0942e00SIwan R Timmer 		for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
5257f0942e00SIwan R Timmer 			other_mirrors |= ingress ?
5258f0942e00SIwan R Timmer 					 chip->ports[i].mirror_ingress :
5259f0942e00SIwan R Timmer 					 chip->ports[i].mirror_egress;
5260f0942e00SIwan R Timmer 
5261f0942e00SIwan R Timmer 		/* Can't change egress port when other mirror is active */
5262f0942e00SIwan R Timmer 		if (other_mirrors) {
5263f0942e00SIwan R Timmer 			err = -EBUSY;
5264f0942e00SIwan R Timmer 			goto out;
5265f0942e00SIwan R Timmer 		}
5266f0942e00SIwan R Timmer 
5267f0942e00SIwan R Timmer 		err = chip->info->ops->set_egress_port(chip,
5268f0942e00SIwan R Timmer 						       direction,
5269f0942e00SIwan R Timmer 						       mirror->to_local_port);
5270f0942e00SIwan R Timmer 		if (err)
5271f0942e00SIwan R Timmer 			goto out;
5272f0942e00SIwan R Timmer 	}
5273f0942e00SIwan R Timmer 
5274f0942e00SIwan R Timmer 	err = mv88e6xxx_port_set_mirror(chip, port, direction, true);
5275f0942e00SIwan R Timmer out:
5276f0942e00SIwan R Timmer 	mutex_unlock(&chip->reg_lock);
5277f0942e00SIwan R Timmer 
5278f0942e00SIwan R Timmer 	return err;
5279f0942e00SIwan R Timmer }
5280f0942e00SIwan R Timmer 
5281f0942e00SIwan R Timmer static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
5282f0942e00SIwan R Timmer 				      struct dsa_mall_mirror_tc_entry *mirror)
5283f0942e00SIwan R Timmer {
5284f0942e00SIwan R Timmer 	enum mv88e6xxx_egress_direction direction = mirror->ingress ?
5285f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS :
5286f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS;
5287f0942e00SIwan R Timmer 	struct mv88e6xxx_chip *chip = ds->priv;
5288f0942e00SIwan R Timmer 	bool other_mirrors = false;
5289f0942e00SIwan R Timmer 	int i;
5290f0942e00SIwan R Timmer 
5291f0942e00SIwan R Timmer 	mutex_lock(&chip->reg_lock);
5292f0942e00SIwan R Timmer 	if (mv88e6xxx_port_set_mirror(chip, port, direction, false))
5293f0942e00SIwan R Timmer 		dev_err(ds->dev, "p%d: failed to disable mirroring\n", port);
5294f0942e00SIwan R Timmer 
5295f0942e00SIwan R Timmer 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
5296f0942e00SIwan R Timmer 		other_mirrors |= mirror->ingress ?
5297f0942e00SIwan R Timmer 				 chip->ports[i].mirror_ingress :
5298f0942e00SIwan R Timmer 				 chip->ports[i].mirror_egress;
5299f0942e00SIwan R Timmer 
5300f0942e00SIwan R Timmer 	/* Reset egress port when no other mirror is active */
5301f0942e00SIwan R Timmer 	if (!other_mirrors) {
5302f0942e00SIwan R Timmer 		if (chip->info->ops->set_egress_port(chip,
5303f0942e00SIwan R Timmer 						     direction,
5304f0942e00SIwan R Timmer 						     dsa_upstream_port(ds,
53054e4637b1SColin Ian King 								       port)))
5306f0942e00SIwan R Timmer 			dev_err(ds->dev, "failed to set egress port\n");
5307f0942e00SIwan R Timmer 	}
5308f0942e00SIwan R Timmer 
5309f0942e00SIwan R Timmer 	mutex_unlock(&chip->reg_lock);
5310f0942e00SIwan R Timmer }
5311f0942e00SIwan R Timmer 
53124f85901fSRussell King static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
53134f85901fSRussell King 					 bool unicast, bool multicast)
53144f85901fSRussell King {
53154f85901fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
53164f85901fSRussell King 	int err = -EOPNOTSUPP;
53174f85901fSRussell King 
5318c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
53194f85901fSRussell King 	if (chip->info->ops->port_set_egress_floods)
53204f85901fSRussell King 		err = chip->info->ops->port_set_egress_floods(chip, port,
53214f85901fSRussell King 							      unicast,
53224f85901fSRussell King 							      multicast);
5323c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
53244f85901fSRussell King 
53254f85901fSRussell King 	return err;
53264f85901fSRussell King }
53274f85901fSRussell King 
5328a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
53297b314362SAndrew Lunn 	.get_tag_protocol	= mv88e6xxx_get_tag_protocol,
5330fad09c73SVivien Didelot 	.setup			= mv88e6xxx_setup,
533123e8b470SAndrew Lunn 	.teardown		= mv88e6xxx_teardown,
5332c9a2356fSRussell King 	.phylink_validate	= mv88e6xxx_validate,
5333a5a6858bSRussell King 	.phylink_mac_link_state	= mv88e6xxx_serdes_pcs_get_state,
5334c9a2356fSRussell King 	.phylink_mac_config	= mv88e6xxx_mac_config,
5335a5a6858bSRussell King 	.phylink_mac_an_restart	= mv88e6xxx_serdes_pcs_an_restart,
5336c9a2356fSRussell King 	.phylink_mac_link_down	= mv88e6xxx_mac_link_down,
5337c9a2356fSRussell King 	.phylink_mac_link_up	= mv88e6xxx_mac_link_up,
5338fad09c73SVivien Didelot 	.get_strings		= mv88e6xxx_get_strings,
5339fad09c73SVivien Didelot 	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
5340fad09c73SVivien Didelot 	.get_sset_count		= mv88e6xxx_get_sset_count,
534104aca993SAndrew Lunn 	.port_enable		= mv88e6xxx_port_enable,
534204aca993SAndrew Lunn 	.port_disable		= mv88e6xxx_port_disable,
53432a550aecSAndrew Lunn 	.port_max_mtu		= mv88e6xxx_get_max_mtu,
53442a550aecSAndrew Lunn 	.port_change_mtu	= mv88e6xxx_change_mtu,
534508f50061SVivien Didelot 	.get_mac_eee		= mv88e6xxx_get_mac_eee,
534608f50061SVivien Didelot 	.set_mac_eee		= mv88e6xxx_set_mac_eee,
5347fad09c73SVivien Didelot 	.get_eeprom_len		= mv88e6xxx_get_eeprom_len,
5348fad09c73SVivien Didelot 	.get_eeprom		= mv88e6xxx_get_eeprom,
5349fad09c73SVivien Didelot 	.set_eeprom		= mv88e6xxx_set_eeprom,
5350fad09c73SVivien Didelot 	.get_regs_len		= mv88e6xxx_get_regs_len,
5351fad09c73SVivien Didelot 	.get_regs		= mv88e6xxx_get_regs,
5352da7dc875SVivien Didelot 	.get_rxnfc		= mv88e6xxx_get_rxnfc,
5353da7dc875SVivien Didelot 	.set_rxnfc		= mv88e6xxx_set_rxnfc,
53542cfcd964SVivien Didelot 	.set_ageing_time	= mv88e6xxx_set_ageing_time,
5355fad09c73SVivien Didelot 	.port_bridge_join	= mv88e6xxx_port_bridge_join,
5356fad09c73SVivien Didelot 	.port_bridge_leave	= mv88e6xxx_port_bridge_leave,
53574f85901fSRussell King 	.port_egress_floods	= mv88e6xxx_port_egress_floods,
5358fad09c73SVivien Didelot 	.port_stp_state_set	= mv88e6xxx_port_stp_state_set,
5359749efcb8SVivien Didelot 	.port_fast_age		= mv88e6xxx_port_fast_age,
5360fad09c73SVivien Didelot 	.port_vlan_filtering	= mv88e6xxx_port_vlan_filtering,
5361fad09c73SVivien Didelot 	.port_vlan_prepare	= mv88e6xxx_port_vlan_prepare,
5362fad09c73SVivien Didelot 	.port_vlan_add		= mv88e6xxx_port_vlan_add,
5363fad09c73SVivien Didelot 	.port_vlan_del		= mv88e6xxx_port_vlan_del,
5364fad09c73SVivien Didelot 	.port_fdb_add           = mv88e6xxx_port_fdb_add,
5365fad09c73SVivien Didelot 	.port_fdb_del           = mv88e6xxx_port_fdb_del,
5366fad09c73SVivien Didelot 	.port_fdb_dump          = mv88e6xxx_port_fdb_dump,
53677df8fbddSVivien Didelot 	.port_mdb_prepare       = mv88e6xxx_port_mdb_prepare,
53687df8fbddSVivien Didelot 	.port_mdb_add           = mv88e6xxx_port_mdb_add,
53697df8fbddSVivien Didelot 	.port_mdb_del           = mv88e6xxx_port_mdb_del,
5370f0942e00SIwan R Timmer 	.port_mirror_add	= mv88e6xxx_port_mirror_add,
5371f0942e00SIwan R Timmer 	.port_mirror_del	= mv88e6xxx_port_mirror_del,
5372aec5ac88SVivien Didelot 	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
5373aec5ac88SVivien Didelot 	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
5374c6fe0ad2SBrandon Streiff 	.port_hwtstamp_set	= mv88e6xxx_port_hwtstamp_set,
5375c6fe0ad2SBrandon Streiff 	.port_hwtstamp_get	= mv88e6xxx_port_hwtstamp_get,
5376c6fe0ad2SBrandon Streiff 	.port_txtstamp		= mv88e6xxx_port_txtstamp,
5377c6fe0ad2SBrandon Streiff 	.port_rxtstamp		= mv88e6xxx_port_rxtstamp,
5378c6fe0ad2SBrandon Streiff 	.get_ts_info		= mv88e6xxx_get_ts_info,
537923e8b470SAndrew Lunn 	.devlink_param_get	= mv88e6xxx_devlink_param_get,
538023e8b470SAndrew Lunn 	.devlink_param_set	= mv88e6xxx_devlink_param_set,
5381fad09c73SVivien Didelot };
5382fad09c73SVivien Didelot 
538355ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
5384fad09c73SVivien Didelot {
5385fad09c73SVivien Didelot 	struct device *dev = chip->dev;
5386fad09c73SVivien Didelot 	struct dsa_switch *ds;
5387fad09c73SVivien Didelot 
53887e99e347SVivien Didelot 	ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
5389fad09c73SVivien Didelot 	if (!ds)
5390fad09c73SVivien Didelot 		return -ENOMEM;
5391fad09c73SVivien Didelot 
53927e99e347SVivien Didelot 	ds->dev = dev;
53937e99e347SVivien Didelot 	ds->num_ports = mv88e6xxx_num_ports(chip);
5394fad09c73SVivien Didelot 	ds->priv = chip;
5395877b7cb0SAndrew Lunn 	ds->dev = dev;
53969d490b4eSVivien Didelot 	ds->ops = &mv88e6xxx_switch_ops;
53979ff74f24SVivien Didelot 	ds->ageing_time_min = chip->info->age_time_coeff;
53989ff74f24SVivien Didelot 	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
5399fad09c73SVivien Didelot 
5400fad09c73SVivien Didelot 	dev_set_drvdata(dev, ds);
5401fad09c73SVivien Didelot 
540223c9ee49SVivien Didelot 	return dsa_register_switch(ds);
5403fad09c73SVivien Didelot }
5404fad09c73SVivien Didelot 
5405fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
5406fad09c73SVivien Didelot {
5407fad09c73SVivien Didelot 	dsa_unregister_switch(chip->ds);
5408fad09c73SVivien Didelot }
5409fad09c73SVivien Didelot 
5410877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev)
5411877b7cb0SAndrew Lunn {
5412877b7cb0SAndrew Lunn 	const struct of_device_id *matches = dev->driver->of_match_table;
5413877b7cb0SAndrew Lunn 	const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data;
5414877b7cb0SAndrew Lunn 
5415877b7cb0SAndrew Lunn 	for (; matches->name[0] || matches->type[0] || matches->compatible[0];
5416877b7cb0SAndrew Lunn 	     matches++) {
5417877b7cb0SAndrew Lunn 		if (!strcmp(pdata->compatible, matches->compatible))
5418877b7cb0SAndrew Lunn 			return matches->data;
5419877b7cb0SAndrew Lunn 	}
5420877b7cb0SAndrew Lunn 	return NULL;
5421877b7cb0SAndrew Lunn }
5422877b7cb0SAndrew Lunn 
5423bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration
5424bcd3d9d9SMiquel Raynal  * would be lost after a power cycle so prevent it to be suspended.
5425bcd3d9d9SMiquel Raynal  */
5426bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev)
5427bcd3d9d9SMiquel Raynal {
5428bcd3d9d9SMiquel Raynal 	return -EOPNOTSUPP;
5429bcd3d9d9SMiquel Raynal }
5430bcd3d9d9SMiquel Raynal 
5431bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev)
5432bcd3d9d9SMiquel Raynal {
5433bcd3d9d9SMiquel Raynal 	return 0;
5434bcd3d9d9SMiquel Raynal }
5435bcd3d9d9SMiquel Raynal 
5436bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume);
5437bcd3d9d9SMiquel Raynal 
5438fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev)
5439fad09c73SVivien Didelot {
5440877b7cb0SAndrew Lunn 	struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data;
54417ddae24fSDavid S. Miller 	const struct mv88e6xxx_info *compat_info = NULL;
5442fad09c73SVivien Didelot 	struct device *dev = &mdiodev->dev;
5443fad09c73SVivien Didelot 	struct device_node *np = dev->of_node;
5444fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
5445877b7cb0SAndrew Lunn 	int port;
5446fad09c73SVivien Didelot 	int err;
5447fad09c73SVivien Didelot 
54487bb8c996SAndrew Lunn 	if (!np && !pdata)
54497bb8c996SAndrew Lunn 		return -EINVAL;
54507bb8c996SAndrew Lunn 
5451877b7cb0SAndrew Lunn 	if (np)
5452fad09c73SVivien Didelot 		compat_info = of_device_get_match_data(dev);
5453877b7cb0SAndrew Lunn 
5454877b7cb0SAndrew Lunn 	if (pdata) {
5455877b7cb0SAndrew Lunn 		compat_info = pdata_device_get_match_data(dev);
5456877b7cb0SAndrew Lunn 
5457877b7cb0SAndrew Lunn 		if (!pdata->netdev)
5458877b7cb0SAndrew Lunn 			return -EINVAL;
5459877b7cb0SAndrew Lunn 
5460877b7cb0SAndrew Lunn 		for (port = 0; port < DSA_MAX_PORTS; port++) {
5461877b7cb0SAndrew Lunn 			if (!(pdata->enabled_ports & (1 << port)))
5462877b7cb0SAndrew Lunn 				continue;
5463877b7cb0SAndrew Lunn 			if (strcmp(pdata->cd.port_names[port], "cpu"))
5464877b7cb0SAndrew Lunn 				continue;
5465877b7cb0SAndrew Lunn 			pdata->cd.netdev[port] = &pdata->netdev->dev;
5466877b7cb0SAndrew Lunn 			break;
5467877b7cb0SAndrew Lunn 		}
5468877b7cb0SAndrew Lunn 	}
5469877b7cb0SAndrew Lunn 
5470fad09c73SVivien Didelot 	if (!compat_info)
5471fad09c73SVivien Didelot 		return -EINVAL;
5472fad09c73SVivien Didelot 
5473fad09c73SVivien Didelot 	chip = mv88e6xxx_alloc_chip(dev);
5474877b7cb0SAndrew Lunn 	if (!chip) {
5475877b7cb0SAndrew Lunn 		err = -ENOMEM;
5476877b7cb0SAndrew Lunn 		goto out;
5477877b7cb0SAndrew Lunn 	}
5478fad09c73SVivien Didelot 
5479fad09c73SVivien Didelot 	chip->info = compat_info;
5480fad09c73SVivien Didelot 
5481fad09c73SVivien Didelot 	err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
5482fad09c73SVivien Didelot 	if (err)
5483877b7cb0SAndrew Lunn 		goto out;
5484fad09c73SVivien Didelot 
5485b4308f04SAndrew Lunn 	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
5486877b7cb0SAndrew Lunn 	if (IS_ERR(chip->reset)) {
5487877b7cb0SAndrew Lunn 		err = PTR_ERR(chip->reset);
5488877b7cb0SAndrew Lunn 		goto out;
5489877b7cb0SAndrew Lunn 	}
54907b75e49dSBaruch Siach 	if (chip->reset)
54917b75e49dSBaruch Siach 		usleep_range(1000, 2000);
5492b4308f04SAndrew Lunn 
5493fad09c73SVivien Didelot 	err = mv88e6xxx_detect(chip);
5494fad09c73SVivien Didelot 	if (err)
5495877b7cb0SAndrew Lunn 		goto out;
5496fad09c73SVivien Didelot 
5497e57e5e77SVivien Didelot 	mv88e6xxx_phy_init(chip);
5498e57e5e77SVivien Didelot 
549900baabe5SAndrew Lunn 	if (chip->info->ops->get_eeprom) {
550000baabe5SAndrew Lunn 		if (np)
550100baabe5SAndrew Lunn 			of_property_read_u32(np, "eeprom-length",
550200baabe5SAndrew Lunn 					     &chip->eeprom_len);
550300baabe5SAndrew Lunn 		else
550400baabe5SAndrew Lunn 			chip->eeprom_len = pdata->eeprom_len;
550500baabe5SAndrew Lunn 	}
5506fad09c73SVivien Didelot 
5507c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5508dc30c35bSAndrew Lunn 	err = mv88e6xxx_switch_reset(chip);
5509c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
5510fad09c73SVivien Didelot 	if (err)
5511dc30c35bSAndrew Lunn 		goto out;
5512fad09c73SVivien Didelot 
5513a27415deSAndrew Lunn 	if (np) {
5514dc30c35bSAndrew Lunn 		chip->irq = of_irq_get(np, 0);
5515dc30c35bSAndrew Lunn 		if (chip->irq == -EPROBE_DEFER) {
5516dc30c35bSAndrew Lunn 			err = chip->irq;
5517dc30c35bSAndrew Lunn 			goto out;
5518fad09c73SVivien Didelot 		}
5519a27415deSAndrew Lunn 	}
5520a27415deSAndrew Lunn 
5521a27415deSAndrew Lunn 	if (pdata)
5522a27415deSAndrew Lunn 		chip->irq = pdata->irq;
5523fad09c73SVivien Didelot 
5524294d711eSAndrew Lunn 	/* Has to be performed before the MDIO bus is created, because
5525a708767eSUwe Kleine-König 	 * the PHYs will link their interrupts to these interrupt
5526294d711eSAndrew Lunn 	 * controllers
5527dc30c35bSAndrew Lunn 	 */
5528c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5529294d711eSAndrew Lunn 	if (chip->irq > 0)
5530dc30c35bSAndrew Lunn 		err = mv88e6xxx_g1_irq_setup(chip);
5531294d711eSAndrew Lunn 	else
5532294d711eSAndrew Lunn 		err = mv88e6xxx_irq_poll_setup(chip);
5533c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
5534dc30c35bSAndrew Lunn 
5535dc30c35bSAndrew Lunn 	if (err)
5536dc30c35bSAndrew Lunn 		goto out;
5537dc30c35bSAndrew Lunn 
5538d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0) {
5539dc30c35bSAndrew Lunn 		err = mv88e6xxx_g2_irq_setup(chip);
5540dc30c35bSAndrew Lunn 		if (err)
5541dc30c35bSAndrew Lunn 			goto out_g1_irq;
5542dc30c35bSAndrew Lunn 	}
55430977644cSAndrew Lunn 
55440977644cSAndrew Lunn 	err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
55450977644cSAndrew Lunn 	if (err)
55460977644cSAndrew Lunn 		goto out_g2_irq;
554762eb1162SAndrew Lunn 
554862eb1162SAndrew Lunn 	err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
554962eb1162SAndrew Lunn 	if (err)
555062eb1162SAndrew Lunn 		goto out_g1_atu_prob_irq;
5551dc30c35bSAndrew Lunn 
5552a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdios_register(chip, np);
5553dc30c35bSAndrew Lunn 	if (err)
555462eb1162SAndrew Lunn 		goto out_g1_vtu_prob_irq;
5555dc30c35bSAndrew Lunn 
555655ed0ce0SFlorian Fainelli 	err = mv88e6xxx_register_switch(chip);
5557dc30c35bSAndrew Lunn 	if (err)
5558dc30c35bSAndrew Lunn 		goto out_mdio;
5559dc30c35bSAndrew Lunn 
5560fad09c73SVivien Didelot 	return 0;
5561dc30c35bSAndrew Lunn 
5562dc30c35bSAndrew Lunn out_mdio:
5563a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
556462eb1162SAndrew Lunn out_g1_vtu_prob_irq:
556562eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
55660977644cSAndrew Lunn out_g1_atu_prob_irq:
55670977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
5568dc30c35bSAndrew Lunn out_g2_irq:
5569294d711eSAndrew Lunn 	if (chip->info->g2_irqs > 0)
5570dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
5571dc30c35bSAndrew Lunn out_g1_irq:
5572294d711eSAndrew Lunn 	if (chip->irq > 0)
5573dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
5574294d711eSAndrew Lunn 	else
5575294d711eSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
5576dc30c35bSAndrew Lunn out:
5577877b7cb0SAndrew Lunn 	if (pdata)
5578877b7cb0SAndrew Lunn 		dev_put(pdata->netdev);
5579877b7cb0SAndrew Lunn 
5580dc30c35bSAndrew Lunn 	return err;
5581fad09c73SVivien Didelot }
5582fad09c73SVivien Didelot 
5583fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev)
5584fad09c73SVivien Didelot {
5585fad09c73SVivien Didelot 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
558604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
5587fad09c73SVivien Didelot 
5588c6fe0ad2SBrandon Streiff 	if (chip->info->ptp_support) {
5589c6fe0ad2SBrandon Streiff 		mv88e6xxx_hwtstamp_free(chip);
55902fa8d3afSBrandon Streiff 		mv88e6xxx_ptp_free(chip);
5591c6fe0ad2SBrandon Streiff 	}
55922fa8d3afSBrandon Streiff 
5593930188ceSAndrew Lunn 	mv88e6xxx_phy_destroy(chip);
5594fad09c73SVivien Didelot 	mv88e6xxx_unregister_switch(chip);
5595a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
5596dc30c35bSAndrew Lunn 
559762eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
55980977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
559976f38f1fSAndrew Lunn 
5600d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0)
5601dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
560276f38f1fSAndrew Lunn 
560376f38f1fSAndrew Lunn 	if (chip->irq > 0)
5604dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
560576f38f1fSAndrew Lunn 	else
560676f38f1fSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
5607fad09c73SVivien Didelot }
5608fad09c73SVivien Didelot 
5609fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = {
5610fad09c73SVivien Didelot 	{
5611fad09c73SVivien Didelot 		.compatible = "marvell,mv88e6085",
5612fad09c73SVivien Didelot 		.data = &mv88e6xxx_table[MV88E6085],
5613fad09c73SVivien Didelot 	},
56141a3b39ecSAndrew Lunn 	{
56151a3b39ecSAndrew Lunn 		.compatible = "marvell,mv88e6190",
56161a3b39ecSAndrew Lunn 		.data = &mv88e6xxx_table[MV88E6190],
56171a3b39ecSAndrew Lunn 	},
56181f71836fSRasmus Villemoes 	{
56191f71836fSRasmus Villemoes 		.compatible = "marvell,mv88e6250",
56201f71836fSRasmus Villemoes 		.data = &mv88e6xxx_table[MV88E6250],
56211f71836fSRasmus Villemoes 	},
5622fad09c73SVivien Didelot 	{ /* sentinel */ },
5623fad09c73SVivien Didelot };
5624fad09c73SVivien Didelot 
5625fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);
5626fad09c73SVivien Didelot 
5627fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = {
5628fad09c73SVivien Didelot 	.probe	= mv88e6xxx_probe,
5629fad09c73SVivien Didelot 	.remove = mv88e6xxx_remove,
5630fad09c73SVivien Didelot 	.mdiodrv.driver = {
5631fad09c73SVivien Didelot 		.name = "mv88e6085",
5632fad09c73SVivien Didelot 		.of_match_table = mv88e6xxx_of_match,
5633bcd3d9d9SMiquel Raynal 		.pm = &mv88e6xxx_pm_ops,
5634fad09c73SVivien Didelot 	},
5635fad09c73SVivien Didelot };
5636fad09c73SVivien Didelot 
56377324d50eSAndrew Lunn mdio_module_driver(mv88e6xxx_driver);
5638fad09c73SVivien Didelot 
5639fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
5640fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
5641fad09c73SVivien Didelot MODULE_LICENSE("GPL");
5642