xref: /openbmc/linux/drivers/net/dsa/mv88e6xxx/chip.c (revision bacf93b0)
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>
155bded825SVladimir Oltean #include <linux/dsa/mv88e6xxx.h>
16fad09c73SVivien Didelot #include <linux/etherdevice.h>
17fad09c73SVivien Didelot #include <linux/ethtool.h>
18fad09c73SVivien Didelot #include <linux/if_bridge.h>
19dc30c35bSAndrew Lunn #include <linux/interrupt.h>
20dc30c35bSAndrew Lunn #include <linux/irq.h>
21dc30c35bSAndrew Lunn #include <linux/irqdomain.h>
22fad09c73SVivien Didelot #include <linux/jiffies.h>
23fad09c73SVivien Didelot #include <linux/list.h>
24fad09c73SVivien Didelot #include <linux/mdio.h>
25fad09c73SVivien Didelot #include <linux/module.h>
26fad09c73SVivien Didelot #include <linux/of_device.h>
27dc30c35bSAndrew Lunn #include <linux/of_irq.h>
28fad09c73SVivien Didelot #include <linux/of_mdio.h>
29877b7cb0SAndrew Lunn #include <linux/platform_data/mv88e6xxx.h>
30fad09c73SVivien Didelot #include <linux/netdevice.h>
31fad09c73SVivien Didelot #include <linux/gpio/consumer.h>
32c9a2356fSRussell King #include <linux/phylink.h>
33fad09c73SVivien Didelot #include <net/dsa.h>
34ec561276SVivien Didelot 
354d5f2ba7SVivien Didelot #include "chip.h"
369dd43aa2SAndrew Lunn #include "devlink.h"
37a935c052SVivien Didelot #include "global1.h"
38ec561276SVivien Didelot #include "global2.h"
39c6fe0ad2SBrandon Streiff #include "hwtstamp.h"
4010fa5bfcSAndrew Lunn #include "phy.h"
4118abed21SVivien Didelot #include "port.h"
422fa8d3afSBrandon Streiff #include "ptp.h"
436d91782fSAndrew Lunn #include "serdes.h"
44e7ba0fadSVivien Didelot #include "smi.h"
45fad09c73SVivien Didelot 
46fad09c73SVivien Didelot static void assert_reg_lock(struct mv88e6xxx_chip *chip)
47fad09c73SVivien Didelot {
48fad09c73SVivien Didelot 	if (unlikely(!mutex_is_locked(&chip->reg_lock))) {
49fad09c73SVivien Didelot 		dev_err(chip->dev, "Switch registers lock not held!\n");
50fad09c73SVivien Didelot 		dump_stack();
51fad09c73SVivien Didelot 	}
52fad09c73SVivien Didelot }
53fad09c73SVivien Didelot 
54ec561276SVivien Didelot int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
55fad09c73SVivien Didelot {
56fad09c73SVivien Didelot 	int err;
57fad09c73SVivien Didelot 
58fad09c73SVivien Didelot 	assert_reg_lock(chip);
59fad09c73SVivien Didelot 
60fad09c73SVivien Didelot 	err = mv88e6xxx_smi_read(chip, addr, reg, val);
61fad09c73SVivien Didelot 	if (err)
62fad09c73SVivien Didelot 		return err;
63fad09c73SVivien Didelot 
64fad09c73SVivien Didelot 	dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
65fad09c73SVivien Didelot 		addr, reg, *val);
66fad09c73SVivien Didelot 
67fad09c73SVivien Didelot 	return 0;
68fad09c73SVivien Didelot }
69fad09c73SVivien Didelot 
70ec561276SVivien Didelot int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
71fad09c73SVivien Didelot {
72fad09c73SVivien Didelot 	int err;
73fad09c73SVivien Didelot 
74fad09c73SVivien Didelot 	assert_reg_lock(chip);
75fad09c73SVivien Didelot 
76fad09c73SVivien Didelot 	err = mv88e6xxx_smi_write(chip, addr, reg, val);
77fad09c73SVivien Didelot 	if (err)
78fad09c73SVivien Didelot 		return err;
79fad09c73SVivien Didelot 
80fad09c73SVivien Didelot 	dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
81fad09c73SVivien Didelot 		addr, reg, val);
82fad09c73SVivien Didelot 
83fad09c73SVivien Didelot 	return 0;
84fad09c73SVivien Didelot }
85fad09c73SVivien Didelot 
86683f2244SVivien Didelot int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg,
87683f2244SVivien Didelot 			u16 mask, u16 val)
88683f2244SVivien Didelot {
8935da1dfdSTobias Waldekranz 	const unsigned long timeout = jiffies + msecs_to_jiffies(50);
90683f2244SVivien Didelot 	u16 data;
91683f2244SVivien Didelot 	int err;
92683f2244SVivien Didelot 	int i;
93683f2244SVivien Didelot 
9435da1dfdSTobias Waldekranz 	/* There's no bus specific operation to wait for a mask. Even
9535da1dfdSTobias Waldekranz 	 * if the initial poll takes longer than 50ms, always do at
9635da1dfdSTobias Waldekranz 	 * least one more attempt.
9735da1dfdSTobias Waldekranz 	 */
9835da1dfdSTobias Waldekranz 	for (i = 0; time_before(jiffies, timeout) || (i < 2); i++) {
99683f2244SVivien Didelot 		err = mv88e6xxx_read(chip, addr, reg, &data);
100683f2244SVivien Didelot 		if (err)
101683f2244SVivien Didelot 			return err;
102683f2244SVivien Didelot 
103683f2244SVivien Didelot 		if ((data & mask) == val)
104683f2244SVivien Didelot 			return 0;
105683f2244SVivien Didelot 
10635da1dfdSTobias Waldekranz 		if (i < 2)
10735da1dfdSTobias Waldekranz 			cpu_relax();
10835da1dfdSTobias Waldekranz 		else
109683f2244SVivien Didelot 			usleep_range(1000, 2000);
110683f2244SVivien Didelot 	}
111683f2244SVivien Didelot 
112683f2244SVivien Didelot 	dev_err(chip->dev, "Timeout while waiting for switch\n");
113683f2244SVivien Didelot 	return -ETIMEDOUT;
114683f2244SVivien Didelot }
115683f2244SVivien Didelot 
11619fb7f69SVivien Didelot int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg,
11719fb7f69SVivien Didelot 		       int bit, int val)
11819fb7f69SVivien Didelot {
11919fb7f69SVivien Didelot 	return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit),
12019fb7f69SVivien Didelot 				   val ? BIT(bit) : 0x0000);
12119fb7f69SVivien Didelot }
12219fb7f69SVivien Didelot 
12310fa5bfcSAndrew Lunn struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
124a3c53be5SAndrew Lunn {
125a3c53be5SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
126a3c53be5SAndrew Lunn 
127a3c53be5SAndrew Lunn 	mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus,
128a3c53be5SAndrew Lunn 				    list);
129a3c53be5SAndrew Lunn 	if (!mdio_bus)
130a3c53be5SAndrew Lunn 		return NULL;
131a3c53be5SAndrew Lunn 
132a3c53be5SAndrew Lunn 	return mdio_bus->bus;
133a3c53be5SAndrew Lunn }
134a3c53be5SAndrew Lunn 
135dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_mask(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 
143dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_unmask(struct irq_data *d)
144dc30c35bSAndrew Lunn {
145dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
146dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
147dc30c35bSAndrew Lunn 
148dc30c35bSAndrew Lunn 	chip->g1_irq.masked &= ~(1 << n);
149dc30c35bSAndrew Lunn }
150dc30c35bSAndrew Lunn 
151294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip)
152dc30c35bSAndrew Lunn {
153dc30c35bSAndrew Lunn 	unsigned int nhandled = 0;
154dc30c35bSAndrew Lunn 	unsigned int sub_irq;
155dc30c35bSAndrew Lunn 	unsigned int n;
156dc30c35bSAndrew Lunn 	u16 reg;
1577c0db24cSJohn David Anglin 	u16 ctl1;
158dc30c35bSAndrew Lunn 	int err;
159dc30c35bSAndrew Lunn 
160c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
16182466921SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
162c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
163dc30c35bSAndrew Lunn 
164dc30c35bSAndrew Lunn 	if (err)
165dc30c35bSAndrew Lunn 		goto out;
166dc30c35bSAndrew Lunn 
1677c0db24cSJohn David Anglin 	do {
168dc30c35bSAndrew Lunn 		for (n = 0; n < chip->g1_irq.nirqs; ++n) {
169dc30c35bSAndrew Lunn 			if (reg & (1 << n)) {
1707c0db24cSJohn David Anglin 				sub_irq = irq_find_mapping(chip->g1_irq.domain,
1717c0db24cSJohn David Anglin 							   n);
172dc30c35bSAndrew Lunn 				handle_nested_irq(sub_irq);
173dc30c35bSAndrew Lunn 				++nhandled;
174dc30c35bSAndrew Lunn 			}
175dc30c35bSAndrew Lunn 		}
1767c0db24cSJohn David Anglin 
177c9acece0SRasmus Villemoes 		mv88e6xxx_reg_lock(chip);
1787c0db24cSJohn David Anglin 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1);
1797c0db24cSJohn David Anglin 		if (err)
1807c0db24cSJohn David Anglin 			goto unlock;
1817c0db24cSJohn David Anglin 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
1827c0db24cSJohn David Anglin unlock:
183c9acece0SRasmus Villemoes 		mv88e6xxx_reg_unlock(chip);
1847c0db24cSJohn David Anglin 		if (err)
1857c0db24cSJohn David Anglin 			goto out;
1867c0db24cSJohn David Anglin 		ctl1 &= GENMASK(chip->g1_irq.nirqs, 0);
1877c0db24cSJohn David Anglin 	} while (reg & ctl1);
1887c0db24cSJohn David Anglin 
189dc30c35bSAndrew Lunn out:
190dc30c35bSAndrew Lunn 	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
191dc30c35bSAndrew Lunn }
192dc30c35bSAndrew Lunn 
193294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
194294d711eSAndrew Lunn {
195294d711eSAndrew Lunn 	struct mv88e6xxx_chip *chip = dev_id;
196294d711eSAndrew Lunn 
197294d711eSAndrew Lunn 	return mv88e6xxx_g1_irq_thread_work(chip);
198294d711eSAndrew Lunn }
199294d711eSAndrew Lunn 
200dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
201dc30c35bSAndrew Lunn {
202dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
203dc30c35bSAndrew Lunn 
204c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
205dc30c35bSAndrew Lunn }
206dc30c35bSAndrew Lunn 
207dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
208dc30c35bSAndrew Lunn {
209dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
210dc30c35bSAndrew Lunn 	u16 mask = GENMASK(chip->g1_irq.nirqs, 0);
211dc30c35bSAndrew Lunn 	u16 reg;
212dc30c35bSAndrew Lunn 	int err;
213dc30c35bSAndrew Lunn 
214d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &reg);
215dc30c35bSAndrew Lunn 	if (err)
216dc30c35bSAndrew Lunn 		goto out;
217dc30c35bSAndrew Lunn 
218dc30c35bSAndrew Lunn 	reg &= ~mask;
219dc30c35bSAndrew Lunn 	reg |= (~chip->g1_irq.masked & mask);
220dc30c35bSAndrew Lunn 
221d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg);
222dc30c35bSAndrew Lunn 	if (err)
223dc30c35bSAndrew Lunn 		goto out;
224dc30c35bSAndrew Lunn 
225dc30c35bSAndrew Lunn out:
226c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
227dc30c35bSAndrew Lunn }
228dc30c35bSAndrew Lunn 
2296eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g1_irq_chip = {
230dc30c35bSAndrew Lunn 	.name			= "mv88e6xxx-g1",
231dc30c35bSAndrew Lunn 	.irq_mask		= mv88e6xxx_g1_irq_mask,
232dc30c35bSAndrew Lunn 	.irq_unmask		= mv88e6xxx_g1_irq_unmask,
233dc30c35bSAndrew Lunn 	.irq_bus_lock		= mv88e6xxx_g1_irq_bus_lock,
234dc30c35bSAndrew Lunn 	.irq_bus_sync_unlock	= mv88e6xxx_g1_irq_bus_sync_unlock,
235dc30c35bSAndrew Lunn };
236dc30c35bSAndrew Lunn 
237dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d,
238dc30c35bSAndrew Lunn 				       unsigned int irq,
239dc30c35bSAndrew Lunn 				       irq_hw_number_t hwirq)
240dc30c35bSAndrew Lunn {
241dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = d->host_data;
242dc30c35bSAndrew Lunn 
243dc30c35bSAndrew Lunn 	irq_set_chip_data(irq, d->host_data);
244dc30c35bSAndrew Lunn 	irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq);
245dc30c35bSAndrew Lunn 	irq_set_noprobe(irq);
246dc30c35bSAndrew Lunn 
247dc30c35bSAndrew Lunn 	return 0;
248dc30c35bSAndrew Lunn }
249dc30c35bSAndrew Lunn 
250dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = {
251dc30c35bSAndrew Lunn 	.map	= mv88e6xxx_g1_irq_domain_map,
252dc30c35bSAndrew Lunn 	.xlate	= irq_domain_xlate_twocell,
253dc30c35bSAndrew Lunn };
254dc30c35bSAndrew Lunn 
2553d82475aSUwe Kleine-König /* To be called with reg_lock held */
256294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip)
257dc30c35bSAndrew Lunn {
258dc30c35bSAndrew Lunn 	int irq, virq;
2593460a577SAndrew Lunn 	u16 mask;
2603460a577SAndrew Lunn 
261d77f4321SVivien Didelot 	mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
2623d5fdba1SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
263d77f4321SVivien Didelot 	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
2643460a577SAndrew Lunn 
2655edef2f2SAndreas Färber 	for (irq = 0; irq < chip->g1_irq.nirqs; irq++) {
266a3db3d3aSAndrew Lunn 		virq = irq_find_mapping(chip->g1_irq.domain, irq);
267dc30c35bSAndrew Lunn 		irq_dispose_mapping(virq);
268dc30c35bSAndrew Lunn 	}
269dc30c35bSAndrew Lunn 
270a3db3d3aSAndrew Lunn 	irq_domain_remove(chip->g1_irq.domain);
271dc30c35bSAndrew Lunn }
272dc30c35bSAndrew Lunn 
273294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
274294d711eSAndrew Lunn {
2753d82475aSUwe Kleine-König 	/*
2763d82475aSUwe Kleine-König 	 * free_irq must be called without reg_lock taken because the irq
2773d82475aSUwe Kleine-König 	 * handler takes this lock, too.
2783d82475aSUwe Kleine-König 	 */
279294d711eSAndrew Lunn 	free_irq(chip->irq, chip);
2803d82475aSUwe Kleine-König 
281c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2823d82475aSUwe Kleine-König 	mv88e6xxx_g1_irq_free_common(chip);
283c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
284294d711eSAndrew Lunn }
285294d711eSAndrew Lunn 
286294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip)
287dc30c35bSAndrew Lunn {
2883dd0ef05SAndrew Lunn 	int err, irq, virq;
2893dd0ef05SAndrew Lunn 	u16 reg, mask;
290dc30c35bSAndrew Lunn 
291dc30c35bSAndrew Lunn 	chip->g1_irq.nirqs = chip->info->g1_irqs;
292dc30c35bSAndrew Lunn 	chip->g1_irq.domain = irq_domain_add_simple(
293dc30c35bSAndrew Lunn 		NULL, chip->g1_irq.nirqs, 0,
294dc30c35bSAndrew Lunn 		&mv88e6xxx_g1_irq_domain_ops, chip);
295dc30c35bSAndrew Lunn 	if (!chip->g1_irq.domain)
296dc30c35bSAndrew Lunn 		return -ENOMEM;
297dc30c35bSAndrew Lunn 
298dc30c35bSAndrew Lunn 	for (irq = 0; irq < chip->g1_irq.nirqs; irq++)
299dc30c35bSAndrew Lunn 		irq_create_mapping(chip->g1_irq.domain, irq);
300dc30c35bSAndrew Lunn 
301dc30c35bSAndrew Lunn 	chip->g1_irq.chip = mv88e6xxx_g1_irq_chip;
302dc30c35bSAndrew Lunn 	chip->g1_irq.masked = ~0;
303dc30c35bSAndrew Lunn 
304d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
305dc30c35bSAndrew Lunn 	if (err)
3063dd0ef05SAndrew Lunn 		goto out_mapping;
307dc30c35bSAndrew Lunn 
3083dd0ef05SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
309dc30c35bSAndrew Lunn 
310d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
311dc30c35bSAndrew Lunn 	if (err)
3123dd0ef05SAndrew Lunn 		goto out_disable;
313dc30c35bSAndrew Lunn 
314dc30c35bSAndrew Lunn 	/* Reading the interrupt status clears (most of) them */
31582466921SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
316dc30c35bSAndrew Lunn 	if (err)
3173dd0ef05SAndrew Lunn 		goto out_disable;
318dc30c35bSAndrew Lunn 
319dc30c35bSAndrew Lunn 	return 0;
320dc30c35bSAndrew Lunn 
3213dd0ef05SAndrew Lunn out_disable:
3223d5fdba1SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
323d77f4321SVivien Didelot 	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
3243dd0ef05SAndrew Lunn 
3253dd0ef05SAndrew Lunn out_mapping:
3263dd0ef05SAndrew Lunn 	for (irq = 0; irq < 16; irq++) {
3273dd0ef05SAndrew Lunn 		virq = irq_find_mapping(chip->g1_irq.domain, irq);
3283dd0ef05SAndrew Lunn 		irq_dispose_mapping(virq);
3293dd0ef05SAndrew Lunn 	}
3303dd0ef05SAndrew Lunn 
3313dd0ef05SAndrew Lunn 	irq_domain_remove(chip->g1_irq.domain);
332dc30c35bSAndrew Lunn 
333dc30c35bSAndrew Lunn 	return err;
334dc30c35bSAndrew Lunn }
335dc30c35bSAndrew Lunn 
336294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
337294d711eSAndrew Lunn {
338f6d9758bSAndrew Lunn 	static struct lock_class_key lock_key;
339f6d9758bSAndrew Lunn 	static struct lock_class_key request_key;
340294d711eSAndrew Lunn 	int err;
341294d711eSAndrew Lunn 
342294d711eSAndrew Lunn 	err = mv88e6xxx_g1_irq_setup_common(chip);
343294d711eSAndrew Lunn 	if (err)
344294d711eSAndrew Lunn 		return err;
345294d711eSAndrew Lunn 
346f6d9758bSAndrew Lunn 	/* These lock classes tells lockdep that global 1 irqs are in
347f6d9758bSAndrew Lunn 	 * a different category than their parent GPIO, so it won't
348f6d9758bSAndrew Lunn 	 * report false recursion.
349f6d9758bSAndrew Lunn 	 */
350f6d9758bSAndrew Lunn 	irq_set_lockdep_class(chip->irq, &lock_key, &request_key);
351f6d9758bSAndrew Lunn 
3523095383aSAndrew Lunn 	snprintf(chip->irq_name, sizeof(chip->irq_name),
3533095383aSAndrew Lunn 		 "mv88e6xxx-%s", dev_name(chip->dev));
3543095383aSAndrew Lunn 
355c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
356294d711eSAndrew Lunn 	err = request_threaded_irq(chip->irq, NULL,
357294d711eSAndrew Lunn 				   mv88e6xxx_g1_irq_thread_fn,
3580340376eSMarek Behún 				   IRQF_ONESHOT | IRQF_SHARED,
3593095383aSAndrew Lunn 				   chip->irq_name, chip);
360c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
361294d711eSAndrew Lunn 	if (err)
362294d711eSAndrew Lunn 		mv88e6xxx_g1_irq_free_common(chip);
363294d711eSAndrew Lunn 
364294d711eSAndrew Lunn 	return err;
365294d711eSAndrew Lunn }
366294d711eSAndrew Lunn 
367294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work)
368294d711eSAndrew Lunn {
369294d711eSAndrew Lunn 	struct mv88e6xxx_chip *chip = container_of(work,
370294d711eSAndrew Lunn 						   struct mv88e6xxx_chip,
371294d711eSAndrew Lunn 						   irq_poll_work.work);
372294d711eSAndrew Lunn 	mv88e6xxx_g1_irq_thread_work(chip);
373294d711eSAndrew Lunn 
374294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
375294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
376294d711eSAndrew Lunn }
377294d711eSAndrew Lunn 
378294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip)
379294d711eSAndrew Lunn {
380294d711eSAndrew Lunn 	int err;
381294d711eSAndrew Lunn 
382294d711eSAndrew Lunn 	err = mv88e6xxx_g1_irq_setup_common(chip);
383294d711eSAndrew Lunn 	if (err)
384294d711eSAndrew Lunn 		return err;
385294d711eSAndrew Lunn 
386294d711eSAndrew Lunn 	kthread_init_delayed_work(&chip->irq_poll_work,
387294d711eSAndrew Lunn 				  mv88e6xxx_irq_poll);
388294d711eSAndrew Lunn 
3893f8b8696SFlorian Fainelli 	chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev));
390294d711eSAndrew Lunn 	if (IS_ERR(chip->kworker))
391294d711eSAndrew Lunn 		return PTR_ERR(chip->kworker);
392294d711eSAndrew Lunn 
393294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
394294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
395294d711eSAndrew Lunn 
396294d711eSAndrew Lunn 	return 0;
397294d711eSAndrew Lunn }
398294d711eSAndrew Lunn 
399294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip)
400294d711eSAndrew Lunn {
401294d711eSAndrew Lunn 	kthread_cancel_delayed_work_sync(&chip->irq_poll_work);
402294d711eSAndrew Lunn 	kthread_destroy_worker(chip->kworker);
4033d82475aSUwe Kleine-König 
404c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
4053d82475aSUwe Kleine-König 	mv88e6xxx_g1_irq_free_common(chip);
406c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
407294d711eSAndrew Lunn }
408294d711eSAndrew Lunn 
40964d47d50SRussell King static int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip,
41064d47d50SRussell King 					   int port, phy_interface_t interface)
41164d47d50SRussell King {
41264d47d50SRussell King 	int err;
41364d47d50SRussell King 
41464d47d50SRussell King 	if (chip->info->ops->port_set_rgmii_delay) {
41564d47d50SRussell King 		err = chip->info->ops->port_set_rgmii_delay(chip, port,
41664d47d50SRussell King 							    interface);
41764d47d50SRussell King 		if (err && err != -EOPNOTSUPP)
41864d47d50SRussell King 			return err;
41964d47d50SRussell King 	}
42064d47d50SRussell King 
42164d47d50SRussell King 	if (chip->info->ops->port_set_cmode) {
42264d47d50SRussell King 		err = chip->info->ops->port_set_cmode(chip, port,
42364d47d50SRussell King 						      interface);
42464d47d50SRussell King 		if (err && err != -EOPNOTSUPP)
42564d47d50SRussell King 			return err;
42664d47d50SRussell King 	}
42764d47d50SRussell King 
42864d47d50SRussell King 	return 0;
42964d47d50SRussell King }
43064d47d50SRussell King 
431a5a6858bSRussell King static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
432a5a6858bSRussell King 				    int link, int speed, int duplex, int pause,
433d78343d2SVivien Didelot 				    phy_interface_t mode)
434d78343d2SVivien Didelot {
435d78343d2SVivien Didelot 	int err;
436d78343d2SVivien Didelot 
437d78343d2SVivien Didelot 	if (!chip->info->ops->port_set_link)
438d78343d2SVivien Didelot 		return 0;
439d78343d2SVivien Didelot 
440d78343d2SVivien Didelot 	/* Port's MAC control must not be changed unless the link is down */
44143c8e0aeSHubert Feurstein 	err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN);
442d78343d2SVivien Didelot 	if (err)
443d78343d2SVivien Didelot 		return err;
444d78343d2SVivien Didelot 
445f365c6f7SRussell King 	if (chip->info->ops->port_set_speed_duplex) {
446f365c6f7SRussell King 		err = chip->info->ops->port_set_speed_duplex(chip, port,
447f365c6f7SRussell King 							     speed, duplex);
448d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
449d78343d2SVivien Didelot 			goto restore_link;
450d78343d2SVivien Didelot 	}
451d78343d2SVivien Didelot 
4527cbbee05SAndrew Lunn 	if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode)
4537cbbee05SAndrew Lunn 		mode = chip->info->ops->port_max_speed_mode(port);
4547cbbee05SAndrew Lunn 
45554186b91SAndrew Lunn 	if (chip->info->ops->port_set_pause) {
45654186b91SAndrew Lunn 		err = chip->info->ops->port_set_pause(chip, port, pause);
45754186b91SAndrew Lunn 		if (err)
45854186b91SAndrew Lunn 			goto restore_link;
45954186b91SAndrew Lunn 	}
46054186b91SAndrew Lunn 
46164d47d50SRussell King 	err = mv88e6xxx_port_config_interface(chip, port, mode);
462d78343d2SVivien Didelot restore_link:
463d78343d2SVivien Didelot 	if (chip->info->ops->port_set_link(chip, port, link))
464774439e5SVivien Didelot 		dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
465d78343d2SVivien Didelot 
466d78343d2SVivien Didelot 	return err;
467d78343d2SVivien Didelot }
468d78343d2SVivien Didelot 
469d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
470d700ec41SMarek Vasut {
471d700ec41SMarek Vasut 	struct mv88e6xxx_chip *chip = ds->priv;
472d700ec41SMarek Vasut 
473d700ec41SMarek Vasut 	return port < chip->info->num_internal_phys;
474d700ec41SMarek Vasut }
475d700ec41SMarek Vasut 
4765d5b231dSRussell King static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port)
4775d5b231dSRussell King {
4785d5b231dSRussell King 	u16 reg;
4795d5b231dSRussell King 	int err;
4805d5b231dSRussell King 
4812b29cb9eSRussell King (Oracle) 	/* The 88e6250 family does not have the PHY detect bit. Instead,
4822b29cb9eSRussell King (Oracle) 	 * report whether the port is internal.
4832b29cb9eSRussell King (Oracle) 	 */
4842b29cb9eSRussell King (Oracle) 	if (chip->info->family == MV88E6XXX_FAMILY_6250)
4852b29cb9eSRussell King (Oracle) 		return port < chip->info->num_internal_phys;
4862b29cb9eSRussell King (Oracle) 
4875d5b231dSRussell King 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
4885d5b231dSRussell King 	if (err) {
4895d5b231dSRussell King 		dev_err(chip->dev,
4905d5b231dSRussell King 			"p%d: %s: failed to read port status\n",
4915d5b231dSRussell King 			port, __func__);
4925d5b231dSRussell King 		return err;
4935d5b231dSRussell King 	}
4945d5b231dSRussell King 
4955d5b231dSRussell King 	return !!(reg & MV88E6XXX_PORT_STS_PHY_DETECT);
4965d5b231dSRussell King }
4975d5b231dSRussell King 
498a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port,
499a5a6858bSRussell King 					  struct phylink_link_state *state)
500a5a6858bSRussell King {
501a5a6858bSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
502193c5b26SPavana Sharma 	int lane;
503a5a6858bSRussell King 	int err;
504a5a6858bSRussell King 
505a5a6858bSRussell King 	mv88e6xxx_reg_lock(chip);
506a5a6858bSRussell King 	lane = mv88e6xxx_serdes_get_lane(chip, port);
507193c5b26SPavana Sharma 	if (lane >= 0 && chip->info->ops->serdes_pcs_get_state)
508a5a6858bSRussell King 		err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
509a5a6858bSRussell King 							    state);
510a5a6858bSRussell King 	else
511a5a6858bSRussell King 		err = -EOPNOTSUPP;
512a5a6858bSRussell King 	mv88e6xxx_reg_unlock(chip);
513a5a6858bSRussell King 
514a5a6858bSRussell King 	return err;
515a5a6858bSRussell King }
516a5a6858bSRussell King 
517a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
518a5a6858bSRussell King 				       unsigned int mode,
519a5a6858bSRussell King 				       phy_interface_t interface,
520a5a6858bSRussell King 				       const unsigned long *advertise)
521a5a6858bSRussell King {
522a5a6858bSRussell King 	const struct mv88e6xxx_ops *ops = chip->info->ops;
523193c5b26SPavana Sharma 	int lane;
524a5a6858bSRussell King 
525a5a6858bSRussell King 	if (ops->serdes_pcs_config) {
526a5a6858bSRussell King 		lane = mv88e6xxx_serdes_get_lane(chip, port);
527193c5b26SPavana Sharma 		if (lane >= 0)
528a5a6858bSRussell King 			return ops->serdes_pcs_config(chip, port, lane, mode,
529a5a6858bSRussell King 						      interface, advertise);
530a5a6858bSRussell King 	}
531a5a6858bSRussell King 
532a5a6858bSRussell King 	return 0;
533a5a6858bSRussell King }
534a5a6858bSRussell King 
535a5a6858bSRussell King static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port)
536a5a6858bSRussell King {
537a5a6858bSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
538a5a6858bSRussell King 	const struct mv88e6xxx_ops *ops;
539a5a6858bSRussell King 	int err = 0;
540193c5b26SPavana Sharma 	int lane;
541a5a6858bSRussell King 
542a5a6858bSRussell King 	ops = chip->info->ops;
543a5a6858bSRussell King 
544a5a6858bSRussell King 	if (ops->serdes_pcs_an_restart) {
545a5a6858bSRussell King 		mv88e6xxx_reg_lock(chip);
546a5a6858bSRussell King 		lane = mv88e6xxx_serdes_get_lane(chip, port);
547193c5b26SPavana Sharma 		if (lane >= 0)
548a5a6858bSRussell King 			err = ops->serdes_pcs_an_restart(chip, port, lane);
549a5a6858bSRussell King 		mv88e6xxx_reg_unlock(chip);
550a5a6858bSRussell King 
551a5a6858bSRussell King 		if (err)
552a5a6858bSRussell King 			dev_err(ds->dev, "p%d: failed to restart AN\n", port);
553a5a6858bSRussell King 	}
554a5a6858bSRussell King }
555a5a6858bSRussell King 
556a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
557a5a6858bSRussell King 					unsigned int mode,
558a5a6858bSRussell King 					int speed, int duplex)
559a5a6858bSRussell King {
560a5a6858bSRussell King 	const struct mv88e6xxx_ops *ops = chip->info->ops;
561193c5b26SPavana Sharma 	int lane;
562a5a6858bSRussell King 
563a5a6858bSRussell King 	if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) {
564a5a6858bSRussell King 		lane = mv88e6xxx_serdes_get_lane(chip, port);
565193c5b26SPavana Sharma 		if (lane >= 0)
566a5a6858bSRussell King 			return ops->serdes_pcs_link_up(chip, port, lane,
567a5a6858bSRussell King 						       speed, duplex);
568a5a6858bSRussell King 	}
569a5a6858bSRussell King 
570a5a6858bSRussell King 	return 0;
571a5a6858bSRussell King }
572a5a6858bSRussell King 
573d4ebf12bSRussell King (Oracle) static const u8 mv88e6185_phy_interface_modes[] = {
574d4ebf12bSRussell King (Oracle) 	[MV88E6185_PORT_STS_CMODE_GMII_FD]	 = PHY_INTERFACE_MODE_GMII,
575d4ebf12bSRussell King (Oracle) 	[MV88E6185_PORT_STS_CMODE_MII_100_FD_PS] = PHY_INTERFACE_MODE_MII,
576d4ebf12bSRussell King (Oracle) 	[MV88E6185_PORT_STS_CMODE_MII_100]	 = PHY_INTERFACE_MODE_MII,
577d4ebf12bSRussell King (Oracle) 	[MV88E6185_PORT_STS_CMODE_MII_10]	 = PHY_INTERFACE_MODE_MII,
578d4ebf12bSRussell King (Oracle) 	[MV88E6185_PORT_STS_CMODE_SERDES]	 = PHY_INTERFACE_MODE_1000BASEX,
579d4ebf12bSRussell King (Oracle) 	[MV88E6185_PORT_STS_CMODE_1000BASE_X]	 = PHY_INTERFACE_MODE_1000BASEX,
580d4ebf12bSRussell King (Oracle) 	[MV88E6185_PORT_STS_CMODE_PHY]		 = PHY_INTERFACE_MODE_SGMII,
581d4ebf12bSRussell King (Oracle) };
582d4ebf12bSRussell King (Oracle) 
583d0b78ab1STobias Waldekranz static void mv88e6095_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
584d0b78ab1STobias Waldekranz 				       struct phylink_config *config)
585d0b78ab1STobias Waldekranz {
586d0b78ab1STobias Waldekranz 	u8 cmode = chip->ports[port].cmode;
587d0b78ab1STobias Waldekranz 
588d0b78ab1STobias Waldekranz 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100;
589d0b78ab1STobias Waldekranz 
590d0b78ab1STobias Waldekranz 	if (mv88e6xxx_phy_is_internal(chip->ds, port)) {
591d0b78ab1STobias Waldekranz 		__set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
592d0b78ab1STobias Waldekranz 	} else {
593d0b78ab1STobias Waldekranz 		if (cmode < ARRAY_SIZE(mv88e6185_phy_interface_modes) &&
594d0b78ab1STobias Waldekranz 		    mv88e6185_phy_interface_modes[cmode])
595d0b78ab1STobias Waldekranz 			__set_bit(mv88e6185_phy_interface_modes[cmode],
596d0b78ab1STobias Waldekranz 				  config->supported_interfaces);
597d0b78ab1STobias Waldekranz 
598d0b78ab1STobias Waldekranz 		config->mac_capabilities |= MAC_1000FD;
599d0b78ab1STobias Waldekranz 	}
600d0b78ab1STobias Waldekranz }
601d0b78ab1STobias Waldekranz 
602d4ebf12bSRussell King (Oracle) static void mv88e6185_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
603d4ebf12bSRussell King (Oracle) 				       struct phylink_config *config)
604d4ebf12bSRussell King (Oracle) {
605d4ebf12bSRussell King (Oracle) 	u8 cmode = chip->ports[port].cmode;
606d4ebf12bSRussell King (Oracle) 
607dde41a69SDan Carpenter 	if (cmode < ARRAY_SIZE(mv88e6185_phy_interface_modes) &&
608d4ebf12bSRussell King (Oracle) 	    mv88e6185_phy_interface_modes[cmode])
609d4ebf12bSRussell King (Oracle) 		__set_bit(mv88e6185_phy_interface_modes[cmode],
610d4ebf12bSRussell King (Oracle) 			  config->supported_interfaces);
611d4ebf12bSRussell King (Oracle) 
612d4ebf12bSRussell King (Oracle) 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
613d4ebf12bSRussell King (Oracle) 				   MAC_1000FD;
614d4ebf12bSRussell King (Oracle) }
615d4ebf12bSRussell King (Oracle) 
616d4ebf12bSRussell King (Oracle) static const u8 mv88e6xxx_phy_interface_modes[] = {
617d4ebf12bSRussell King (Oracle) 	[MV88E6XXX_PORT_STS_CMODE_MII_PHY]	= PHY_INTERFACE_MODE_MII,
618d4ebf12bSRussell King (Oracle) 	[MV88E6XXX_PORT_STS_CMODE_MII]		= PHY_INTERFACE_MODE_MII,
619d4ebf12bSRussell King (Oracle) 	[MV88E6XXX_PORT_STS_CMODE_GMII]		= PHY_INTERFACE_MODE_GMII,
620d4ebf12bSRussell King (Oracle) 	[MV88E6XXX_PORT_STS_CMODE_RMII_PHY]	= PHY_INTERFACE_MODE_RMII,
621d4ebf12bSRussell King (Oracle) 	[MV88E6XXX_PORT_STS_CMODE_RMII]		= PHY_INTERFACE_MODE_RMII,
622d4ebf12bSRussell King (Oracle) 	[MV88E6XXX_PORT_STS_CMODE_100BASEX]	= PHY_INTERFACE_MODE_100BASEX,
623d4ebf12bSRussell King (Oracle) 	[MV88E6XXX_PORT_STS_CMODE_1000BASEX]	= PHY_INTERFACE_MODE_1000BASEX,
624d4ebf12bSRussell King (Oracle) 	[MV88E6XXX_PORT_STS_CMODE_SGMII]	= PHY_INTERFACE_MODE_SGMII,
625d4ebf12bSRussell King (Oracle) 	/* higher interface modes are not needed here, since ports supporting
626d4ebf12bSRussell King (Oracle) 	 * them are writable, and so the supported interfaces are filled in the
627d4ebf12bSRussell King (Oracle) 	 * corresponding .phylink_set_interfaces() implementation below
6286c422e34SRussell King 	 */
629d4ebf12bSRussell King (Oracle) };
630d4ebf12bSRussell King (Oracle) 
631d4ebf12bSRussell King (Oracle) static void mv88e6xxx_translate_cmode(u8 cmode, unsigned long *supported)
632d4ebf12bSRussell King (Oracle) {
633d4ebf12bSRussell King (Oracle) 	if (cmode < ARRAY_SIZE(mv88e6xxx_phy_interface_modes) &&
634d4ebf12bSRussell King (Oracle) 	    mv88e6xxx_phy_interface_modes[cmode])
635d4ebf12bSRussell King (Oracle) 		__set_bit(mv88e6xxx_phy_interface_modes[cmode], supported);
636d4ebf12bSRussell King (Oracle) 	else if (cmode == MV88E6XXX_PORT_STS_CMODE_RGMII)
637d4ebf12bSRussell King (Oracle) 		phy_interface_set_rgmii(supported);
638d4ebf12bSRussell King (Oracle) }
639d4ebf12bSRussell King (Oracle) 
640d4ebf12bSRussell King (Oracle) static void mv88e6250_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
641d4ebf12bSRussell King (Oracle) 				       struct phylink_config *config)
642d4ebf12bSRussell King (Oracle) {
643d4ebf12bSRussell King (Oracle) 	unsigned long *supported = config->supported_interfaces;
644d4ebf12bSRussell King (Oracle) 
645d4ebf12bSRussell King (Oracle) 	/* Translate the default cmode */
646d4ebf12bSRussell King (Oracle) 	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
647d4ebf12bSRussell King (Oracle) 
648d4ebf12bSRussell King (Oracle) 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100;
649d4ebf12bSRussell King (Oracle) }
650d4ebf12bSRussell King (Oracle) 
651d4ebf12bSRussell King (Oracle) static int mv88e6352_get_port4_serdes_cmode(struct mv88e6xxx_chip *chip)
652d4ebf12bSRussell King (Oracle) {
653d4ebf12bSRussell King (Oracle) 	u16 reg, val;
654d4ebf12bSRussell King (Oracle) 	int err;
655d4ebf12bSRussell King (Oracle) 
656d4ebf12bSRussell King (Oracle) 	err = mv88e6xxx_port_read(chip, 4, MV88E6XXX_PORT_STS, &reg);
657d4ebf12bSRussell King (Oracle) 	if (err)
658d4ebf12bSRussell King (Oracle) 		return err;
659d4ebf12bSRussell King (Oracle) 
660d4ebf12bSRussell King (Oracle) 	/* If PHY_DETECT is zero, then we are not in auto-media mode */
661d4ebf12bSRussell King (Oracle) 	if (!(reg & MV88E6XXX_PORT_STS_PHY_DETECT))
662d4ebf12bSRussell King (Oracle) 		return 0xf;
663d4ebf12bSRussell King (Oracle) 
664d4ebf12bSRussell King (Oracle) 	val = reg & ~MV88E6XXX_PORT_STS_PHY_DETECT;
665d4ebf12bSRussell King (Oracle) 	err = mv88e6xxx_port_write(chip, 4, MV88E6XXX_PORT_STS, val);
666d4ebf12bSRussell King (Oracle) 	if (err)
667d4ebf12bSRussell King (Oracle) 		return err;
668d4ebf12bSRussell King (Oracle) 
669d4ebf12bSRussell King (Oracle) 	err = mv88e6xxx_port_read(chip, 4, MV88E6XXX_PORT_STS, &val);
670d4ebf12bSRussell King (Oracle) 	if (err)
671d4ebf12bSRussell King (Oracle) 		return err;
672d4ebf12bSRussell King (Oracle) 
673d4ebf12bSRussell King (Oracle) 	/* Restore PHY_DETECT value */
674d4ebf12bSRussell King (Oracle) 	err = mv88e6xxx_port_write(chip, 4, MV88E6XXX_PORT_STS, reg);
675d4ebf12bSRussell King (Oracle) 	if (err)
676d4ebf12bSRussell King (Oracle) 		return err;
677d4ebf12bSRussell King (Oracle) 
678d4ebf12bSRussell King (Oracle) 	return val & MV88E6XXX_PORT_STS_CMODE_MASK;
679d4ebf12bSRussell King (Oracle) }
680d4ebf12bSRussell King (Oracle) 
681d4ebf12bSRussell King (Oracle) static void mv88e6352_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
682d4ebf12bSRussell King (Oracle) 				       struct phylink_config *config)
683d4ebf12bSRussell King (Oracle) {
684d4ebf12bSRussell King (Oracle) 	unsigned long *supported = config->supported_interfaces;
685d4ebf12bSRussell King (Oracle) 	int err, cmode;
686d4ebf12bSRussell King (Oracle) 
687d4ebf12bSRussell King (Oracle) 	/* Translate the default cmode */
688d4ebf12bSRussell King (Oracle) 	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
689d4ebf12bSRussell King (Oracle) 
690d4ebf12bSRussell King (Oracle) 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
691d4ebf12bSRussell King (Oracle) 				   MAC_1000FD;
692d4ebf12bSRussell King (Oracle) 
693d4ebf12bSRussell King (Oracle) 	/* Port 4 supports automedia if the serdes is associated with it. */
694d4ebf12bSRussell King (Oracle) 	if (port == 4) {
695d4ebf12bSRussell King (Oracle) 		mv88e6xxx_reg_lock(chip);
696d4ebf12bSRussell King (Oracle) 		err = mv88e6352_g2_scratch_port_has_serdes(chip, port);
697d4ebf12bSRussell King (Oracle) 		if (err < 0)
698d4ebf12bSRussell King (Oracle) 			dev_err(chip->dev, "p%d: failed to read scratch\n",
699d4ebf12bSRussell King (Oracle) 				port);
700d4ebf12bSRussell King (Oracle) 		if (err <= 0)
701d4ebf12bSRussell King (Oracle) 			goto unlock;
702d4ebf12bSRussell King (Oracle) 
703d4ebf12bSRussell King (Oracle) 		cmode = mv88e6352_get_port4_serdes_cmode(chip);
704d4ebf12bSRussell King (Oracle) 		if (cmode < 0)
705d4ebf12bSRussell King (Oracle) 			dev_err(chip->dev, "p%d: failed to read serdes cmode\n",
706d4ebf12bSRussell King (Oracle) 				port);
707d4ebf12bSRussell King (Oracle) 		else
708d4ebf12bSRussell King (Oracle) 			mv88e6xxx_translate_cmode(cmode, supported);
709d4ebf12bSRussell King (Oracle) unlock:
710d4ebf12bSRussell King (Oracle) 		mv88e6xxx_reg_unlock(chip);
711d4ebf12bSRussell King (Oracle) 	}
712d4ebf12bSRussell King (Oracle) }
713d4ebf12bSRussell King (Oracle) 
714d4ebf12bSRussell King (Oracle) static void mv88e6341_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
715d4ebf12bSRussell King (Oracle) 				       struct phylink_config *config)
716d4ebf12bSRussell King (Oracle) {
717d4ebf12bSRussell King (Oracle) 	unsigned long *supported = config->supported_interfaces;
718d4ebf12bSRussell King (Oracle) 
719d4ebf12bSRussell King (Oracle) 	/* Translate the default cmode */
720d4ebf12bSRussell King (Oracle) 	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
721d4ebf12bSRussell King (Oracle) 
722d4ebf12bSRussell King (Oracle) 	/* No ethtool bits for 200Mbps */
723d4ebf12bSRussell King (Oracle) 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
724d4ebf12bSRussell King (Oracle) 				   MAC_1000FD;
725d4ebf12bSRussell King (Oracle) 
726d4ebf12bSRussell King (Oracle) 	/* The C_Mode field is programmable on port 5 */
727d4ebf12bSRussell King (Oracle) 	if (port == 5) {
728d4ebf12bSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_SGMII, supported);
729d4ebf12bSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
730d4ebf12bSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
731d4ebf12bSRussell King (Oracle) 
732d4ebf12bSRussell King (Oracle) 		config->mac_capabilities |= MAC_2500FD;
733d4ebf12bSRussell King (Oracle) 	}
734d4ebf12bSRussell King (Oracle) }
735d4ebf12bSRussell King (Oracle) 
736d4ebf12bSRussell King (Oracle) static void mv88e6390_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
737d4ebf12bSRussell King (Oracle) 				       struct phylink_config *config)
738d4ebf12bSRussell King (Oracle) {
739d4ebf12bSRussell King (Oracle) 	unsigned long *supported = config->supported_interfaces;
740d4ebf12bSRussell King (Oracle) 
741d4ebf12bSRussell King (Oracle) 	/* Translate the default cmode */
742d4ebf12bSRussell King (Oracle) 	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
743d4ebf12bSRussell King (Oracle) 
744d4ebf12bSRussell King (Oracle) 	/* No ethtool bits for 200Mbps */
745d4ebf12bSRussell King (Oracle) 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
746d4ebf12bSRussell King (Oracle) 				   MAC_1000FD;
747d4ebf12bSRussell King (Oracle) 
748d4ebf12bSRussell King (Oracle) 	/* The C_Mode field is programmable on ports 9 and 10 */
749d4ebf12bSRussell King (Oracle) 	if (port == 9 || port == 10) {
750d4ebf12bSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_SGMII, supported);
751d4ebf12bSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
752d4ebf12bSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
753d4ebf12bSRussell King (Oracle) 
754d4ebf12bSRussell King (Oracle) 		config->mac_capabilities |= MAC_2500FD;
755d4ebf12bSRussell King (Oracle) 	}
756d4ebf12bSRussell King (Oracle) }
757d4ebf12bSRussell King (Oracle) 
758d4ebf12bSRussell King (Oracle) static void mv88e6390x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
759d4ebf12bSRussell King (Oracle) 					struct phylink_config *config)
760d4ebf12bSRussell King (Oracle) {
761d4ebf12bSRussell King (Oracle) 	unsigned long *supported = config->supported_interfaces;
762d4ebf12bSRussell King (Oracle) 
763d4ebf12bSRussell King (Oracle) 	mv88e6390_phylink_get_caps(chip, port, config);
764d4ebf12bSRussell King (Oracle) 
765d4ebf12bSRussell King (Oracle) 	/* For the 6x90X, ports 2-7 can be in automedia mode.
766d4ebf12bSRussell King (Oracle) 	 * (Note that 6x90 doesn't support RXAUI nor XAUI).
767d4ebf12bSRussell King (Oracle) 	 *
768d4ebf12bSRussell King (Oracle) 	 * Port 2 can also support 1000BASE-X in automedia mode if port 9 is
769d4ebf12bSRussell King (Oracle) 	 * configured for 1000BASE-X, SGMII or 2500BASE-X.
770d4ebf12bSRussell King (Oracle) 	 * Port 3-4 can also support 1000BASE-X in automedia mode if port 9 is
771d4ebf12bSRussell King (Oracle) 	 * configured for RXAUI, 1000BASE-X, SGMII or 2500BASE-X.
772d4ebf12bSRussell King (Oracle) 	 *
773d4ebf12bSRussell King (Oracle) 	 * Port 5 can also support 1000BASE-X in automedia mode if port 10 is
774d4ebf12bSRussell King (Oracle) 	 * configured for 1000BASE-X, SGMII or 2500BASE-X.
775d4ebf12bSRussell King (Oracle) 	 * Port 6-7 can also support 1000BASE-X in automedia mode if port 10 is
776d4ebf12bSRussell King (Oracle) 	 * configured for RXAUI, 1000BASE-X, SGMII or 2500BASE-X.
777d4ebf12bSRussell King (Oracle) 	 *
778d4ebf12bSRussell King (Oracle) 	 * For now, be permissive (as the old code was) and allow 1000BASE-X
779d4ebf12bSRussell King (Oracle) 	 * on ports 2..7.
780d4ebf12bSRussell King (Oracle) 	 */
781d4ebf12bSRussell King (Oracle) 	if (port >= 2 && port <= 7)
782d4ebf12bSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
783d4ebf12bSRussell King (Oracle) 
784d4ebf12bSRussell King (Oracle) 	/* The C_Mode field can also be programmed for 10G speeds */
785d4ebf12bSRussell King (Oracle) 	if (port == 9 || port == 10) {
786d4ebf12bSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_XAUI, supported);
787d4ebf12bSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_RXAUI, supported);
788d4ebf12bSRussell King (Oracle) 
789d4ebf12bSRussell King (Oracle) 		config->mac_capabilities |= MAC_10000FD;
790d4ebf12bSRussell King (Oracle) 	}
791d4ebf12bSRussell King (Oracle) }
792d4ebf12bSRussell King (Oracle) 
793d4ebf12bSRussell King (Oracle) static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
794d4ebf12bSRussell King (Oracle) 					struct phylink_config *config)
795d4ebf12bSRussell King (Oracle) {
796d4ebf12bSRussell King (Oracle) 	unsigned long *supported = config->supported_interfaces;
797d4ebf12bSRussell King (Oracle) 	bool is_6191x =
798d4ebf12bSRussell King (Oracle) 		chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X;
799d4ebf12bSRussell King (Oracle) 
800d4ebf12bSRussell King (Oracle) 	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
801d4ebf12bSRussell King (Oracle) 
802d4ebf12bSRussell King (Oracle) 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
803d4ebf12bSRussell King (Oracle) 				   MAC_1000FD;
804d4ebf12bSRussell King (Oracle) 
805d4ebf12bSRussell King (Oracle) 	/* The C_Mode field can be programmed for ports 0, 9 and 10 */
806d4ebf12bSRussell King (Oracle) 	if (port == 0 || port == 9 || port == 10) {
807d4ebf12bSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_SGMII, supported);
808d4ebf12bSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
809d4ebf12bSRussell King (Oracle) 
810d4ebf12bSRussell King (Oracle) 		/* 6191X supports >1G modes only on port 10 */
811d4ebf12bSRussell King (Oracle) 		if (!is_6191x || port == 10) {
812d4ebf12bSRussell King (Oracle) 			__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
813d4ebf12bSRussell King (Oracle) 			__set_bit(PHY_INTERFACE_MODE_5GBASER, supported);
814d4ebf12bSRussell King (Oracle) 			__set_bit(PHY_INTERFACE_MODE_10GBASER, supported);
815d4ebf12bSRussell King (Oracle) 			/* FIXME: USXGMII is not supported yet */
816d4ebf12bSRussell King (Oracle) 			/* __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); */
817d4ebf12bSRussell King (Oracle) 
818d4ebf12bSRussell King (Oracle) 			config->mac_capabilities |= MAC_2500FD | MAC_5000FD |
819d4ebf12bSRussell King (Oracle) 				MAC_10000FD;
820d4ebf12bSRussell King (Oracle) 		}
821d4ebf12bSRussell King (Oracle) 	}
822d4ebf12bSRussell King (Oracle) }
823d4ebf12bSRussell King (Oracle) 
824d4ebf12bSRussell King (Oracle) static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port,
825d4ebf12bSRussell King (Oracle) 			       struct phylink_config *config)
826d4ebf12bSRussell King (Oracle) {
827d4ebf12bSRussell King (Oracle) 	struct mv88e6xxx_chip *chip = ds->priv;
828d4ebf12bSRussell King (Oracle) 
829d4ebf12bSRussell King (Oracle) 	chip->info->ops->phylink_get_caps(chip, port, config);
830d4ebf12bSRussell King (Oracle) 
831d4ebf12bSRussell King (Oracle) 	/* Internal ports need GMII for PHYLIB */
832d4ebf12bSRussell King (Oracle) 	if (mv88e6xxx_phy_is_internal(ds, port))
833d4ebf12bSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_GMII,
834d4ebf12bSRussell King (Oracle) 			  config->supported_interfaces);
835c9a2356fSRussell King }
836c9a2356fSRussell King 
837c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
838c9a2356fSRussell King 				 unsigned int mode,
839c9a2356fSRussell King 				 const struct phylink_link_state *state)
840c9a2356fSRussell King {
841c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
842fad58190SRussell King 	struct mv88e6xxx_port *p;
84304ec4e62SRussell King (Oracle) 	int err = 0;
844c9a2356fSRussell King 
845fad58190SRussell King 	p = &chip->ports[port];
846fad58190SRussell King 
847c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
848fad58190SRussell King 
84904ec4e62SRussell King (Oracle) 	if (mode != MLO_AN_PHY || !mv88e6xxx_phy_is_internal(ds, port)) {
85004ec4e62SRussell King (Oracle) 		/* In inband mode, the link may come up at any time while the
85104ec4e62SRussell King (Oracle) 		 * link is not forced down. Force the link down while we
85204ec4e62SRussell King (Oracle) 		 * reconfigure the interface mode.
85304ec4e62SRussell King (Oracle) 		 */
85404ec4e62SRussell King (Oracle) 		if (mode == MLO_AN_INBAND &&
85504ec4e62SRussell King (Oracle) 		    p->interface != state->interface &&
85604ec4e62SRussell King (Oracle) 		    chip->info->ops->port_set_link)
85704ec4e62SRussell King (Oracle) 			chip->info->ops->port_set_link(chip, port,
85804ec4e62SRussell King (Oracle) 						       LINK_FORCED_DOWN);
85904ec4e62SRussell King (Oracle) 
86004ec4e62SRussell King (Oracle) 		err = mv88e6xxx_port_config_interface(chip, port,
86104ec4e62SRussell King (Oracle) 						      state->interface);
862a5a6858bSRussell King 		if (err && err != -EOPNOTSUPP)
863a5a6858bSRussell King 			goto err_unlock;
864a5a6858bSRussell King 
86504ec4e62SRussell King (Oracle) 		err = mv88e6xxx_serdes_pcs_config(chip, port, mode,
86604ec4e62SRussell King (Oracle) 						  state->interface,
867a5a6858bSRussell King 						  state->advertising);
86804ec4e62SRussell King (Oracle) 		/* FIXME: we should restart negotiation if something changed -
86904ec4e62SRussell King (Oracle) 		 * which is something we get if we convert to using phylinks
87004ec4e62SRussell King (Oracle) 		 * PCS operations.
871a5a6858bSRussell King 		 */
872a5a6858bSRussell King 		if (err > 0)
873a5a6858bSRussell King 			err = 0;
87404ec4e62SRussell King (Oracle) 	}
875a5a6858bSRussell King 
876fad58190SRussell King 	/* Undo the forced down state above after completing configuration
87704ec4e62SRussell King (Oracle) 	 * irrespective of its state on entry, which allows the link to come
87804ec4e62SRussell King (Oracle) 	 * up in the in-band case where there is no separate SERDES. Also
87904ec4e62SRussell King (Oracle) 	 * ensure that the link can come up if the PPU is in use and we are
88004ec4e62SRussell King (Oracle) 	 * in PHY mode (we treat the PPU as an effective in-band mechanism.)
881fad58190SRussell King 	 */
88204ec4e62SRussell King (Oracle) 	if (chip->info->ops->port_set_link &&
88304ec4e62SRussell King (Oracle) 	    ((mode == MLO_AN_INBAND && p->interface != state->interface) ||
88404ec4e62SRussell King (Oracle) 	     (mode == MLO_AN_PHY && mv88e6xxx_port_ppu_updates(chip, port))))
885fad58190SRussell King 		chip->info->ops->port_set_link(chip, port, LINK_UNFORCED);
886fad58190SRussell King 
887fad58190SRussell King 	p->interface = state->interface;
888fad58190SRussell King 
889a5a6858bSRussell King err_unlock:
890c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
891c9a2356fSRussell King 
892c9a2356fSRussell King 	if (err && err != -EOPNOTSUPP)
89364d47d50SRussell King 		dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port);
894c9a2356fSRussell King }
895c9a2356fSRussell King 
896c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
897c9a2356fSRussell King 				    unsigned int mode,
898c9a2356fSRussell King 				    phy_interface_t interface)
899c9a2356fSRussell King {
90030c4a5b0SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
90130c4a5b0SRussell King 	const struct mv88e6xxx_ops *ops;
90230c4a5b0SRussell King 	int err = 0;
90330c4a5b0SRussell King 
90430c4a5b0SRussell King 	ops = chip->info->ops;
90530c4a5b0SRussell King 
90630c4a5b0SRussell King 	mv88e6xxx_reg_lock(chip);
9072b29cb9eSRussell King (Oracle) 	/* Force the link down if we know the port may not be automatically
9082b29cb9eSRussell King (Oracle) 	 * updated by the switch or if we are using fixed-link mode.
9094a3e0aedSMaarten Zanders 	 */
9102b29cb9eSRussell King (Oracle) 	if ((!mv88e6xxx_port_ppu_updates(chip, port) ||
9114efe7662SChris Packham 	     mode == MLO_AN_FIXED) && ops->port_sync_link)
9124efe7662SChris Packham 		err = ops->port_sync_link(chip, port, mode, false);
9139d591fc0SMarek Behún 
9149d591fc0SMarek Behún 	if (!err && ops->port_set_speed_duplex)
9159d591fc0SMarek Behún 		err = ops->port_set_speed_duplex(chip, port, SPEED_UNFORCED,
9169d591fc0SMarek Behún 						 DUPLEX_UNFORCED);
91730c4a5b0SRussell King 	mv88e6xxx_reg_unlock(chip);
91830c4a5b0SRussell King 
91930c4a5b0SRussell King 	if (err)
92030c4a5b0SRussell King 		dev_err(chip->dev,
92130c4a5b0SRussell King 			"p%d: failed to force MAC link down\n", port);
92230c4a5b0SRussell King }
923c9a2356fSRussell King 
924c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
925c9a2356fSRussell King 				  unsigned int mode, phy_interface_t interface,
9265b502a7bSRussell King 				  struct phy_device *phydev,
9275b502a7bSRussell King 				  int speed, int duplex,
9285b502a7bSRussell King 				  bool tx_pause, bool rx_pause)
929c9a2356fSRussell King {
93030c4a5b0SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
93130c4a5b0SRussell King 	const struct mv88e6xxx_ops *ops;
93230c4a5b0SRussell King 	int err = 0;
93330c4a5b0SRussell King 
93430c4a5b0SRussell King 	ops = chip->info->ops;
93530c4a5b0SRussell King 
93630c4a5b0SRussell King 	mv88e6xxx_reg_lock(chip);
9372b29cb9eSRussell King (Oracle) 	/* Configure and force the link up if we know that the port may not
9382b29cb9eSRussell King (Oracle) 	 * automatically updated by the switch or if we are using fixed-link
9392b29cb9eSRussell King (Oracle) 	 * mode.
9404a3e0aedSMaarten Zanders 	 */
9412b29cb9eSRussell King (Oracle) 	if (!mv88e6xxx_port_ppu_updates(chip, port) ||
9424a3e0aedSMaarten Zanders 	    mode == MLO_AN_FIXED) {
94330c4a5b0SRussell King 		/* FIXME: for an automedia port, should we force the link
94430c4a5b0SRussell King 		 * down here - what if the link comes up due to "other" media
94530c4a5b0SRussell King 		 * while we're bringing the port up, how is the exclusivity
946a5a6858bSRussell King 		 * handled in the Marvell hardware? E.g. port 2 on 88E6390
94730c4a5b0SRussell King 		 * shared between internal PHY and Serdes.
94830c4a5b0SRussell King 		 */
949a5a6858bSRussell King 		err = mv88e6xxx_serdes_pcs_link_up(chip, port, mode, speed,
950a5a6858bSRussell King 						   duplex);
951a5a6858bSRussell King 		if (err)
952a5a6858bSRussell King 			goto error;
953a5a6858bSRussell King 
954f365c6f7SRussell King 		if (ops->port_set_speed_duplex) {
955f365c6f7SRussell King 			err = ops->port_set_speed_duplex(chip, port,
956f365c6f7SRussell King 							 speed, duplex);
95730c4a5b0SRussell King 			if (err && err != -EOPNOTSUPP)
95830c4a5b0SRussell King 				goto error;
95930c4a5b0SRussell King 		}
96030c4a5b0SRussell King 
9614efe7662SChris Packham 		if (ops->port_sync_link)
9624efe7662SChris Packham 			err = ops->port_sync_link(chip, port, mode, true);
9635d5b231dSRussell King 	}
96430c4a5b0SRussell King error:
96530c4a5b0SRussell King 	mv88e6xxx_reg_unlock(chip);
96630c4a5b0SRussell King 
96730c4a5b0SRussell King 	if (err && err != -EOPNOTSUPP)
96830c4a5b0SRussell King 		dev_err(ds->dev,
96930c4a5b0SRussell King 			"p%d: failed to configure MAC link up\n", port);
97030c4a5b0SRussell King }
971c9a2356fSRussell King 
972a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
973fad09c73SVivien Didelot {
974a605a0feSAndrew Lunn 	if (!chip->info->ops->stats_snapshot)
975a605a0feSAndrew Lunn 		return -EOPNOTSUPP;
976fad09c73SVivien Didelot 
977a605a0feSAndrew Lunn 	return chip->info->ops->stats_snapshot(chip, port);
978fad09c73SVivien Didelot }
979fad09c73SVivien Didelot 
980fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
981dfafe449SAndrew Lunn 	{ "in_good_octets",		8, 0x00, STATS_TYPE_BANK0, },
982dfafe449SAndrew Lunn 	{ "in_bad_octets",		4, 0x02, STATS_TYPE_BANK0, },
983dfafe449SAndrew Lunn 	{ "in_unicast",			4, 0x04, STATS_TYPE_BANK0, },
984dfafe449SAndrew Lunn 	{ "in_broadcasts",		4, 0x06, STATS_TYPE_BANK0, },
985dfafe449SAndrew Lunn 	{ "in_multicasts",		4, 0x07, STATS_TYPE_BANK0, },
986dfafe449SAndrew Lunn 	{ "in_pause",			4, 0x16, STATS_TYPE_BANK0, },
987dfafe449SAndrew Lunn 	{ "in_undersize",		4, 0x18, STATS_TYPE_BANK0, },
988dfafe449SAndrew Lunn 	{ "in_fragments",		4, 0x19, STATS_TYPE_BANK0, },
989dfafe449SAndrew Lunn 	{ "in_oversize",		4, 0x1a, STATS_TYPE_BANK0, },
990dfafe449SAndrew Lunn 	{ "in_jabber",			4, 0x1b, STATS_TYPE_BANK0, },
991dfafe449SAndrew Lunn 	{ "in_rx_error",		4, 0x1c, STATS_TYPE_BANK0, },
992dfafe449SAndrew Lunn 	{ "in_fcs_error",		4, 0x1d, STATS_TYPE_BANK0, },
993dfafe449SAndrew Lunn 	{ "out_octets",			8, 0x0e, STATS_TYPE_BANK0, },
994dfafe449SAndrew Lunn 	{ "out_unicast",		4, 0x10, STATS_TYPE_BANK0, },
995dfafe449SAndrew Lunn 	{ "out_broadcasts",		4, 0x13, STATS_TYPE_BANK0, },
996dfafe449SAndrew Lunn 	{ "out_multicasts",		4, 0x12, STATS_TYPE_BANK0, },
997dfafe449SAndrew Lunn 	{ "out_pause",			4, 0x15, STATS_TYPE_BANK0, },
998dfafe449SAndrew Lunn 	{ "excessive",			4, 0x11, STATS_TYPE_BANK0, },
999dfafe449SAndrew Lunn 	{ "collisions",			4, 0x1e, STATS_TYPE_BANK0, },
1000dfafe449SAndrew Lunn 	{ "deferred",			4, 0x05, STATS_TYPE_BANK0, },
1001dfafe449SAndrew Lunn 	{ "single",			4, 0x14, STATS_TYPE_BANK0, },
1002dfafe449SAndrew Lunn 	{ "multiple",			4, 0x17, STATS_TYPE_BANK0, },
1003dfafe449SAndrew Lunn 	{ "out_fcs_error",		4, 0x03, STATS_TYPE_BANK0, },
1004dfafe449SAndrew Lunn 	{ "late",			4, 0x1f, STATS_TYPE_BANK0, },
1005dfafe449SAndrew Lunn 	{ "hist_64bytes",		4, 0x08, STATS_TYPE_BANK0, },
1006dfafe449SAndrew Lunn 	{ "hist_65_127bytes",		4, 0x09, STATS_TYPE_BANK0, },
1007dfafe449SAndrew Lunn 	{ "hist_128_255bytes",		4, 0x0a, STATS_TYPE_BANK0, },
1008dfafe449SAndrew Lunn 	{ "hist_256_511bytes",		4, 0x0b, STATS_TYPE_BANK0, },
1009dfafe449SAndrew Lunn 	{ "hist_512_1023bytes",		4, 0x0c, STATS_TYPE_BANK0, },
1010dfafe449SAndrew Lunn 	{ "hist_1024_max_bytes",	4, 0x0d, STATS_TYPE_BANK0, },
1011dfafe449SAndrew Lunn 	{ "sw_in_discards",		4, 0x10, STATS_TYPE_PORT, },
1012dfafe449SAndrew Lunn 	{ "sw_in_filtered",		2, 0x12, STATS_TYPE_PORT, },
1013dfafe449SAndrew Lunn 	{ "sw_out_filtered",		2, 0x13, STATS_TYPE_PORT, },
1014dfafe449SAndrew Lunn 	{ "in_discards",		4, 0x00, STATS_TYPE_BANK1, },
1015dfafe449SAndrew Lunn 	{ "in_filtered",		4, 0x01, STATS_TYPE_BANK1, },
1016dfafe449SAndrew Lunn 	{ "in_accepted",		4, 0x02, STATS_TYPE_BANK1, },
1017dfafe449SAndrew Lunn 	{ "in_bad_accepted",		4, 0x03, STATS_TYPE_BANK1, },
1018dfafe449SAndrew Lunn 	{ "in_good_avb_class_a",	4, 0x04, STATS_TYPE_BANK1, },
1019dfafe449SAndrew Lunn 	{ "in_good_avb_class_b",	4, 0x05, STATS_TYPE_BANK1, },
1020dfafe449SAndrew Lunn 	{ "in_bad_avb_class_a",		4, 0x06, STATS_TYPE_BANK1, },
1021dfafe449SAndrew Lunn 	{ "in_bad_avb_class_b",		4, 0x07, STATS_TYPE_BANK1, },
1022dfafe449SAndrew Lunn 	{ "tcam_counter_0",		4, 0x08, STATS_TYPE_BANK1, },
1023dfafe449SAndrew Lunn 	{ "tcam_counter_1",		4, 0x09, STATS_TYPE_BANK1, },
1024dfafe449SAndrew Lunn 	{ "tcam_counter_2",		4, 0x0a, STATS_TYPE_BANK1, },
1025dfafe449SAndrew Lunn 	{ "tcam_counter_3",		4, 0x0b, STATS_TYPE_BANK1, },
1026dfafe449SAndrew Lunn 	{ "in_da_unknown",		4, 0x0e, STATS_TYPE_BANK1, },
1027dfafe449SAndrew Lunn 	{ "in_management",		4, 0x0f, STATS_TYPE_BANK1, },
1028dfafe449SAndrew Lunn 	{ "out_queue_0",		4, 0x10, STATS_TYPE_BANK1, },
1029dfafe449SAndrew Lunn 	{ "out_queue_1",		4, 0x11, STATS_TYPE_BANK1, },
1030dfafe449SAndrew Lunn 	{ "out_queue_2",		4, 0x12, STATS_TYPE_BANK1, },
1031dfafe449SAndrew Lunn 	{ "out_queue_3",		4, 0x13, STATS_TYPE_BANK1, },
1032dfafe449SAndrew Lunn 	{ "out_queue_4",		4, 0x14, STATS_TYPE_BANK1, },
1033dfafe449SAndrew Lunn 	{ "out_queue_5",		4, 0x15, STATS_TYPE_BANK1, },
1034dfafe449SAndrew Lunn 	{ "out_queue_6",		4, 0x16, STATS_TYPE_BANK1, },
1035dfafe449SAndrew Lunn 	{ "out_queue_7",		4, 0x17, STATS_TYPE_BANK1, },
1036dfafe449SAndrew Lunn 	{ "out_cut_through",		4, 0x18, STATS_TYPE_BANK1, },
1037dfafe449SAndrew Lunn 	{ "out_octets_a",		4, 0x1a, STATS_TYPE_BANK1, },
1038dfafe449SAndrew Lunn 	{ "out_octets_b",		4, 0x1b, STATS_TYPE_BANK1, },
1039dfafe449SAndrew Lunn 	{ "out_management",		4, 0x1f, STATS_TYPE_BANK1, },
1040fad09c73SVivien Didelot };
1041fad09c73SVivien Didelot 
1042fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
1043fad09c73SVivien Didelot 					    struct mv88e6xxx_hw_stat *s,
1044e0d8b615SAndrew Lunn 					    int port, u16 bank1_select,
1045e0d8b615SAndrew Lunn 					    u16 histogram)
1046fad09c73SVivien Didelot {
1047fad09c73SVivien Didelot 	u32 low;
1048fad09c73SVivien Didelot 	u32 high = 0;
1049dfafe449SAndrew Lunn 	u16 reg = 0;
10500e7b9925SAndrew Lunn 	int err;
1051fad09c73SVivien Didelot 	u64 value;
1052fad09c73SVivien Didelot 
1053fad09c73SVivien Didelot 	switch (s->type) {
1054dfafe449SAndrew Lunn 	case STATS_TYPE_PORT:
10550e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
10560e7b9925SAndrew Lunn 		if (err)
10576c3442f5SJisheng Zhang 			return U64_MAX;
1058fad09c73SVivien Didelot 
10590e7b9925SAndrew Lunn 		low = reg;
1060cda9f4aaSAndrew Lunn 		if (s->size == 4) {
10610e7b9925SAndrew Lunn 			err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
10620e7b9925SAndrew Lunn 			if (err)
10636c3442f5SJisheng Zhang 				return U64_MAX;
106484b3fd1fSRasmus Villemoes 			low |= ((u32)reg) << 16;
1065fad09c73SVivien Didelot 		}
1066fad09c73SVivien Didelot 		break;
1067dfafe449SAndrew Lunn 	case STATS_TYPE_BANK1:
1068e0d8b615SAndrew Lunn 		reg = bank1_select;
1069df561f66SGustavo A. R. Silva 		fallthrough;
1070dfafe449SAndrew Lunn 	case STATS_TYPE_BANK0:
1071e0d8b615SAndrew Lunn 		reg |= s->reg | histogram;
10727f9ef3afSAndrew Lunn 		mv88e6xxx_g1_stats_read(chip, reg, &low);
1073cda9f4aaSAndrew Lunn 		if (s->size == 8)
10747f9ef3afSAndrew Lunn 			mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
10759fc3e4dcSGustavo A. R. Silva 		break;
10769fc3e4dcSGustavo A. R. Silva 	default:
10776c3442f5SJisheng Zhang 		return U64_MAX;
1078fad09c73SVivien Didelot 	}
10796e46e2d8SAndrew Lunn 	value = (((u64)high) << 32) | low;
1080fad09c73SVivien Didelot 	return value;
1081fad09c73SVivien Didelot }
1082fad09c73SVivien Didelot 
1083436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
1084dfafe449SAndrew Lunn 				       uint8_t *data, int types)
1085fad09c73SVivien Didelot {
1086fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
1087fad09c73SVivien Didelot 	int i, j;
1088fad09c73SVivien Didelot 
1089fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
1090fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
1091dfafe449SAndrew Lunn 		if (stat->type & types) {
1092fad09c73SVivien Didelot 			memcpy(data + j * ETH_GSTRING_LEN, stat->string,
1093fad09c73SVivien Didelot 			       ETH_GSTRING_LEN);
1094fad09c73SVivien Didelot 			j++;
1095fad09c73SVivien Didelot 		}
1096fad09c73SVivien Didelot 	}
1097436fe17dSAndrew Lunn 
1098436fe17dSAndrew Lunn 	return j;
1099fad09c73SVivien Didelot }
1100fad09c73SVivien Didelot 
1101436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
1102dfafe449SAndrew Lunn 				       uint8_t *data)
1103dfafe449SAndrew Lunn {
1104436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
1105dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_PORT);
1106dfafe449SAndrew Lunn }
1107dfafe449SAndrew Lunn 
11081f71836fSRasmus Villemoes static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip,
11091f71836fSRasmus Villemoes 				       uint8_t *data)
11101f71836fSRasmus Villemoes {
11111f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0);
11121f71836fSRasmus Villemoes }
11131f71836fSRasmus Villemoes 
1114436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
1115dfafe449SAndrew Lunn 				       uint8_t *data)
1116dfafe449SAndrew Lunn {
1117436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
1118dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
1119dfafe449SAndrew Lunn }
1120dfafe449SAndrew Lunn 
112165f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = {
112265f60e45SAndrew Lunn 	"atu_member_violation",
112365f60e45SAndrew Lunn 	"atu_miss_violation",
112465f60e45SAndrew Lunn 	"atu_full_violation",
112565f60e45SAndrew Lunn 	"vtu_member_violation",
112665f60e45SAndrew Lunn 	"vtu_miss_violation",
112765f60e45SAndrew Lunn };
112865f60e45SAndrew Lunn 
112965f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data)
113065f60e45SAndrew Lunn {
113165f60e45SAndrew Lunn 	unsigned int i;
113265f60e45SAndrew Lunn 
113365f60e45SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++)
113465f60e45SAndrew Lunn 		strlcpy(data + i * ETH_GSTRING_LEN,
113565f60e45SAndrew Lunn 			mv88e6xxx_atu_vtu_stats_strings[i],
113665f60e45SAndrew Lunn 			ETH_GSTRING_LEN);
113765f60e45SAndrew Lunn }
113865f60e45SAndrew Lunn 
1139dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
114089f09048SFlorian Fainelli 				  u32 stringset, uint8_t *data)
1141fad09c73SVivien Didelot {
114204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1143436fe17dSAndrew Lunn 	int count = 0;
1144dfafe449SAndrew Lunn 
114589f09048SFlorian Fainelli 	if (stringset != ETH_SS_STATS)
114689f09048SFlorian Fainelli 		return;
114789f09048SFlorian Fainelli 
1148c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1149c6c8cd5eSAndrew Lunn 
1150dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_strings)
1151436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_strings(chip, data);
1152436fe17dSAndrew Lunn 
1153436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_strings) {
1154436fe17dSAndrew Lunn 		data += count * ETH_GSTRING_LEN;
115565f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_strings(chip, port, data);
1156436fe17dSAndrew Lunn 	}
1157c6c8cd5eSAndrew Lunn 
115865f60e45SAndrew Lunn 	data += count * ETH_GSTRING_LEN;
115965f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_strings(data);
116065f60e45SAndrew Lunn 
1161c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1162dfafe449SAndrew Lunn }
1163dfafe449SAndrew Lunn 
1164dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
1165dfafe449SAndrew Lunn 					  int types)
1166dfafe449SAndrew Lunn {
1167fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
1168fad09c73SVivien Didelot 	int i, j;
1169fad09c73SVivien Didelot 
1170fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
1171fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
1172dfafe449SAndrew Lunn 		if (stat->type & types)
1173fad09c73SVivien Didelot 			j++;
1174fad09c73SVivien Didelot 	}
1175fad09c73SVivien Didelot 	return j;
1176fad09c73SVivien Didelot }
1177fad09c73SVivien Didelot 
1178dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
1179dfafe449SAndrew Lunn {
1180dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
1181dfafe449SAndrew Lunn 					      STATS_TYPE_PORT);
1182dfafe449SAndrew Lunn }
1183dfafe449SAndrew Lunn 
11841f71836fSRasmus Villemoes static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip)
11851f71836fSRasmus Villemoes {
11861f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0);
11871f71836fSRasmus Villemoes }
11881f71836fSRasmus Villemoes 
1189dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
1190dfafe449SAndrew Lunn {
1191dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
1192dfafe449SAndrew Lunn 					      STATS_TYPE_BANK1);
1193dfafe449SAndrew Lunn }
1194dfafe449SAndrew Lunn 
119589f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
1196dfafe449SAndrew Lunn {
1197dfafe449SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
1198436fe17dSAndrew Lunn 	int serdes_count = 0;
1199436fe17dSAndrew Lunn 	int count = 0;
1200dfafe449SAndrew Lunn 
120189f09048SFlorian Fainelli 	if (sset != ETH_SS_STATS)
120289f09048SFlorian Fainelli 		return 0;
120389f09048SFlorian Fainelli 
1204c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1205dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_sset_count)
1206436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_sset_count(chip);
1207436fe17dSAndrew Lunn 	if (count < 0)
1208436fe17dSAndrew Lunn 		goto out;
1209436fe17dSAndrew Lunn 
1210436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_sset_count)
1211436fe17dSAndrew Lunn 		serdes_count = chip->info->ops->serdes_get_sset_count(chip,
1212436fe17dSAndrew Lunn 								      port);
121365f60e45SAndrew Lunn 	if (serdes_count < 0) {
1214436fe17dSAndrew Lunn 		count = serdes_count;
121565f60e45SAndrew Lunn 		goto out;
121665f60e45SAndrew Lunn 	}
1217436fe17dSAndrew Lunn 	count += serdes_count;
121865f60e45SAndrew Lunn 	count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings);
121965f60e45SAndrew Lunn 
1220436fe17dSAndrew Lunn out:
1221c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1222dfafe449SAndrew Lunn 
1223436fe17dSAndrew Lunn 	return count;
1224dfafe449SAndrew Lunn }
1225dfafe449SAndrew Lunn 
1226436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1227e0d8b615SAndrew Lunn 				     uint64_t *data, int types,
1228e0d8b615SAndrew Lunn 				     u16 bank1_select, u16 histogram)
1229052f947fSAndrew Lunn {
1230052f947fSAndrew Lunn 	struct mv88e6xxx_hw_stat *stat;
1231052f947fSAndrew Lunn 	int i, j;
1232052f947fSAndrew Lunn 
1233052f947fSAndrew Lunn 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
1234052f947fSAndrew Lunn 		stat = &mv88e6xxx_hw_stats[i];
1235052f947fSAndrew Lunn 		if (stat->type & types) {
1236c9acece0SRasmus Villemoes 			mv88e6xxx_reg_lock(chip);
1237e0d8b615SAndrew Lunn 			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
1238e0d8b615SAndrew Lunn 							      bank1_select,
1239e0d8b615SAndrew Lunn 							      histogram);
1240c9acece0SRasmus Villemoes 			mv88e6xxx_reg_unlock(chip);
1241377cda13SAndrew Lunn 
1242052f947fSAndrew Lunn 			j++;
1243052f947fSAndrew Lunn 		}
1244052f947fSAndrew Lunn 	}
1245436fe17dSAndrew Lunn 	return j;
1246052f947fSAndrew Lunn }
1247052f947fSAndrew Lunn 
1248436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1249052f947fSAndrew Lunn 				     uint64_t *data)
1250052f947fSAndrew Lunn {
1251052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1252e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
125357d1ef38SVivien Didelot 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1254052f947fSAndrew Lunn }
1255052f947fSAndrew Lunn 
12561f71836fSRasmus Villemoes static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
12571f71836fSRasmus Villemoes 				     uint64_t *data)
12581f71836fSRasmus Villemoes {
12591f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0,
12601f71836fSRasmus Villemoes 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
12611f71836fSRasmus Villemoes }
12621f71836fSRasmus Villemoes 
1263436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1264052f947fSAndrew Lunn 				     uint64_t *data)
1265052f947fSAndrew Lunn {
1266052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1267e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
126857d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
126957d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1270e0d8b615SAndrew Lunn }
1271e0d8b615SAndrew Lunn 
1272436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1273e0d8b615SAndrew Lunn 				     uint64_t *data)
1274e0d8b615SAndrew Lunn {
1275e0d8b615SAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1276e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
127757d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
127857d1ef38SVivien Didelot 					 0);
1279052f947fSAndrew Lunn }
1280052f947fSAndrew Lunn 
128165f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
128265f60e45SAndrew Lunn 					uint64_t *data)
128365f60e45SAndrew Lunn {
128465f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_member_violation;
128565f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_miss_violation;
128665f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_full_violation;
128765f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_member_violation;
128865f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_miss_violation;
128965f60e45SAndrew Lunn }
129065f60e45SAndrew Lunn 
1291052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
1292052f947fSAndrew Lunn 				uint64_t *data)
1293052f947fSAndrew Lunn {
1294436fe17dSAndrew Lunn 	int count = 0;
1295436fe17dSAndrew Lunn 
1296052f947fSAndrew Lunn 	if (chip->info->ops->stats_get_stats)
1297436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_stats(chip, port, data);
1298436fe17dSAndrew Lunn 
1299c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1300436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_stats) {
1301436fe17dSAndrew Lunn 		data += count;
130265f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_stats(chip, port, data);
1303436fe17dSAndrew Lunn 	}
130465f60e45SAndrew Lunn 	data += count;
130565f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_stats(chip, port, data);
1306c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1307052f947fSAndrew Lunn }
1308052f947fSAndrew Lunn 
1309fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
1310fad09c73SVivien Didelot 					uint64_t *data)
1311fad09c73SVivien Didelot {
131204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1313fad09c73SVivien Didelot 	int ret;
1314fad09c73SVivien Didelot 
1315c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1316fad09c73SVivien Didelot 
1317a605a0feSAndrew Lunn 	ret = mv88e6xxx_stats_snapshot(chip, port);
1318c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1319377cda13SAndrew Lunn 
1320377cda13SAndrew Lunn 	if (ret < 0)
1321fad09c73SVivien Didelot 		return;
1322052f947fSAndrew Lunn 
1323052f947fSAndrew Lunn 	mv88e6xxx_get_stats(chip, port, data);
1324fad09c73SVivien Didelot 
1325fad09c73SVivien Didelot }
1326fad09c73SVivien Didelot 
1327fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
1328fad09c73SVivien Didelot {
13290d30bbd0SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
13300d30bbd0SAndrew Lunn 	int len;
13310d30bbd0SAndrew Lunn 
13320d30bbd0SAndrew Lunn 	len = 32 * sizeof(u16);
13330d30bbd0SAndrew Lunn 	if (chip->info->ops->serdes_get_regs_len)
13340d30bbd0SAndrew Lunn 		len += chip->info->ops->serdes_get_regs_len(chip, port);
13350d30bbd0SAndrew Lunn 
13360d30bbd0SAndrew Lunn 	return len;
1337fad09c73SVivien Didelot }
1338fad09c73SVivien Didelot 
1339fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
1340fad09c73SVivien Didelot 			       struct ethtool_regs *regs, void *_p)
1341fad09c73SVivien Didelot {
134204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
13430e7b9925SAndrew Lunn 	int err;
13440e7b9925SAndrew Lunn 	u16 reg;
1345fad09c73SVivien Didelot 	u16 *p = _p;
1346fad09c73SVivien Didelot 	int i;
1347fad09c73SVivien Didelot 
1348a5f39326SVivien Didelot 	regs->version = chip->info->prod_num;
1349fad09c73SVivien Didelot 
1350fad09c73SVivien Didelot 	memset(p, 0xff, 32 * sizeof(u16));
1351fad09c73SVivien Didelot 
1352c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1353fad09c73SVivien Didelot 
1354fad09c73SVivien Didelot 	for (i = 0; i < 32; i++) {
1355fad09c73SVivien Didelot 
13560e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, i, &reg);
13570e7b9925SAndrew Lunn 		if (!err)
13580e7b9925SAndrew Lunn 			p[i] = reg;
1359fad09c73SVivien Didelot 	}
1360fad09c73SVivien Didelot 
13610d30bbd0SAndrew Lunn 	if (chip->info->ops->serdes_get_regs)
13620d30bbd0SAndrew Lunn 		chip->info->ops->serdes_get_regs(chip, port, &p[i]);
13630d30bbd0SAndrew Lunn 
1364c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1365fad09c73SVivien Didelot }
1366fad09c73SVivien Didelot 
136708f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
1368fad09c73SVivien Didelot 				 struct ethtool_eee *e)
1369fad09c73SVivien Didelot {
13705480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
13715480db69SVivien Didelot 	return 0;
1372fad09c73SVivien Didelot }
1373fad09c73SVivien Didelot 
137408f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port,
137546587e4aSVivien Didelot 				 struct ethtool_eee *e)
1376fad09c73SVivien Didelot {
13775480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
13785480db69SVivien Didelot 	return 0;
1379fad09c73SVivien Didelot }
1380fad09c73SVivien Didelot 
13819dc8b13eSVivien Didelot /* Mask of the local ports allowed to receive frames from a given fabric port */
1382e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
1383fad09c73SVivien Didelot {
13849dc8b13eSVivien Didelot 	struct dsa_switch *ds = chip->ds;
13859dc8b13eSVivien Didelot 	struct dsa_switch_tree *dst = ds->dst;
138665144067SVladimir Oltean 	struct dsa_port *dp, *other_dp;
13879dc8b13eSVivien Didelot 	bool found = false;
1388e5887a2aSVivien Didelot 	u16 pvlan;
1389fad09c73SVivien Didelot 
1390ce5df689SVladimir Oltean 	/* dev is a physical switch */
1391ce5df689SVladimir Oltean 	if (dev <= dst->last_switch) {
13929dc8b13eSVivien Didelot 		list_for_each_entry(dp, &dst->ports, list) {
13939dc8b13eSVivien Didelot 			if (dp->ds->index == dev && dp->index == port) {
1394ce5df689SVladimir Oltean 				/* dp might be a DSA link or a user port, so it
139565144067SVladimir Oltean 				 * might or might not have a bridge.
139665144067SVladimir Oltean 				 * Use the "found" variable for both cases.
1397ce5df689SVladimir Oltean 				 */
1398ce5df689SVladimir Oltean 				found = true;
1399ce5df689SVladimir Oltean 				break;
1400ce5df689SVladimir Oltean 			}
1401ce5df689SVladimir Oltean 		}
1402ce5df689SVladimir Oltean 	/* dev is a virtual bridge */
1403ce5df689SVladimir Oltean 	} else {
1404ce5df689SVladimir Oltean 		list_for_each_entry(dp, &dst->ports, list) {
140541fb0cf1SVladimir Oltean 			unsigned int bridge_num = dsa_port_bridge_num_get(dp);
140641fb0cf1SVladimir Oltean 
140741fb0cf1SVladimir Oltean 			if (!bridge_num)
1408ce5df689SVladimir Oltean 				continue;
1409ce5df689SVladimir Oltean 
141041fb0cf1SVladimir Oltean 			if (bridge_num + dst->last_switch != dev)
1411ce5df689SVladimir Oltean 				continue;
1412ce5df689SVladimir Oltean 
14139dc8b13eSVivien Didelot 			found = true;
14149dc8b13eSVivien Didelot 			break;
14159dc8b13eSVivien Didelot 		}
14169dc8b13eSVivien Didelot 	}
1417fad09c73SVivien Didelot 
1418ce5df689SVladimir Oltean 	/* Prevent frames from unknown switch or virtual bridge */
14199dc8b13eSVivien Didelot 	if (!found)
1420e5887a2aSVivien Didelot 		return 0;
1421e5887a2aSVivien Didelot 
1422e5887a2aSVivien Didelot 	/* Frames from DSA links and CPU ports can egress any local port */
14239dc8b13eSVivien Didelot 	if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA)
1424e5887a2aSVivien Didelot 		return mv88e6xxx_port_mask(chip);
1425e5887a2aSVivien Didelot 
1426e5887a2aSVivien Didelot 	pvlan = 0;
1427e5887a2aSVivien Didelot 
14287af4a361STobias Waldekranz 	/* Frames from standalone user ports can only egress on the
14297af4a361STobias Waldekranz 	 * upstream port.
14307af4a361STobias Waldekranz 	 */
14317af4a361STobias Waldekranz 	if (!dsa_port_bridge_dev_get(dp))
14327af4a361STobias Waldekranz 		return BIT(dsa_switch_upstream_port(ds));
14337af4a361STobias Waldekranz 
14347af4a361STobias Waldekranz 	/* Frames from bridged user ports can egress any local DSA
14357af4a361STobias Waldekranz 	 * links and CPU ports, as well as any local member of their
14367af4a361STobias Waldekranz 	 * bridge group.
1437e5887a2aSVivien Didelot 	 */
143865144067SVladimir Oltean 	dsa_switch_for_each_port(other_dp, ds)
143965144067SVladimir Oltean 		if (other_dp->type == DSA_PORT_TYPE_CPU ||
144065144067SVladimir Oltean 		    other_dp->type == DSA_PORT_TYPE_DSA ||
144141fb0cf1SVladimir Oltean 		    dsa_port_bridge_same(dp, other_dp))
144265144067SVladimir Oltean 			pvlan |= BIT(other_dp->index);
1443e5887a2aSVivien Didelot 
1444e5887a2aSVivien Didelot 	return pvlan;
1445fad09c73SVivien Didelot }
1446e5887a2aSVivien Didelot 
1447240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port)
1448e5887a2aSVivien Didelot {
1449e5887a2aSVivien Didelot 	u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port);
1450fad09c73SVivien Didelot 
1451fad09c73SVivien Didelot 	/* prevent frames from going back out of the port they came in on */
1452fad09c73SVivien Didelot 	output_ports &= ~BIT(port);
1453fad09c73SVivien Didelot 
14545a7921f4SVivien Didelot 	return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
1455fad09c73SVivien Didelot }
1456fad09c73SVivien Didelot 
1457fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
1458fad09c73SVivien Didelot 					 u8 state)
1459fad09c73SVivien Didelot {
146004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1461fad09c73SVivien Didelot 	int err;
1462fad09c73SVivien Didelot 
1463c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1464f894c29cSVivien Didelot 	err = mv88e6xxx_port_set_state(chip, port, state);
1465c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1466fad09c73SVivien Didelot 
1467fad09c73SVivien Didelot 	if (err)
1468774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to update state\n", port);
1469fad09c73SVivien Didelot }
1470fad09c73SVivien Didelot 
147193e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip)
147293e18d61SVivien Didelot {
147393e18d61SVivien Didelot 	int err;
147493e18d61SVivien Didelot 
147593e18d61SVivien Didelot 	if (chip->info->ops->ieee_pri_map) {
147693e18d61SVivien Didelot 		err = chip->info->ops->ieee_pri_map(chip);
147793e18d61SVivien Didelot 		if (err)
147893e18d61SVivien Didelot 			return err;
147993e18d61SVivien Didelot 	}
148093e18d61SVivien Didelot 
148193e18d61SVivien Didelot 	if (chip->info->ops->ip_pri_map) {
148293e18d61SVivien Didelot 		err = chip->info->ops->ip_pri_map(chip);
148393e18d61SVivien Didelot 		if (err)
148493e18d61SVivien Didelot 			return err;
148593e18d61SVivien Didelot 	}
148693e18d61SVivien Didelot 
148793e18d61SVivien Didelot 	return 0;
148893e18d61SVivien Didelot }
148993e18d61SVivien Didelot 
1490c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
1491c7f047b6SVivien Didelot {
1492c5f51765SVivien Didelot 	struct dsa_switch *ds = chip->ds;
1493c7f047b6SVivien Didelot 	int target, port;
1494c7f047b6SVivien Didelot 	int err;
1495c7f047b6SVivien Didelot 
1496c7f047b6SVivien Didelot 	if (!chip->info->global2_addr)
1497c7f047b6SVivien Didelot 		return 0;
1498c7f047b6SVivien Didelot 
1499c7f047b6SVivien Didelot 	/* Initialize the routing port to the 32 possible target devices */
1500c7f047b6SVivien Didelot 	for (target = 0; target < 32; target++) {
1501c5f51765SVivien Didelot 		port = dsa_routing_port(ds, target);
1502c5f51765SVivien Didelot 		if (port == ds->num_ports)
1503c7f047b6SVivien Didelot 			port = 0x1f;
1504c7f047b6SVivien Didelot 
1505c7f047b6SVivien Didelot 		err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
1506c7f047b6SVivien Didelot 		if (err)
1507c7f047b6SVivien Didelot 			return err;
1508c7f047b6SVivien Didelot 	}
1509c7f047b6SVivien Didelot 
151002317e68SVivien Didelot 	if (chip->info->ops->set_cascade_port) {
151102317e68SVivien Didelot 		port = MV88E6XXX_CASCADE_PORT_MULTIPLE;
151202317e68SVivien Didelot 		err = chip->info->ops->set_cascade_port(chip, port);
151302317e68SVivien Didelot 		if (err)
151402317e68SVivien Didelot 			return err;
151502317e68SVivien Didelot 	}
151602317e68SVivien Didelot 
151723c98919SVivien Didelot 	err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index);
151823c98919SVivien Didelot 	if (err)
151923c98919SVivien Didelot 		return err;
152023c98919SVivien Didelot 
1521c7f047b6SVivien Didelot 	return 0;
1522c7f047b6SVivien Didelot }
1523c7f047b6SVivien Didelot 
1524b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip)
1525b28f872dSVivien Didelot {
1526b28f872dSVivien Didelot 	/* Clear all trunk masks and mapping */
1527b28f872dSVivien Didelot 	if (chip->info->global2_addr)
1528b28f872dSVivien Didelot 		return mv88e6xxx_g2_trunk_clear(chip);
1529b28f872dSVivien Didelot 
1530b28f872dSVivien Didelot 	return 0;
1531b28f872dSVivien Didelot }
1532b28f872dSVivien Didelot 
15339e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
15349e5baf9bSVivien Didelot {
15359e5baf9bSVivien Didelot 	if (chip->info->ops->rmu_disable)
15369e5baf9bSVivien Didelot 		return chip->info->ops->rmu_disable(chip);
15379e5baf9bSVivien Didelot 
15389e5baf9bSVivien Didelot 	return 0;
15399e5baf9bSVivien Didelot }
15409e5baf9bSVivien Didelot 
15419e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
15429e907d73SVivien Didelot {
15439e907d73SVivien Didelot 	if (chip->info->ops->pot_clear)
15449e907d73SVivien Didelot 		return chip->info->ops->pot_clear(chip);
15459e907d73SVivien Didelot 
15469e907d73SVivien Didelot 	return 0;
15479e907d73SVivien Didelot }
15489e907d73SVivien Didelot 
154951c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip)
155051c901a7SVivien Didelot {
155151c901a7SVivien Didelot 	if (chip->info->ops->mgmt_rsvd2cpu)
155251c901a7SVivien Didelot 		return chip->info->ops->mgmt_rsvd2cpu(chip);
155351c901a7SVivien Didelot 
155451c901a7SVivien Didelot 	return 0;
155551c901a7SVivien Didelot }
155651c901a7SVivien Didelot 
1557a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
1558a2ac29d2SVivien Didelot {
1559c3a7d4adSVivien Didelot 	int err;
1560c3a7d4adSVivien Didelot 
1561daefc943SVivien Didelot 	err = mv88e6xxx_g1_atu_flush(chip, 0, true);
1562daefc943SVivien Didelot 	if (err)
1563daefc943SVivien Didelot 		return err;
1564daefc943SVivien Didelot 
156549506a9bSRasmus Villemoes 	/* The chips that have a "learn2all" bit in Global1, ATU
156649506a9bSRasmus Villemoes 	 * Control are precisely those whose port registers have a
156749506a9bSRasmus Villemoes 	 * Message Port bit in Port Control 1 and hence implement
156849506a9bSRasmus Villemoes 	 * ->port_setup_message_port.
156949506a9bSRasmus Villemoes 	 */
157049506a9bSRasmus Villemoes 	if (chip->info->ops->port_setup_message_port) {
1571c3a7d4adSVivien Didelot 		err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
1572c3a7d4adSVivien Didelot 		if (err)
1573c3a7d4adSVivien Didelot 			return err;
157449506a9bSRasmus Villemoes 	}
1575c3a7d4adSVivien Didelot 
1576a2ac29d2SVivien Didelot 	return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
1577a2ac29d2SVivien Didelot }
1578a2ac29d2SVivien Didelot 
1579cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip)
1580cd8da8bbSVivien Didelot {
1581cd8da8bbSVivien Didelot 	int port;
1582cd8da8bbSVivien Didelot 	int err;
1583cd8da8bbSVivien Didelot 
1584cd8da8bbSVivien Didelot 	if (!chip->info->ops->irl_init_all)
1585cd8da8bbSVivien Didelot 		return 0;
1586cd8da8bbSVivien Didelot 
1587cd8da8bbSVivien Didelot 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
1588cd8da8bbSVivien Didelot 		/* Disable ingress rate limiting by resetting all per port
1589cd8da8bbSVivien Didelot 		 * ingress rate limit resources to their initial state.
1590cd8da8bbSVivien Didelot 		 */
1591cd8da8bbSVivien Didelot 		err = chip->info->ops->irl_init_all(chip, port);
1592cd8da8bbSVivien Didelot 		if (err)
1593cd8da8bbSVivien Didelot 			return err;
1594cd8da8bbSVivien Didelot 	}
1595cd8da8bbSVivien Didelot 
1596cd8da8bbSVivien Didelot 	return 0;
1597cd8da8bbSVivien Didelot }
1598cd8da8bbSVivien Didelot 
159904a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip)
160004a69a17SVivien Didelot {
160104a69a17SVivien Didelot 	if (chip->info->ops->set_switch_mac) {
160204a69a17SVivien Didelot 		u8 addr[ETH_ALEN];
160304a69a17SVivien Didelot 
160404a69a17SVivien Didelot 		eth_random_addr(addr);
160504a69a17SVivien Didelot 
160604a69a17SVivien Didelot 		return chip->info->ops->set_switch_mac(chip, addr);
160704a69a17SVivien Didelot 	}
160804a69a17SVivien Didelot 
160904a69a17SVivien Didelot 	return 0;
161004a69a17SVivien Didelot }
161104a69a17SVivien Didelot 
161217a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
161317a1594eSVivien Didelot {
161457e661aaSTobias Waldekranz 	struct dsa_switch_tree *dst = chip->ds->dst;
161557e661aaSTobias Waldekranz 	struct dsa_switch *ds;
161657e661aaSTobias Waldekranz 	struct dsa_port *dp;
161717a1594eSVivien Didelot 	u16 pvlan = 0;
161817a1594eSVivien Didelot 
161917a1594eSVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
1620d14939beSVivien Didelot 		return 0;
162117a1594eSVivien Didelot 
162217a1594eSVivien Didelot 	/* Skip the local source device, which uses in-chip port VLAN */
162357e661aaSTobias Waldekranz 	if (dev != chip->ds->index) {
1624aec5ac88SVivien Didelot 		pvlan = mv88e6xxx_port_vlan(chip, dev, port);
162517a1594eSVivien Didelot 
162657e661aaSTobias Waldekranz 		ds = dsa_switch_find(dst->index, dev);
162757e661aaSTobias Waldekranz 		dp = ds ? dsa_to_port(ds, port) : NULL;
1628dedd6a00SVladimir Oltean 		if (dp && dp->lag) {
162957e661aaSTobias Waldekranz 			/* As the PVT is used to limit flooding of
163057e661aaSTobias Waldekranz 			 * FORWARD frames, which use the LAG ID as the
163157e661aaSTobias Waldekranz 			 * source port, we must translate dev/port to
163257e661aaSTobias Waldekranz 			 * the special "LAG device" in the PVT, using
16333d4a0a2aSVladimir Oltean 			 * the LAG ID (one-based) as the port number
16343d4a0a2aSVladimir Oltean 			 * (zero-based).
163557e661aaSTobias Waldekranz 			 */
163678e70dbcSTobias Waldekranz 			dev = MV88E6XXX_G2_PVT_ADDR_DEV_TRUNK;
1637dedd6a00SVladimir Oltean 			port = dsa_port_lag_id_get(dp) - 1;
163857e661aaSTobias Waldekranz 		}
163957e661aaSTobias Waldekranz 	}
164057e661aaSTobias Waldekranz 
164117a1594eSVivien Didelot 	return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
164217a1594eSVivien Didelot }
164317a1594eSVivien Didelot 
164481228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
164581228996SVivien Didelot {
164617a1594eSVivien Didelot 	int dev, port;
164717a1594eSVivien Didelot 	int err;
164817a1594eSVivien Didelot 
164981228996SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
165081228996SVivien Didelot 		return 0;
165181228996SVivien Didelot 
165281228996SVivien Didelot 	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
165381228996SVivien Didelot 	 * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
165481228996SVivien Didelot 	 */
165517a1594eSVivien Didelot 	err = mv88e6xxx_g2_misc_4_bit_port(chip);
165617a1594eSVivien Didelot 	if (err)
165717a1594eSVivien Didelot 		return err;
165817a1594eSVivien Didelot 
165917a1594eSVivien Didelot 	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) {
166017a1594eSVivien Didelot 		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) {
166117a1594eSVivien Didelot 			err = mv88e6xxx_pvt_map(chip, dev, port);
166217a1594eSVivien Didelot 			if (err)
166317a1594eSVivien Didelot 				return err;
166417a1594eSVivien Didelot 		}
166517a1594eSVivien Didelot 	}
166617a1594eSVivien Didelot 
166717a1594eSVivien Didelot 	return 0;
166881228996SVivien Didelot }
166981228996SVivien Didelot 
1670acaf4d2eSTobias Waldekranz static int mv88e6xxx_port_fast_age_fid(struct mv88e6xxx_chip *chip, int port,
1671acaf4d2eSTobias Waldekranz 				       u16 fid)
1672acaf4d2eSTobias Waldekranz {
1673acaf4d2eSTobias Waldekranz 	if (dsa_to_port(chip->ds, port)->lag)
1674acaf4d2eSTobias Waldekranz 		/* Hardware is incapable of fast-aging a LAG through a
1675acaf4d2eSTobias Waldekranz 		 * regular ATU move operation. Until we have something
1676acaf4d2eSTobias Waldekranz 		 * more fancy in place this is a no-op.
1677acaf4d2eSTobias Waldekranz 		 */
1678acaf4d2eSTobias Waldekranz 		return -EOPNOTSUPP;
1679acaf4d2eSTobias Waldekranz 
1680acaf4d2eSTobias Waldekranz 	return mv88e6xxx_g1_atu_remove(chip, fid, port, false);
1681acaf4d2eSTobias Waldekranz }
1682acaf4d2eSTobias Waldekranz 
1683749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
1684749efcb8SVivien Didelot {
1685749efcb8SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1686749efcb8SVivien Didelot 	int err;
1687749efcb8SVivien Didelot 
1688c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1689acaf4d2eSTobias Waldekranz 	err = mv88e6xxx_port_fast_age_fid(chip, port, 0);
1690c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1691749efcb8SVivien Didelot 
1692749efcb8SVivien Didelot 	if (err)
1693acaf4d2eSTobias Waldekranz 		dev_err(chip->ds->dev, "p%d: failed to flush ATU: %d\n",
1694acaf4d2eSTobias Waldekranz 			port, err);
1695749efcb8SVivien Didelot }
1696749efcb8SVivien Didelot 
1697b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)
1698b486d7c9SVivien Didelot {
1699e545f865STobias Waldekranz 	if (!mv88e6xxx_max_vid(chip))
1700b486d7c9SVivien Didelot 		return 0;
1701b486d7c9SVivien Didelot 
1702b486d7c9SVivien Didelot 	return mv88e6xxx_g1_vtu_flush(chip);
1703b486d7c9SVivien Didelot }
1704b486d7c9SVivien Didelot 
170534065c58STobias Waldekranz static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
1706f1394b78SVivien Didelot 			     struct mv88e6xxx_vtu_entry *entry)
1707f1394b78SVivien Didelot {
170834065c58STobias Waldekranz 	int err;
170934065c58STobias Waldekranz 
1710f1394b78SVivien Didelot 	if (!chip->info->ops->vtu_getnext)
1711f1394b78SVivien Didelot 		return -EOPNOTSUPP;
1712f1394b78SVivien Didelot 
171334065c58STobias Waldekranz 	entry->vid = vid ? vid - 1 : mv88e6xxx_max_vid(chip);
171434065c58STobias Waldekranz 	entry->valid = false;
171534065c58STobias Waldekranz 
171634065c58STobias Waldekranz 	err = chip->info->ops->vtu_getnext(chip, entry);
171734065c58STobias Waldekranz 
171834065c58STobias Waldekranz 	if (entry->vid != vid)
171934065c58STobias Waldekranz 		entry->valid = false;
172034065c58STobias Waldekranz 
172134065c58STobias Waldekranz 	return err;
1722f1394b78SVivien Didelot }
1723f1394b78SVivien Didelot 
1724d89ef4b8STobias Waldekranz static int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
1725d89ef4b8STobias Waldekranz 			      int (*cb)(struct mv88e6xxx_chip *chip,
1726d89ef4b8STobias Waldekranz 					const struct mv88e6xxx_vtu_entry *entry,
1727d89ef4b8STobias Waldekranz 					void *priv),
1728d89ef4b8STobias Waldekranz 			      void *priv)
1729d89ef4b8STobias Waldekranz {
1730d89ef4b8STobias Waldekranz 	struct mv88e6xxx_vtu_entry entry = {
1731d89ef4b8STobias Waldekranz 		.vid = mv88e6xxx_max_vid(chip),
1732d89ef4b8STobias Waldekranz 		.valid = false,
1733d89ef4b8STobias Waldekranz 	};
1734d89ef4b8STobias Waldekranz 	int err;
1735d89ef4b8STobias Waldekranz 
1736d89ef4b8STobias Waldekranz 	if (!chip->info->ops->vtu_getnext)
1737d89ef4b8STobias Waldekranz 		return -EOPNOTSUPP;
1738d89ef4b8STobias Waldekranz 
1739d89ef4b8STobias Waldekranz 	do {
1740d89ef4b8STobias Waldekranz 		err = chip->info->ops->vtu_getnext(chip, &entry);
1741d89ef4b8STobias Waldekranz 		if (err)
1742d89ef4b8STobias Waldekranz 			return err;
1743d89ef4b8STobias Waldekranz 
1744d89ef4b8STobias Waldekranz 		if (!entry.valid)
1745d89ef4b8STobias Waldekranz 			break;
1746d89ef4b8STobias Waldekranz 
1747d89ef4b8STobias Waldekranz 		err = cb(chip, &entry, priv);
1748d89ef4b8STobias Waldekranz 		if (err)
1749d89ef4b8STobias Waldekranz 			return err;
1750d89ef4b8STobias Waldekranz 	} while (entry.vid < mv88e6xxx_max_vid(chip));
1751d89ef4b8STobias Waldekranz 
1752d89ef4b8STobias Waldekranz 	return 0;
1753d89ef4b8STobias Waldekranz }
1754d89ef4b8STobias Waldekranz 
17550ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
17560ad5daf6SVivien Didelot 				   struct mv88e6xxx_vtu_entry *entry)
17570ad5daf6SVivien Didelot {
17580ad5daf6SVivien Didelot 	if (!chip->info->ops->vtu_loadpurge)
17590ad5daf6SVivien Didelot 		return -EOPNOTSUPP;
17600ad5daf6SVivien Didelot 
17610ad5daf6SVivien Didelot 	return chip->info->ops->vtu_loadpurge(chip, entry);
17620ad5daf6SVivien Didelot }
17630ad5daf6SVivien Didelot 
1764d89ef4b8STobias Waldekranz static int mv88e6xxx_fid_map_vlan(struct mv88e6xxx_chip *chip,
1765d89ef4b8STobias Waldekranz 				  const struct mv88e6xxx_vtu_entry *entry,
1766d89ef4b8STobias Waldekranz 				  void *_fid_bitmap)
1767d89ef4b8STobias Waldekranz {
1768d89ef4b8STobias Waldekranz 	unsigned long *fid_bitmap = _fid_bitmap;
1769d89ef4b8STobias Waldekranz 
1770d89ef4b8STobias Waldekranz 	set_bit(entry->fid, fid_bitmap);
1771d89ef4b8STobias Waldekranz 	return 0;
1772d89ef4b8STobias Waldekranz }
1773d89ef4b8STobias Waldekranz 
177490b6dbdfSAndrew Lunn int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *fid_bitmap)
1775fad09c73SVivien Didelot {
1776fad09c73SVivien Didelot 	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
1777fad09c73SVivien Didelot 
1778d352b20fSTobias Waldekranz 	/* Every FID has an associated VID, so walking the VTU
1779d352b20fSTobias Waldekranz 	 * will discover the full set of FIDs in use.
1780d352b20fSTobias Waldekranz 	 */
1781d89ef4b8STobias Waldekranz 	return mv88e6xxx_vtu_walk(chip, mv88e6xxx_fid_map_vlan, fid_bitmap);
178290b6dbdfSAndrew Lunn }
178390b6dbdfSAndrew Lunn 
178490b6dbdfSAndrew Lunn static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
178590b6dbdfSAndrew Lunn {
178690b6dbdfSAndrew Lunn 	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
178790b6dbdfSAndrew Lunn 	int err;
178890b6dbdfSAndrew Lunn 
178990b6dbdfSAndrew Lunn 	err = mv88e6xxx_fid_map(chip, fid_bitmap);
179090b6dbdfSAndrew Lunn 	if (err)
179190b6dbdfSAndrew Lunn 		return err;
179290b6dbdfSAndrew Lunn 
1793d352b20fSTobias Waldekranz 	*fid = find_first_zero_bit(fid_bitmap, MV88E6XXX_N_FID);
1794fad09c73SVivien Didelot 	if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
1795fad09c73SVivien Didelot 		return -ENOSPC;
1796fad09c73SVivien Didelot 
1797fad09c73SVivien Didelot 	/* Clear the database */
1798daefc943SVivien Didelot 	return mv88e6xxx_g1_atu_flush(chip, *fid, true);
1799fad09c73SVivien Didelot }
1800fad09c73SVivien Didelot 
180149c98c1dSTobias Waldekranz static int mv88e6xxx_stu_loadpurge(struct mv88e6xxx_chip *chip,
180249c98c1dSTobias Waldekranz 				   struct mv88e6xxx_stu_entry *entry)
180349c98c1dSTobias Waldekranz {
180449c98c1dSTobias Waldekranz 	if (!chip->info->ops->stu_loadpurge)
180549c98c1dSTobias Waldekranz 		return -EOPNOTSUPP;
180649c98c1dSTobias Waldekranz 
180749c98c1dSTobias Waldekranz 	return chip->info->ops->stu_loadpurge(chip, entry);
180849c98c1dSTobias Waldekranz }
180949c98c1dSTobias Waldekranz 
181049c98c1dSTobias Waldekranz static int mv88e6xxx_stu_setup(struct mv88e6xxx_chip *chip)
181149c98c1dSTobias Waldekranz {
181249c98c1dSTobias Waldekranz 	struct mv88e6xxx_stu_entry stu = {
181349c98c1dSTobias Waldekranz 		.valid = true,
181449c98c1dSTobias Waldekranz 		.sid = 0
181549c98c1dSTobias Waldekranz 	};
181649c98c1dSTobias Waldekranz 
181749c98c1dSTobias Waldekranz 	if (!mv88e6xxx_has_stu(chip))
181849c98c1dSTobias Waldekranz 		return 0;
181949c98c1dSTobias Waldekranz 
182049c98c1dSTobias Waldekranz 	/* Make sure that SID 0 is always valid. This is used by VTU
182149c98c1dSTobias Waldekranz 	 * entries that do not make use of the STU, e.g. when creating
182249c98c1dSTobias Waldekranz 	 * a VLAN upper on a port that is also part of a VLAN
182349c98c1dSTobias Waldekranz 	 * filtering bridge.
182449c98c1dSTobias Waldekranz 	 */
182549c98c1dSTobias Waldekranz 	return mv88e6xxx_stu_loadpurge(chip, &stu);
182649c98c1dSTobias Waldekranz }
182749c98c1dSTobias Waldekranz 
1828acaf4d2eSTobias Waldekranz static int mv88e6xxx_sid_get(struct mv88e6xxx_chip *chip, u8 *sid)
1829acaf4d2eSTobias Waldekranz {
1830acaf4d2eSTobias Waldekranz 	DECLARE_BITMAP(busy, MV88E6XXX_N_SID) = { 0 };
1831acaf4d2eSTobias Waldekranz 	struct mv88e6xxx_mst *mst;
1832acaf4d2eSTobias Waldekranz 
1833acaf4d2eSTobias Waldekranz 	__set_bit(0, busy);
1834acaf4d2eSTobias Waldekranz 
1835acaf4d2eSTobias Waldekranz 	list_for_each_entry(mst, &chip->msts, node)
1836acaf4d2eSTobias Waldekranz 		__set_bit(mst->stu.sid, busy);
1837acaf4d2eSTobias Waldekranz 
1838acaf4d2eSTobias Waldekranz 	*sid = find_first_zero_bit(busy, MV88E6XXX_N_SID);
1839acaf4d2eSTobias Waldekranz 
1840acaf4d2eSTobias Waldekranz 	return (*sid >= mv88e6xxx_max_sid(chip)) ? -ENOSPC : 0;
1841acaf4d2eSTobias Waldekranz }
1842acaf4d2eSTobias Waldekranz 
1843acaf4d2eSTobias Waldekranz static int mv88e6xxx_mst_put(struct mv88e6xxx_chip *chip, u8 sid)
1844acaf4d2eSTobias Waldekranz {
1845acaf4d2eSTobias Waldekranz 	struct mv88e6xxx_mst *mst, *tmp;
1846acaf4d2eSTobias Waldekranz 	int err;
1847acaf4d2eSTobias Waldekranz 
1848acaf4d2eSTobias Waldekranz 	if (!sid)
1849acaf4d2eSTobias Waldekranz 		return 0;
1850acaf4d2eSTobias Waldekranz 
1851acaf4d2eSTobias Waldekranz 	list_for_each_entry_safe(mst, tmp, &chip->msts, node) {
1852acaf4d2eSTobias Waldekranz 		if (mst->stu.sid != sid)
1853acaf4d2eSTobias Waldekranz 			continue;
1854acaf4d2eSTobias Waldekranz 
1855acaf4d2eSTobias Waldekranz 		if (!refcount_dec_and_test(&mst->refcnt))
1856acaf4d2eSTobias Waldekranz 			return 0;
1857acaf4d2eSTobias Waldekranz 
1858acaf4d2eSTobias Waldekranz 		mst->stu.valid = false;
1859acaf4d2eSTobias Waldekranz 		err = mv88e6xxx_stu_loadpurge(chip, &mst->stu);
1860acaf4d2eSTobias Waldekranz 		if (err) {
1861acaf4d2eSTobias Waldekranz 			refcount_set(&mst->refcnt, 1);
1862acaf4d2eSTobias Waldekranz 			return err;
1863acaf4d2eSTobias Waldekranz 		}
1864acaf4d2eSTobias Waldekranz 
1865acaf4d2eSTobias Waldekranz 		list_del(&mst->node);
1866acaf4d2eSTobias Waldekranz 		kfree(mst);
1867acaf4d2eSTobias Waldekranz 		return 0;
1868acaf4d2eSTobias Waldekranz 	}
1869acaf4d2eSTobias Waldekranz 
1870acaf4d2eSTobias Waldekranz 	return -ENOENT;
1871acaf4d2eSTobias Waldekranz }
1872acaf4d2eSTobias Waldekranz 
1873acaf4d2eSTobias Waldekranz static int mv88e6xxx_mst_get(struct mv88e6xxx_chip *chip, struct net_device *br,
1874acaf4d2eSTobias Waldekranz 			     u16 msti, u8 *sid)
1875acaf4d2eSTobias Waldekranz {
1876acaf4d2eSTobias Waldekranz 	struct mv88e6xxx_mst *mst;
1877acaf4d2eSTobias Waldekranz 	int err, i;
1878acaf4d2eSTobias Waldekranz 
1879acaf4d2eSTobias Waldekranz 	if (!mv88e6xxx_has_stu(chip)) {
1880acaf4d2eSTobias Waldekranz 		err = -EOPNOTSUPP;
1881acaf4d2eSTobias Waldekranz 		goto err;
1882acaf4d2eSTobias Waldekranz 	}
1883acaf4d2eSTobias Waldekranz 
1884acaf4d2eSTobias Waldekranz 	if (!msti) {
1885acaf4d2eSTobias Waldekranz 		*sid = 0;
1886acaf4d2eSTobias Waldekranz 		return 0;
1887acaf4d2eSTobias Waldekranz 	}
1888acaf4d2eSTobias Waldekranz 
1889acaf4d2eSTobias Waldekranz 	list_for_each_entry(mst, &chip->msts, node) {
1890acaf4d2eSTobias Waldekranz 		if (mst->br == br && mst->msti == msti) {
1891acaf4d2eSTobias Waldekranz 			refcount_inc(&mst->refcnt);
1892acaf4d2eSTobias Waldekranz 			*sid = mst->stu.sid;
1893acaf4d2eSTobias Waldekranz 			return 0;
1894acaf4d2eSTobias Waldekranz 		}
1895acaf4d2eSTobias Waldekranz 	}
1896acaf4d2eSTobias Waldekranz 
1897acaf4d2eSTobias Waldekranz 	err = mv88e6xxx_sid_get(chip, sid);
1898acaf4d2eSTobias Waldekranz 	if (err)
1899acaf4d2eSTobias Waldekranz 		goto err;
1900acaf4d2eSTobias Waldekranz 
1901acaf4d2eSTobias Waldekranz 	mst = kzalloc(sizeof(*mst), GFP_KERNEL);
1902acaf4d2eSTobias Waldekranz 	if (!mst) {
1903acaf4d2eSTobias Waldekranz 		err = -ENOMEM;
1904acaf4d2eSTobias Waldekranz 		goto err;
1905acaf4d2eSTobias Waldekranz 	}
1906acaf4d2eSTobias Waldekranz 
1907acaf4d2eSTobias Waldekranz 	INIT_LIST_HEAD(&mst->node);
1908acaf4d2eSTobias Waldekranz 	refcount_set(&mst->refcnt, 1);
1909acaf4d2eSTobias Waldekranz 	mst->br = br;
1910acaf4d2eSTobias Waldekranz 	mst->msti = msti;
1911acaf4d2eSTobias Waldekranz 	mst->stu.valid = true;
1912acaf4d2eSTobias Waldekranz 	mst->stu.sid = *sid;
1913acaf4d2eSTobias Waldekranz 
1914acaf4d2eSTobias Waldekranz 	/* The bridge starts out all ports in the disabled state. But
1915acaf4d2eSTobias Waldekranz 	 * a STU state of disabled means to go by the port-global
1916acaf4d2eSTobias Waldekranz 	 * state. So we set all user port's initial state to blocking,
1917acaf4d2eSTobias Waldekranz 	 * to match the bridge's behavior.
1918acaf4d2eSTobias Waldekranz 	 */
1919acaf4d2eSTobias Waldekranz 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
1920acaf4d2eSTobias Waldekranz 		mst->stu.state[i] = dsa_is_user_port(chip->ds, i) ?
1921acaf4d2eSTobias Waldekranz 			MV88E6XXX_PORT_CTL0_STATE_BLOCKING :
1922acaf4d2eSTobias Waldekranz 			MV88E6XXX_PORT_CTL0_STATE_DISABLED;
1923acaf4d2eSTobias Waldekranz 
1924acaf4d2eSTobias Waldekranz 	err = mv88e6xxx_stu_loadpurge(chip, &mst->stu);
1925acaf4d2eSTobias Waldekranz 	if (err)
1926acaf4d2eSTobias Waldekranz 		goto err_free;
1927acaf4d2eSTobias Waldekranz 
1928acaf4d2eSTobias Waldekranz 	list_add_tail(&mst->node, &chip->msts);
1929acaf4d2eSTobias Waldekranz 	return 0;
1930acaf4d2eSTobias Waldekranz 
1931acaf4d2eSTobias Waldekranz err_free:
1932acaf4d2eSTobias Waldekranz 	kfree(mst);
1933acaf4d2eSTobias Waldekranz err:
1934acaf4d2eSTobias Waldekranz 	return err;
1935acaf4d2eSTobias Waldekranz }
1936acaf4d2eSTobias Waldekranz 
1937acaf4d2eSTobias Waldekranz static int mv88e6xxx_port_mst_state_set(struct dsa_switch *ds, int port,
1938acaf4d2eSTobias Waldekranz 					const struct switchdev_mst_state *st)
1939acaf4d2eSTobias Waldekranz {
1940acaf4d2eSTobias Waldekranz 	struct dsa_port *dp = dsa_to_port(ds, port);
1941acaf4d2eSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
1942acaf4d2eSTobias Waldekranz 	struct mv88e6xxx_mst *mst;
1943acaf4d2eSTobias Waldekranz 	u8 state;
1944acaf4d2eSTobias Waldekranz 	int err;
1945acaf4d2eSTobias Waldekranz 
1946acaf4d2eSTobias Waldekranz 	if (!mv88e6xxx_has_stu(chip))
1947acaf4d2eSTobias Waldekranz 		return -EOPNOTSUPP;
1948acaf4d2eSTobias Waldekranz 
1949acaf4d2eSTobias Waldekranz 	switch (st->state) {
1950acaf4d2eSTobias Waldekranz 	case BR_STATE_DISABLED:
1951acaf4d2eSTobias Waldekranz 	case BR_STATE_BLOCKING:
1952acaf4d2eSTobias Waldekranz 	case BR_STATE_LISTENING:
1953acaf4d2eSTobias Waldekranz 		state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING;
1954acaf4d2eSTobias Waldekranz 		break;
1955acaf4d2eSTobias Waldekranz 	case BR_STATE_LEARNING:
1956acaf4d2eSTobias Waldekranz 		state = MV88E6XXX_PORT_CTL0_STATE_LEARNING;
1957acaf4d2eSTobias Waldekranz 		break;
1958acaf4d2eSTobias Waldekranz 	case BR_STATE_FORWARDING:
1959acaf4d2eSTobias Waldekranz 		state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
1960acaf4d2eSTobias Waldekranz 		break;
1961acaf4d2eSTobias Waldekranz 	default:
1962acaf4d2eSTobias Waldekranz 		return -EINVAL;
1963acaf4d2eSTobias Waldekranz 	}
1964acaf4d2eSTobias Waldekranz 
1965acaf4d2eSTobias Waldekranz 	list_for_each_entry(mst, &chip->msts, node) {
1966acaf4d2eSTobias Waldekranz 		if (mst->br == dsa_port_bridge_dev_get(dp) &&
1967acaf4d2eSTobias Waldekranz 		    mst->msti == st->msti) {
1968acaf4d2eSTobias Waldekranz 			if (mst->stu.state[port] == state)
1969acaf4d2eSTobias Waldekranz 				return 0;
1970acaf4d2eSTobias Waldekranz 
1971acaf4d2eSTobias Waldekranz 			mst->stu.state[port] = state;
1972acaf4d2eSTobias Waldekranz 			mv88e6xxx_reg_lock(chip);
1973acaf4d2eSTobias Waldekranz 			err = mv88e6xxx_stu_loadpurge(chip, &mst->stu);
1974acaf4d2eSTobias Waldekranz 			mv88e6xxx_reg_unlock(chip);
1975acaf4d2eSTobias Waldekranz 			return err;
1976acaf4d2eSTobias Waldekranz 		}
1977acaf4d2eSTobias Waldekranz 	}
1978acaf4d2eSTobias Waldekranz 
1979acaf4d2eSTobias Waldekranz 	return -ENOENT;
1980acaf4d2eSTobias Waldekranz }
1981acaf4d2eSTobias Waldekranz 
1982fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
1983b7a9e0daSVladimir Oltean 					u16 vid)
1984fad09c73SVivien Didelot {
19850493fa79SVladimir Oltean 	struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
198604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1987425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
19880493fa79SVladimir Oltean 	int err;
1989fad09c73SVivien Didelot 
1990db06ae41SAndrew Lunn 	/* DSA and CPU ports have to be members of multiple vlans */
19910493fa79SVladimir Oltean 	if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp))
1992db06ae41SAndrew Lunn 		return 0;
1993db06ae41SAndrew Lunn 
199434065c58STobias Waldekranz 	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
1995fad09c73SVivien Didelot 	if (err)
19967095a4c4SVivien Didelot 		return err;
1997fad09c73SVivien Didelot 
1998fad09c73SVivien Didelot 	if (!vlan.valid)
1999b7a9e0daSVladimir Oltean 		return 0;
2000fad09c73SVivien Didelot 
20010493fa79SVladimir Oltean 	dsa_switch_for_each_user_port(other_dp, ds) {
200241fb0cf1SVladimir Oltean 		struct net_device *other_br;
200341fb0cf1SVladimir Oltean 
20040493fa79SVladimir Oltean 		if (vlan.member[other_dp->index] ==
20057ec60d6eSVivien Didelot 		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
2006fad09c73SVivien Didelot 			continue;
2007fad09c73SVivien Didelot 
200841fb0cf1SVladimir Oltean 		if (dsa_port_bridge_same(dp, other_dp))
2009fad09c73SVivien Didelot 			break; /* same bridge, check next VLAN */
2010fad09c73SVivien Didelot 
201141fb0cf1SVladimir Oltean 		other_br = dsa_port_bridge_dev_get(other_dp);
201241fb0cf1SVladimir Oltean 		if (!other_br)
201366e2809dSAndrew Lunn 			continue;
201466e2809dSAndrew Lunn 
2015743fcc28SAndrew Lunn 		dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
201641fb0cf1SVladimir Oltean 			port, vlan.vid, other_dp->index, netdev_name(other_br));
20177095a4c4SVivien Didelot 		return -EOPNOTSUPP;
2018fad09c73SVivien Didelot 	}
2019fad09c73SVivien Didelot 
20207095a4c4SVivien Didelot 	return 0;
2021fad09c73SVivien Didelot }
2022fad09c73SVivien Didelot 
20238b6836d8SVladimir Oltean static int mv88e6xxx_port_commit_pvid(struct mv88e6xxx_chip *chip, int port)
20248b6836d8SVladimir Oltean {
20258b6836d8SVladimir Oltean 	struct dsa_port *dp = dsa_to_port(chip->ds, port);
202641fb0cf1SVladimir Oltean 	struct net_device *br = dsa_port_bridge_dev_get(dp);
20278b6836d8SVladimir Oltean 	struct mv88e6xxx_port *p = &chip->ports[port];
20285bded825SVladimir Oltean 	u16 pvid = MV88E6XXX_VID_STANDALONE;
20298b6836d8SVladimir Oltean 	bool drop_untagged = false;
20308b6836d8SVladimir Oltean 	int err;
20318b6836d8SVladimir Oltean 
203241fb0cf1SVladimir Oltean 	if (br) {
203341fb0cf1SVladimir Oltean 		if (br_vlan_enabled(br)) {
20348b6836d8SVladimir Oltean 			pvid = p->bridge_pvid.vid;
20358b6836d8SVladimir Oltean 			drop_untagged = !p->bridge_pvid.valid;
20365bded825SVladimir Oltean 		} else {
20375bded825SVladimir Oltean 			pvid = MV88E6XXX_VID_BRIDGED;
20385bded825SVladimir Oltean 		}
20398b6836d8SVladimir Oltean 	}
20408b6836d8SVladimir Oltean 
20418b6836d8SVladimir Oltean 	err = mv88e6xxx_port_set_pvid(chip, port, pvid);
20428b6836d8SVladimir Oltean 	if (err)
20438b6836d8SVladimir Oltean 		return err;
20448b6836d8SVladimir Oltean 
20458b6836d8SVladimir Oltean 	return mv88e6xxx_port_drop_untagged(chip, port, drop_untagged);
20468b6836d8SVladimir Oltean }
20478b6836d8SVladimir Oltean 
2048fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
204989153ed6SVladimir Oltean 					 bool vlan_filtering,
205089153ed6SVladimir Oltean 					 struct netlink_ext_ack *extack)
2051fad09c73SVivien Didelot {
205204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
205381c6edb2SVivien Didelot 	u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
205481c6edb2SVivien Didelot 		MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
20550e7b9925SAndrew Lunn 	int err;
2056fad09c73SVivien Didelot 
2057bae33f2bSVladimir Oltean 	if (!mv88e6xxx_max_vid(chip))
2058bae33f2bSVladimir Oltean 		return -EOPNOTSUPP;
2059fad09c73SVivien Didelot 
2060c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
20618b6836d8SVladimir Oltean 
2062385a0995SVivien Didelot 	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
20638b6836d8SVladimir Oltean 	if (err)
20648b6836d8SVladimir Oltean 		goto unlock;
20658b6836d8SVladimir Oltean 
20668b6836d8SVladimir Oltean 	err = mv88e6xxx_port_commit_pvid(chip, port);
20678b6836d8SVladimir Oltean 	if (err)
20688b6836d8SVladimir Oltean 		goto unlock;
20698b6836d8SVladimir Oltean 
20708b6836d8SVladimir Oltean unlock:
2071c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2072fad09c73SVivien Didelot 
20730e7b9925SAndrew Lunn 	return err;
2074fad09c73SVivien Didelot }
2075fad09c73SVivien Didelot 
2076fad09c73SVivien Didelot static int
2077fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
207880e02360SVivien Didelot 			    const struct switchdev_obj_port_vlan *vlan)
2079fad09c73SVivien Didelot {
208004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2081fad09c73SVivien Didelot 	int err;
2082fad09c73SVivien Didelot 
2083e545f865STobias Waldekranz 	if (!mv88e6xxx_max_vid(chip))
2084fad09c73SVivien Didelot 		return -EOPNOTSUPP;
2085fad09c73SVivien Didelot 
2086fad09c73SVivien Didelot 	/* If the requested port doesn't belong to the same bridge as the VLAN
2087fad09c73SVivien Didelot 	 * members, do not support it (yet) and fallback to software VLAN.
2088fad09c73SVivien Didelot 	 */
20897095a4c4SVivien Didelot 	mv88e6xxx_reg_lock(chip);
2090b7a9e0daSVladimir Oltean 	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid);
20917095a4c4SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
2092fad09c73SVivien Didelot 
20937095a4c4SVivien Didelot 	return err;
2094fad09c73SVivien Didelot }
2095fad09c73SVivien Didelot 
2096a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
2097a4c93ae1SAndrew Lunn 					const unsigned char *addr, u16 vid,
2098a4c93ae1SAndrew Lunn 					u8 state)
2099a4c93ae1SAndrew Lunn {
2100a4c93ae1SAndrew Lunn 	struct mv88e6xxx_atu_entry entry;
21015ef8d249SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
21025ef8d249SVivien Didelot 	u16 fid;
2103a4c93ae1SAndrew Lunn 	int err;
2104a4c93ae1SAndrew Lunn 
21055bded825SVladimir Oltean 	/* Ports have two private address databases: one for when the port is
21065bded825SVladimir Oltean 	 * standalone and one for when the port is under a bridge and the
21075bded825SVladimir Oltean 	 * 802.1Q mode is disabled. When the port is standalone, DSA wants its
21085bded825SVladimir Oltean 	 * address database to remain 100% empty, so we never load an ATU entry
21095bded825SVladimir Oltean 	 * into a standalone port's database. Therefore, translate the null
21105bded825SVladimir Oltean 	 * VLAN ID into the port's database used for VLAN-unaware bridging.
21115bded825SVladimir Oltean 	 */
21125ef8d249SVivien Didelot 	if (vid == 0) {
21135bded825SVladimir Oltean 		fid = MV88E6XXX_FID_BRIDGED;
21145ef8d249SVivien Didelot 	} else {
211534065c58STobias Waldekranz 		err = mv88e6xxx_vtu_get(chip, vid, &vlan);
21165ef8d249SVivien Didelot 		if (err)
21175ef8d249SVivien Didelot 			return err;
21185ef8d249SVivien Didelot 
21195ef8d249SVivien Didelot 		/* switchdev expects -EOPNOTSUPP to honor software VLANs */
212034065c58STobias Waldekranz 		if (!vlan.valid)
21215ef8d249SVivien Didelot 			return -EOPNOTSUPP;
21225ef8d249SVivien Didelot 
21235ef8d249SVivien Didelot 		fid = vlan.fid;
21245ef8d249SVivien Didelot 	}
2125a4c93ae1SAndrew Lunn 
2126d8291a95SVivien Didelot 	entry.state = 0;
2127a4c93ae1SAndrew Lunn 	ether_addr_copy(entry.mac, addr);
2128a4c93ae1SAndrew Lunn 	eth_addr_dec(entry.mac);
2129a4c93ae1SAndrew Lunn 
21305ef8d249SVivien Didelot 	err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry);
2131a4c93ae1SAndrew Lunn 	if (err)
2132a4c93ae1SAndrew Lunn 		return err;
2133a4c93ae1SAndrew Lunn 
2134a4c93ae1SAndrew Lunn 	/* Initialize a fresh ATU entry if it isn't found */
2135d8291a95SVivien Didelot 	if (!entry.state || !ether_addr_equal(entry.mac, addr)) {
2136a4c93ae1SAndrew Lunn 		memset(&entry, 0, sizeof(entry));
2137a4c93ae1SAndrew Lunn 		ether_addr_copy(entry.mac, addr);
2138a4c93ae1SAndrew Lunn 	}
2139a4c93ae1SAndrew Lunn 
2140a4c93ae1SAndrew Lunn 	/* Purge the ATU entry only if no port is using it anymore */
2141d8291a95SVivien Didelot 	if (!state) {
2142a4c93ae1SAndrew Lunn 		entry.portvec &= ~BIT(port);
2143a4c93ae1SAndrew Lunn 		if (!entry.portvec)
2144d8291a95SVivien Didelot 			entry.state = 0;
2145a4c93ae1SAndrew Lunn 	} else {
2146f72f2fb8SDENG Qingfang 		if (state == MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC)
2147f72f2fb8SDENG Qingfang 			entry.portvec = BIT(port);
2148f72f2fb8SDENG Qingfang 		else
2149a4c93ae1SAndrew Lunn 			entry.portvec |= BIT(port);
2150f72f2fb8SDENG Qingfang 
2151a4c93ae1SAndrew Lunn 		entry.state = state;
2152a4c93ae1SAndrew Lunn 	}
2153a4c93ae1SAndrew Lunn 
21545ef8d249SVivien Didelot 	return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry);
2155a4c93ae1SAndrew Lunn }
2156a4c93ae1SAndrew Lunn 
2157da7dc875SVivien Didelot static int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port,
2158da7dc875SVivien Didelot 				  const struct mv88e6xxx_policy *policy)
2159da7dc875SVivien Didelot {
2160da7dc875SVivien Didelot 	enum mv88e6xxx_policy_mapping mapping = policy->mapping;
2161da7dc875SVivien Didelot 	enum mv88e6xxx_policy_action action = policy->action;
2162da7dc875SVivien Didelot 	const u8 *addr = policy->addr;
2163da7dc875SVivien Didelot 	u16 vid = policy->vid;
2164da7dc875SVivien Didelot 	u8 state;
2165da7dc875SVivien Didelot 	int err;
2166da7dc875SVivien Didelot 	int id;
2167da7dc875SVivien Didelot 
2168da7dc875SVivien Didelot 	if (!chip->info->ops->port_set_policy)
2169da7dc875SVivien Didelot 		return -EOPNOTSUPP;
2170da7dc875SVivien Didelot 
2171da7dc875SVivien Didelot 	switch (mapping) {
2172da7dc875SVivien Didelot 	case MV88E6XXX_POLICY_MAPPING_DA:
2173da7dc875SVivien Didelot 	case MV88E6XXX_POLICY_MAPPING_SA:
2174da7dc875SVivien Didelot 		if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
2175da7dc875SVivien Didelot 			state = 0; /* Dissociate the port and address */
2176da7dc875SVivien Didelot 		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
2177da7dc875SVivien Didelot 			 is_multicast_ether_addr(addr))
2178da7dc875SVivien Didelot 			state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY;
2179da7dc875SVivien Didelot 		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
2180da7dc875SVivien Didelot 			 is_unicast_ether_addr(addr))
2181da7dc875SVivien Didelot 			state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY;
2182da7dc875SVivien Didelot 		else
2183da7dc875SVivien Didelot 			return -EOPNOTSUPP;
2184da7dc875SVivien Didelot 
2185da7dc875SVivien Didelot 		err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
2186da7dc875SVivien Didelot 						   state);
2187da7dc875SVivien Didelot 		if (err)
2188da7dc875SVivien Didelot 			return err;
2189da7dc875SVivien Didelot 		break;
2190da7dc875SVivien Didelot 	default:
2191da7dc875SVivien Didelot 		return -EOPNOTSUPP;
2192da7dc875SVivien Didelot 	}
2193da7dc875SVivien Didelot 
2194da7dc875SVivien Didelot 	/* Skip the port's policy clearing if the mapping is still in use */
2195da7dc875SVivien Didelot 	if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
2196da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
2197da7dc875SVivien Didelot 			if (policy->port == port &&
2198da7dc875SVivien Didelot 			    policy->mapping == mapping &&
2199da7dc875SVivien Didelot 			    policy->action != action)
2200da7dc875SVivien Didelot 				return 0;
2201da7dc875SVivien Didelot 
2202da7dc875SVivien Didelot 	return chip->info->ops->port_set_policy(chip, port, mapping, action);
2203da7dc875SVivien Didelot }
2204da7dc875SVivien Didelot 
2205da7dc875SVivien Didelot static int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port,
2206da7dc875SVivien Didelot 				   struct ethtool_rx_flow_spec *fs)
2207da7dc875SVivien Didelot {
2208da7dc875SVivien Didelot 	struct ethhdr *mac_entry = &fs->h_u.ether_spec;
2209da7dc875SVivien Didelot 	struct ethhdr *mac_mask = &fs->m_u.ether_spec;
2210da7dc875SVivien Didelot 	enum mv88e6xxx_policy_mapping mapping;
2211da7dc875SVivien Didelot 	enum mv88e6xxx_policy_action action;
2212da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
2213da7dc875SVivien Didelot 	u16 vid = 0;
2214da7dc875SVivien Didelot 	u8 *addr;
2215da7dc875SVivien Didelot 	int err;
2216da7dc875SVivien Didelot 	int id;
2217da7dc875SVivien Didelot 
2218da7dc875SVivien Didelot 	if (fs->location != RX_CLS_LOC_ANY)
2219da7dc875SVivien Didelot 		return -EINVAL;
2220da7dc875SVivien Didelot 
2221da7dc875SVivien Didelot 	if (fs->ring_cookie == RX_CLS_FLOW_DISC)
2222da7dc875SVivien Didelot 		action = MV88E6XXX_POLICY_ACTION_DISCARD;
2223da7dc875SVivien Didelot 	else
2224da7dc875SVivien Didelot 		return -EOPNOTSUPP;
2225da7dc875SVivien Didelot 
2226da7dc875SVivien Didelot 	switch (fs->flow_type & ~FLOW_EXT) {
2227da7dc875SVivien Didelot 	case ETHER_FLOW:
2228da7dc875SVivien Didelot 		if (!is_zero_ether_addr(mac_mask->h_dest) &&
2229da7dc875SVivien Didelot 		    is_zero_ether_addr(mac_mask->h_source)) {
2230da7dc875SVivien Didelot 			mapping = MV88E6XXX_POLICY_MAPPING_DA;
2231da7dc875SVivien Didelot 			addr = mac_entry->h_dest;
2232da7dc875SVivien Didelot 		} else if (is_zero_ether_addr(mac_mask->h_dest) &&
2233da7dc875SVivien Didelot 		    !is_zero_ether_addr(mac_mask->h_source)) {
2234da7dc875SVivien Didelot 			mapping = MV88E6XXX_POLICY_MAPPING_SA;
2235da7dc875SVivien Didelot 			addr = mac_entry->h_source;
2236da7dc875SVivien Didelot 		} else {
2237da7dc875SVivien Didelot 			/* Cannot support DA and SA mapping in the same rule */
2238da7dc875SVivien Didelot 			return -EOPNOTSUPP;
2239da7dc875SVivien Didelot 		}
2240da7dc875SVivien Didelot 		break;
2241da7dc875SVivien Didelot 	default:
2242da7dc875SVivien Didelot 		return -EOPNOTSUPP;
2243da7dc875SVivien Didelot 	}
2244da7dc875SVivien Didelot 
2245da7dc875SVivien Didelot 	if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) {
224604844280SAndrew Lunn 		if (fs->m_ext.vlan_tci != htons(0xffff))
2247da7dc875SVivien Didelot 			return -EOPNOTSUPP;
2248da7dc875SVivien Didelot 		vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK;
2249da7dc875SVivien Didelot 	}
2250da7dc875SVivien Didelot 
2251da7dc875SVivien Didelot 	idr_for_each_entry(&chip->policies, policy, id) {
2252da7dc875SVivien Didelot 		if (policy->port == port && policy->mapping == mapping &&
2253da7dc875SVivien Didelot 		    policy->action == action && policy->vid == vid &&
2254da7dc875SVivien Didelot 		    ether_addr_equal(policy->addr, addr))
2255da7dc875SVivien Didelot 			return -EEXIST;
2256da7dc875SVivien Didelot 	}
2257da7dc875SVivien Didelot 
2258da7dc875SVivien Didelot 	policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL);
2259da7dc875SVivien Didelot 	if (!policy)
2260da7dc875SVivien Didelot 		return -ENOMEM;
2261da7dc875SVivien Didelot 
2262da7dc875SVivien Didelot 	fs->location = 0;
2263da7dc875SVivien Didelot 	err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff,
2264da7dc875SVivien Didelot 			    GFP_KERNEL);
2265da7dc875SVivien Didelot 	if (err) {
2266da7dc875SVivien Didelot 		devm_kfree(chip->dev, policy);
2267da7dc875SVivien Didelot 		return err;
2268da7dc875SVivien Didelot 	}
2269da7dc875SVivien Didelot 
2270da7dc875SVivien Didelot 	memcpy(&policy->fs, fs, sizeof(*fs));
2271da7dc875SVivien Didelot 	ether_addr_copy(policy->addr, addr);
2272da7dc875SVivien Didelot 	policy->mapping = mapping;
2273da7dc875SVivien Didelot 	policy->action = action;
2274da7dc875SVivien Didelot 	policy->port = port;
2275da7dc875SVivien Didelot 	policy->vid = vid;
2276da7dc875SVivien Didelot 
2277da7dc875SVivien Didelot 	err = mv88e6xxx_policy_apply(chip, port, policy);
2278da7dc875SVivien Didelot 	if (err) {
2279da7dc875SVivien Didelot 		idr_remove(&chip->policies, fs->location);
2280da7dc875SVivien Didelot 		devm_kfree(chip->dev, policy);
2281da7dc875SVivien Didelot 		return err;
2282da7dc875SVivien Didelot 	}
2283da7dc875SVivien Didelot 
2284da7dc875SVivien Didelot 	return 0;
2285da7dc875SVivien Didelot }
2286da7dc875SVivien Didelot 
2287da7dc875SVivien Didelot static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,
2288da7dc875SVivien Didelot 			       struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
2289da7dc875SVivien Didelot {
2290da7dc875SVivien Didelot 	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
2291da7dc875SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2292da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
2293da7dc875SVivien Didelot 	int err;
2294da7dc875SVivien Didelot 	int id;
2295da7dc875SVivien Didelot 
2296da7dc875SVivien Didelot 	mv88e6xxx_reg_lock(chip);
2297da7dc875SVivien Didelot 
2298da7dc875SVivien Didelot 	switch (rxnfc->cmd) {
2299da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRLCNT:
2300da7dc875SVivien Didelot 		rxnfc->data = 0;
2301da7dc875SVivien Didelot 		rxnfc->data |= RX_CLS_LOC_SPECIAL;
2302da7dc875SVivien Didelot 		rxnfc->rule_cnt = 0;
2303da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
2304da7dc875SVivien Didelot 			if (policy->port == port)
2305da7dc875SVivien Didelot 				rxnfc->rule_cnt++;
2306da7dc875SVivien Didelot 		err = 0;
2307da7dc875SVivien Didelot 		break;
2308da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRULE:
2309da7dc875SVivien Didelot 		err = -ENOENT;
2310da7dc875SVivien Didelot 		policy = idr_find(&chip->policies, fs->location);
2311da7dc875SVivien Didelot 		if (policy) {
2312da7dc875SVivien Didelot 			memcpy(fs, &policy->fs, sizeof(*fs));
2313da7dc875SVivien Didelot 			err = 0;
2314da7dc875SVivien Didelot 		}
2315da7dc875SVivien Didelot 		break;
2316da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRLALL:
2317da7dc875SVivien Didelot 		rxnfc->data = 0;
2318da7dc875SVivien Didelot 		rxnfc->rule_cnt = 0;
2319da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
2320da7dc875SVivien Didelot 			if (policy->port == port)
2321da7dc875SVivien Didelot 				rule_locs[rxnfc->rule_cnt++] = id;
2322da7dc875SVivien Didelot 		err = 0;
2323da7dc875SVivien Didelot 		break;
2324da7dc875SVivien Didelot 	default:
2325da7dc875SVivien Didelot 		err = -EOPNOTSUPP;
2326da7dc875SVivien Didelot 		break;
2327da7dc875SVivien Didelot 	}
2328da7dc875SVivien Didelot 
2329da7dc875SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
2330da7dc875SVivien Didelot 
2331da7dc875SVivien Didelot 	return err;
2332da7dc875SVivien Didelot }
2333da7dc875SVivien Didelot 
2334da7dc875SVivien Didelot static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port,
2335da7dc875SVivien Didelot 			       struct ethtool_rxnfc *rxnfc)
2336da7dc875SVivien Didelot {
2337da7dc875SVivien Didelot 	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
2338da7dc875SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2339da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
2340da7dc875SVivien Didelot 	int err;
2341da7dc875SVivien Didelot 
2342da7dc875SVivien Didelot 	mv88e6xxx_reg_lock(chip);
2343da7dc875SVivien Didelot 
2344da7dc875SVivien Didelot 	switch (rxnfc->cmd) {
2345da7dc875SVivien Didelot 	case ETHTOOL_SRXCLSRLINS:
2346da7dc875SVivien Didelot 		err = mv88e6xxx_policy_insert(chip, port, fs);
2347da7dc875SVivien Didelot 		break;
2348da7dc875SVivien Didelot 	case ETHTOOL_SRXCLSRLDEL:
2349da7dc875SVivien Didelot 		err = -ENOENT;
2350da7dc875SVivien Didelot 		policy = idr_remove(&chip->policies, fs->location);
2351da7dc875SVivien Didelot 		if (policy) {
2352da7dc875SVivien Didelot 			policy->action = MV88E6XXX_POLICY_ACTION_NORMAL;
2353da7dc875SVivien Didelot 			err = mv88e6xxx_policy_apply(chip, port, policy);
2354da7dc875SVivien Didelot 			devm_kfree(chip->dev, policy);
2355da7dc875SVivien Didelot 		}
2356da7dc875SVivien Didelot 		break;
2357da7dc875SVivien Didelot 	default:
2358da7dc875SVivien Didelot 		err = -EOPNOTSUPP;
2359da7dc875SVivien Didelot 		break;
2360da7dc875SVivien Didelot 	}
2361da7dc875SVivien Didelot 
2362da7dc875SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
2363da7dc875SVivien Didelot 
2364da7dc875SVivien Didelot 	return err;
2365da7dc875SVivien Didelot }
2366da7dc875SVivien Didelot 
236787fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
236887fa886eSAndrew Lunn 					u16 vid)
236987fa886eSAndrew Lunn {
237087fa886eSAndrew Lunn 	u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
23710806dd46STobias Waldekranz 	u8 broadcast[ETH_ALEN];
23720806dd46STobias Waldekranz 
23730806dd46STobias Waldekranz 	eth_broadcast_addr(broadcast);
237487fa886eSAndrew Lunn 
237587fa886eSAndrew Lunn 	return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
237687fa886eSAndrew Lunn }
237787fa886eSAndrew Lunn 
237887fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
237987fa886eSAndrew Lunn {
238087fa886eSAndrew Lunn 	int port;
238187fa886eSAndrew Lunn 	int err;
238287fa886eSAndrew Lunn 
238387fa886eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
23848d1d8298STobias Waldekranz 		struct dsa_port *dp = dsa_to_port(chip->ds, port);
23858d1d8298STobias Waldekranz 		struct net_device *brport;
23868d1d8298STobias Waldekranz 
23878d1d8298STobias Waldekranz 		if (dsa_is_unused_port(chip->ds, port))
23888d1d8298STobias Waldekranz 			continue;
23898d1d8298STobias Waldekranz 
23908d1d8298STobias Waldekranz 		brport = dsa_port_to_bridge_port(dp);
23918d1d8298STobias Waldekranz 		if (brport && !br_port_flag_is_set(brport, BR_BCAST_FLOOD))
23928d1d8298STobias Waldekranz 			/* Skip bridged user ports where broadcast
23938d1d8298STobias Waldekranz 			 * flooding is disabled.
23948d1d8298STobias Waldekranz 			 */
23958d1d8298STobias Waldekranz 			continue;
23968d1d8298STobias Waldekranz 
239787fa886eSAndrew Lunn 		err = mv88e6xxx_port_add_broadcast(chip, port, vid);
239887fa886eSAndrew Lunn 		if (err)
239987fa886eSAndrew Lunn 			return err;
240087fa886eSAndrew Lunn 	}
240187fa886eSAndrew Lunn 
240287fa886eSAndrew Lunn 	return 0;
240387fa886eSAndrew Lunn }
240487fa886eSAndrew Lunn 
24058d1d8298STobias Waldekranz struct mv88e6xxx_port_broadcast_sync_ctx {
24068d1d8298STobias Waldekranz 	int port;
24078d1d8298STobias Waldekranz 	bool flood;
24088d1d8298STobias Waldekranz };
24098d1d8298STobias Waldekranz 
24108d1d8298STobias Waldekranz static int
24118d1d8298STobias Waldekranz mv88e6xxx_port_broadcast_sync_vlan(struct mv88e6xxx_chip *chip,
24128d1d8298STobias Waldekranz 				   const struct mv88e6xxx_vtu_entry *vlan,
24138d1d8298STobias Waldekranz 				   void *_ctx)
24148d1d8298STobias Waldekranz {
24158d1d8298STobias Waldekranz 	struct mv88e6xxx_port_broadcast_sync_ctx *ctx = _ctx;
24168d1d8298STobias Waldekranz 	u8 broadcast[ETH_ALEN];
24178d1d8298STobias Waldekranz 	u8 state;
24188d1d8298STobias Waldekranz 
24198d1d8298STobias Waldekranz 	if (ctx->flood)
24208d1d8298STobias Waldekranz 		state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
24218d1d8298STobias Waldekranz 	else
24228d1d8298STobias Waldekranz 		state = MV88E6XXX_G1_ATU_DATA_STATE_MC_UNUSED;
24238d1d8298STobias Waldekranz 
24248d1d8298STobias Waldekranz 	eth_broadcast_addr(broadcast);
24258d1d8298STobias Waldekranz 
24268d1d8298STobias Waldekranz 	return mv88e6xxx_port_db_load_purge(chip, ctx->port, broadcast,
24278d1d8298STobias Waldekranz 					    vlan->vid, state);
24288d1d8298STobias Waldekranz }
24298d1d8298STobias Waldekranz 
24308d1d8298STobias Waldekranz static int mv88e6xxx_port_broadcast_sync(struct mv88e6xxx_chip *chip, int port,
24318d1d8298STobias Waldekranz 					 bool flood)
24328d1d8298STobias Waldekranz {
24338d1d8298STobias Waldekranz 	struct mv88e6xxx_port_broadcast_sync_ctx ctx = {
24348d1d8298STobias Waldekranz 		.port = port,
24358d1d8298STobias Waldekranz 		.flood = flood,
24368d1d8298STobias Waldekranz 	};
24378d1d8298STobias Waldekranz 	struct mv88e6xxx_vtu_entry vid0 = {
24388d1d8298STobias Waldekranz 		.vid = 0,
24398d1d8298STobias Waldekranz 	};
24408d1d8298STobias Waldekranz 	int err;
24418d1d8298STobias Waldekranz 
24428d1d8298STobias Waldekranz 	/* Update the port's private database... */
24438d1d8298STobias Waldekranz 	err = mv88e6xxx_port_broadcast_sync_vlan(chip, &vid0, &ctx);
24448d1d8298STobias Waldekranz 	if (err)
24458d1d8298STobias Waldekranz 		return err;
24468d1d8298STobias Waldekranz 
24478d1d8298STobias Waldekranz 	/* ...and the database for all VLANs. */
24488d1d8298STobias Waldekranz 	return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_broadcast_sync_vlan,
24498d1d8298STobias Waldekranz 				  &ctx);
24508d1d8298STobias Waldekranz }
24518d1d8298STobias Waldekranz 
2452b1ac6fb4SVivien Didelot static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port,
2453933b4425SRussell King 				    u16 vid, u8 member, bool warn)
2454fad09c73SVivien Didelot {
2455b1ac6fb4SVivien Didelot 	const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
2456b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
2457b1ac6fb4SVivien Didelot 	int i, err;
2458fad09c73SVivien Didelot 
245934065c58STobias Waldekranz 	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
2460fad09c73SVivien Didelot 	if (err)
2461fad09c73SVivien Didelot 		return err;
2462fad09c73SVivien Didelot 
246334065c58STobias Waldekranz 	if (!vlan.valid) {
2464b1ac6fb4SVivien Didelot 		memset(&vlan, 0, sizeof(vlan));
2465b1ac6fb4SVivien Didelot 
2466d352b20fSTobias Waldekranz 		if (vid == MV88E6XXX_VID_STANDALONE)
2467d352b20fSTobias Waldekranz 			vlan.policy = true;
2468d352b20fSTobias Waldekranz 
2469b1ac6fb4SVivien Didelot 		err = mv88e6xxx_atu_new(chip, &vlan.fid);
2470b1ac6fb4SVivien Didelot 		if (err)
2471b1ac6fb4SVivien Didelot 			return err;
2472b1ac6fb4SVivien Didelot 
2473b1ac6fb4SVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
2474b1ac6fb4SVivien Didelot 			if (i == port)
2475b1ac6fb4SVivien Didelot 				vlan.member[i] = member;
2476b1ac6fb4SVivien Didelot 			else
2477b1ac6fb4SVivien Didelot 				vlan.member[i] = non_member;
2478b1ac6fb4SVivien Didelot 
2479b1ac6fb4SVivien Didelot 		vlan.vid = vid;
24801cb9dfcaSRasmus Villemoes 		vlan.valid = true;
2481fad09c73SVivien Didelot 
248287fa886eSAndrew Lunn 		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
248387fa886eSAndrew Lunn 		if (err)
248487fa886eSAndrew Lunn 			return err;
248587fa886eSAndrew Lunn 
2486b1ac6fb4SVivien Didelot 		err = mv88e6xxx_broadcast_setup(chip, vlan.vid);
2487b1ac6fb4SVivien Didelot 		if (err)
2488b1ac6fb4SVivien Didelot 			return err;
2489b1ac6fb4SVivien Didelot 	} else if (vlan.member[port] != member) {
2490b1ac6fb4SVivien Didelot 		vlan.member[port] = member;
2491b1ac6fb4SVivien Didelot 
2492b1ac6fb4SVivien Didelot 		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
2493b1ac6fb4SVivien Didelot 		if (err)
2494b1ac6fb4SVivien Didelot 			return err;
2495933b4425SRussell King 	} else if (warn) {
2496b1ac6fb4SVivien Didelot 		dev_info(chip->dev, "p%d: already a member of VLAN %d\n",
2497b1ac6fb4SVivien Didelot 			 port, vid);
2498b1ac6fb4SVivien Didelot 	}
2499b1ac6fb4SVivien Didelot 
2500b1ac6fb4SVivien Didelot 	return 0;
2501fad09c73SVivien Didelot }
2502fad09c73SVivien Didelot 
25031958d581SVladimir Oltean static int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
250431046a5fSVladimir Oltean 				   const struct switchdev_obj_port_vlan *vlan,
250531046a5fSVladimir Oltean 				   struct netlink_ext_ack *extack)
2506fad09c73SVivien Didelot {
250704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2508fad09c73SVivien Didelot 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
2509fad09c73SVivien Didelot 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
25108b6836d8SVladimir Oltean 	struct mv88e6xxx_port *p = &chip->ports[port];
2511933b4425SRussell King 	bool warn;
2512c91498e1SVivien Didelot 	u8 member;
25131958d581SVladimir Oltean 	int err;
2514fad09c73SVivien Didelot 
2515b8b79c41SEldar Gasanov 	if (!vlan->vid)
2516b8b79c41SEldar Gasanov 		return 0;
2517b8b79c41SEldar Gasanov 
25181958d581SVladimir Oltean 	err = mv88e6xxx_port_vlan_prepare(ds, port, vlan);
25191958d581SVladimir Oltean 	if (err)
25201958d581SVladimir Oltean 		return err;
2521fad09c73SVivien Didelot 
2522c91498e1SVivien Didelot 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
25237ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED;
2524c91498e1SVivien Didelot 	else if (untagged)
25257ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED;
2526c91498e1SVivien Didelot 	else
25277ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
2528c91498e1SVivien Didelot 
2529933b4425SRussell King 	/* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port
2530933b4425SRussell King 	 * and then the CPU port. Do not warn for duplicates for the CPU port.
2531933b4425SRussell King 	 */
2532933b4425SRussell King 	warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port);
2533933b4425SRussell King 
2534c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2535fad09c73SVivien Didelot 
25361958d581SVladimir Oltean 	err = mv88e6xxx_port_vlan_join(chip, port, vlan->vid, member, warn);
25371958d581SVladimir Oltean 	if (err) {
2538774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
2539b7a9e0daSVladimir Oltean 			vlan->vid, untagged ? 'u' : 't');
25401958d581SVladimir Oltean 		goto out;
25411958d581SVladimir Oltean 	}
2542fad09c73SVivien Didelot 
25431958d581SVladimir Oltean 	if (pvid) {
25448b6836d8SVladimir Oltean 		p->bridge_pvid.vid = vlan->vid;
25458b6836d8SVladimir Oltean 		p->bridge_pvid.valid = true;
25468b6836d8SVladimir Oltean 
25478b6836d8SVladimir Oltean 		err = mv88e6xxx_port_commit_pvid(chip, port);
25488b6836d8SVladimir Oltean 		if (err)
25498b6836d8SVladimir Oltean 			goto out;
25508b6836d8SVladimir Oltean 	} else if (vlan->vid && p->bridge_pvid.vid == vlan->vid) {
25518b6836d8SVladimir Oltean 		/* The old pvid was reinstalled as a non-pvid VLAN */
25528b6836d8SVladimir Oltean 		p->bridge_pvid.valid = false;
25538b6836d8SVladimir Oltean 
25548b6836d8SVladimir Oltean 		err = mv88e6xxx_port_commit_pvid(chip, port);
25558b6836d8SVladimir Oltean 		if (err)
25561958d581SVladimir Oltean 			goto out;
25571958d581SVladimir Oltean 	}
25588b6836d8SVladimir Oltean 
25591958d581SVladimir Oltean out:
2560c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
25611958d581SVladimir Oltean 
25621958d581SVladimir Oltean 	return err;
2563fad09c73SVivien Didelot }
2564fad09c73SVivien Didelot 
256552109892SVivien Didelot static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip,
2566fad09c73SVivien Didelot 				     int port, u16 vid)
2567fad09c73SVivien Didelot {
2568b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
2569fad09c73SVivien Didelot 	int i, err;
2570fad09c73SVivien Didelot 
257152109892SVivien Didelot 	if (!vid)
2572c92c7413SVladimir Oltean 		return 0;
257352109892SVivien Didelot 
257434065c58STobias Waldekranz 	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
2575fad09c73SVivien Didelot 	if (err)
2576fad09c73SVivien Didelot 		return err;
2577fad09c73SVivien Didelot 
257852109892SVivien Didelot 	/* If the VLAN doesn't exist in hardware or the port isn't a member,
257952109892SVivien Didelot 	 * tell switchdev that this VLAN is likely handled in software.
258052109892SVivien Didelot 	 */
258134065c58STobias Waldekranz 	if (!vlan.valid ||
258252109892SVivien Didelot 	    vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
2583fad09c73SVivien Didelot 		return -EOPNOTSUPP;
2584fad09c73SVivien Didelot 
25857ec60d6eSVivien Didelot 	vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
2586fad09c73SVivien Didelot 
2587fad09c73SVivien Didelot 	/* keep the VLAN unless all ports are excluded */
2588fad09c73SVivien Didelot 	vlan.valid = false;
2589370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
25907ec60d6eSVivien Didelot 		if (vlan.member[i] !=
25917ec60d6eSVivien Didelot 		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
2592fad09c73SVivien Didelot 			vlan.valid = true;
2593fad09c73SVivien Didelot 			break;
2594fad09c73SVivien Didelot 		}
2595fad09c73SVivien Didelot 	}
2596fad09c73SVivien Didelot 
25970ad5daf6SVivien Didelot 	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
2598fad09c73SVivien Didelot 	if (err)
2599fad09c73SVivien Didelot 		return err;
2600fad09c73SVivien Didelot 
2601acaf4d2eSTobias Waldekranz 	if (!vlan.valid) {
2602acaf4d2eSTobias Waldekranz 		err = mv88e6xxx_mst_put(chip, vlan.sid);
2603acaf4d2eSTobias Waldekranz 		if (err)
2604acaf4d2eSTobias Waldekranz 			return err;
2605acaf4d2eSTobias Waldekranz 	}
2606acaf4d2eSTobias Waldekranz 
2607e606ca36SVivien Didelot 	return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
2608fad09c73SVivien Didelot }
2609fad09c73SVivien Didelot 
2610fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
2611fad09c73SVivien Didelot 				   const struct switchdev_obj_port_vlan *vlan)
2612fad09c73SVivien Didelot {
261304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
26148b6836d8SVladimir Oltean 	struct mv88e6xxx_port *p = &chip->ports[port];
2615fad09c73SVivien Didelot 	int err = 0;
2616b7a9e0daSVladimir Oltean 	u16 pvid;
2617fad09c73SVivien Didelot 
2618e545f865STobias Waldekranz 	if (!mv88e6xxx_max_vid(chip))
2619fad09c73SVivien Didelot 		return -EOPNOTSUPP;
2620fad09c73SVivien Didelot 
2621a2614140SVladimir Oltean 	/* The ATU removal procedure needs the FID to be mapped in the VTU,
2622a2614140SVladimir Oltean 	 * but FDB deletion runs concurrently with VLAN deletion. Flush the DSA
2623a2614140SVladimir Oltean 	 * switchdev workqueue to ensure that all FDB entries are deleted
2624a2614140SVladimir Oltean 	 * before we remove the VLAN.
2625a2614140SVladimir Oltean 	 */
2626a2614140SVladimir Oltean 	dsa_flush_workqueue();
2627a2614140SVladimir Oltean 
2628c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2629fad09c73SVivien Didelot 
263077064f37SVivien Didelot 	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
2631fad09c73SVivien Didelot 	if (err)
2632fad09c73SVivien Didelot 		goto unlock;
2633fad09c73SVivien Didelot 
2634b7a9e0daSVladimir Oltean 	err = mv88e6xxx_port_vlan_leave(chip, port, vlan->vid);
2635fad09c73SVivien Didelot 	if (err)
2636fad09c73SVivien Didelot 		goto unlock;
2637fad09c73SVivien Didelot 
2638b7a9e0daSVladimir Oltean 	if (vlan->vid == pvid) {
26398b6836d8SVladimir Oltean 		p->bridge_pvid.valid = false;
26408b6836d8SVladimir Oltean 
26418b6836d8SVladimir Oltean 		err = mv88e6xxx_port_commit_pvid(chip, port);
2642fad09c73SVivien Didelot 		if (err)
2643fad09c73SVivien Didelot 			goto unlock;
2644fad09c73SVivien Didelot 	}
2645fad09c73SVivien Didelot 
2646fad09c73SVivien Didelot unlock:
2647c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2648fad09c73SVivien Didelot 
2649fad09c73SVivien Didelot 	return err;
2650fad09c73SVivien Didelot }
2651fad09c73SVivien Didelot 
2652acaf4d2eSTobias Waldekranz static int mv88e6xxx_port_vlan_fast_age(struct dsa_switch *ds, int port, u16 vid)
2653acaf4d2eSTobias Waldekranz {
2654acaf4d2eSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
2655acaf4d2eSTobias Waldekranz 	struct mv88e6xxx_vtu_entry vlan;
2656acaf4d2eSTobias Waldekranz 	int err;
2657acaf4d2eSTobias Waldekranz 
2658acaf4d2eSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
2659acaf4d2eSTobias Waldekranz 
2660acaf4d2eSTobias Waldekranz 	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
2661acaf4d2eSTobias Waldekranz 	if (err)
2662acaf4d2eSTobias Waldekranz 		goto unlock;
2663acaf4d2eSTobias Waldekranz 
2664acaf4d2eSTobias Waldekranz 	err = mv88e6xxx_port_fast_age_fid(chip, port, vlan.fid);
2665acaf4d2eSTobias Waldekranz 
2666acaf4d2eSTobias Waldekranz unlock:
2667acaf4d2eSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
2668acaf4d2eSTobias Waldekranz 
2669acaf4d2eSTobias Waldekranz 	return err;
2670acaf4d2eSTobias Waldekranz }
2671acaf4d2eSTobias Waldekranz 
2672acaf4d2eSTobias Waldekranz static int mv88e6xxx_vlan_msti_set(struct dsa_switch *ds,
2673acaf4d2eSTobias Waldekranz 				   struct dsa_bridge bridge,
2674acaf4d2eSTobias Waldekranz 				   const struct switchdev_vlan_msti *msti)
2675acaf4d2eSTobias Waldekranz {
2676acaf4d2eSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
2677acaf4d2eSTobias Waldekranz 	struct mv88e6xxx_vtu_entry vlan;
2678acaf4d2eSTobias Waldekranz 	u8 old_sid, new_sid;
2679acaf4d2eSTobias Waldekranz 	int err;
2680acaf4d2eSTobias Waldekranz 
2681bd48b911STobias Waldekranz 	if (!mv88e6xxx_has_stu(chip))
2682bd48b911STobias Waldekranz 		return -EOPNOTSUPP;
2683bd48b911STobias Waldekranz 
2684acaf4d2eSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
2685acaf4d2eSTobias Waldekranz 
2686acaf4d2eSTobias Waldekranz 	err = mv88e6xxx_vtu_get(chip, msti->vid, &vlan);
2687acaf4d2eSTobias Waldekranz 	if (err)
2688acaf4d2eSTobias Waldekranz 		goto unlock;
2689acaf4d2eSTobias Waldekranz 
2690acaf4d2eSTobias Waldekranz 	if (!vlan.valid) {
2691acaf4d2eSTobias Waldekranz 		err = -EINVAL;
2692acaf4d2eSTobias Waldekranz 		goto unlock;
2693acaf4d2eSTobias Waldekranz 	}
2694acaf4d2eSTobias Waldekranz 
2695acaf4d2eSTobias Waldekranz 	old_sid = vlan.sid;
2696acaf4d2eSTobias Waldekranz 
2697acaf4d2eSTobias Waldekranz 	err = mv88e6xxx_mst_get(chip, bridge.dev, msti->msti, &new_sid);
2698acaf4d2eSTobias Waldekranz 	if (err)
2699acaf4d2eSTobias Waldekranz 		goto unlock;
2700acaf4d2eSTobias Waldekranz 
2701acaf4d2eSTobias Waldekranz 	if (new_sid != old_sid) {
2702acaf4d2eSTobias Waldekranz 		vlan.sid = new_sid;
2703acaf4d2eSTobias Waldekranz 
2704acaf4d2eSTobias Waldekranz 		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
2705acaf4d2eSTobias Waldekranz 		if (err) {
2706acaf4d2eSTobias Waldekranz 			mv88e6xxx_mst_put(chip, new_sid);
2707acaf4d2eSTobias Waldekranz 			goto unlock;
2708acaf4d2eSTobias Waldekranz 		}
2709acaf4d2eSTobias Waldekranz 	}
2710acaf4d2eSTobias Waldekranz 
2711acaf4d2eSTobias Waldekranz 	err = mv88e6xxx_mst_put(chip, old_sid);
2712acaf4d2eSTobias Waldekranz 
2713acaf4d2eSTobias Waldekranz unlock:
2714acaf4d2eSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
2715acaf4d2eSTobias Waldekranz 	return err;
2716acaf4d2eSTobias Waldekranz }
2717acaf4d2eSTobias Waldekranz 
27181b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
2719c2693363SVladimir Oltean 				  const unsigned char *addr, u16 vid,
2720c2693363SVladimir Oltean 				  struct dsa_db db)
2721fad09c73SVivien Didelot {
272204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
27231b6dd556SArkadi Sharshevsky 	int err;
2724fad09c73SVivien Didelot 
2725c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
27261b6dd556SArkadi Sharshevsky 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
27271b6dd556SArkadi Sharshevsky 					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
2728c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
27291b6dd556SArkadi Sharshevsky 
27301b6dd556SArkadi Sharshevsky 	return err;
2731fad09c73SVivien Didelot }
2732fad09c73SVivien Didelot 
2733fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
2734c2693363SVladimir Oltean 				  const unsigned char *addr, u16 vid,
2735c2693363SVladimir Oltean 				  struct dsa_db db)
2736fad09c73SVivien Didelot {
273704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
273883dabd1fSVivien Didelot 	int err;
2739fad09c73SVivien Didelot 
2740c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2741d8291a95SVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
2742c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2743fad09c73SVivien Didelot 
274483dabd1fSVivien Didelot 	return err;
2745fad09c73SVivien Didelot }
2746fad09c73SVivien Didelot 
274783dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
2748fad09c73SVivien Didelot 				      u16 fid, u16 vid, int port,
27492bedde1aSArkadi Sharshevsky 				      dsa_fdb_dump_cb_t *cb, void *data)
2750fad09c73SVivien Didelot {
2751dabc1a96SVivien Didelot 	struct mv88e6xxx_atu_entry addr;
27522bedde1aSArkadi Sharshevsky 	bool is_static;
2753fad09c73SVivien Didelot 	int err;
2754fad09c73SVivien Didelot 
2755d8291a95SVivien Didelot 	addr.state = 0;
2756dabc1a96SVivien Didelot 	eth_broadcast_addr(addr.mac);
2757fad09c73SVivien Didelot 
2758fad09c73SVivien Didelot 	do {
2759dabc1a96SVivien Didelot 		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
2760fad09c73SVivien Didelot 		if (err)
276183dabd1fSVivien Didelot 			return err;
2762fad09c73SVivien Didelot 
2763d8291a95SVivien Didelot 		if (!addr.state)
2764fad09c73SVivien Didelot 			break;
2765fad09c73SVivien Didelot 
276601bd96c8SVivien Didelot 		if (addr.trunk || (addr.portvec & BIT(port)) == 0)
276783dabd1fSVivien Didelot 			continue;
2768fad09c73SVivien Didelot 
276983dabd1fSVivien Didelot 		if (!is_unicast_ether_addr(addr.mac))
277083dabd1fSVivien Didelot 			continue;
277183dabd1fSVivien Didelot 
27722bedde1aSArkadi Sharshevsky 		is_static = (addr.state ==
27732bedde1aSArkadi Sharshevsky 			     MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
27742bedde1aSArkadi Sharshevsky 		err = cb(addr.mac, vid, is_static, data);
277583dabd1fSVivien Didelot 		if (err)
277683dabd1fSVivien Didelot 			return err;
2777fad09c73SVivien Didelot 	} while (!is_broadcast_ether_addr(addr.mac));
2778fad09c73SVivien Didelot 
2779fad09c73SVivien Didelot 	return err;
2780fad09c73SVivien Didelot }
2781fad09c73SVivien Didelot 
2782d89ef4b8STobias Waldekranz struct mv88e6xxx_port_db_dump_vlan_ctx {
2783d89ef4b8STobias Waldekranz 	int port;
2784d89ef4b8STobias Waldekranz 	dsa_fdb_dump_cb_t *cb;
2785d89ef4b8STobias Waldekranz 	void *data;
2786d89ef4b8STobias Waldekranz };
2787d89ef4b8STobias Waldekranz 
2788d89ef4b8STobias Waldekranz static int mv88e6xxx_port_db_dump_vlan(struct mv88e6xxx_chip *chip,
2789d89ef4b8STobias Waldekranz 				       const struct mv88e6xxx_vtu_entry *entry,
2790d89ef4b8STobias Waldekranz 				       void *_data)
2791d89ef4b8STobias Waldekranz {
2792d89ef4b8STobias Waldekranz 	struct mv88e6xxx_port_db_dump_vlan_ctx *ctx = _data;
2793d89ef4b8STobias Waldekranz 
2794d89ef4b8STobias Waldekranz 	return mv88e6xxx_port_db_dump_fid(chip, entry->fid, entry->vid,
2795d89ef4b8STobias Waldekranz 					  ctx->port, ctx->cb, ctx->data);
2796d89ef4b8STobias Waldekranz }
2797d89ef4b8STobias Waldekranz 
279883dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
27992bedde1aSArkadi Sharshevsky 				  dsa_fdb_dump_cb_t *cb, void *data)
280083dabd1fSVivien Didelot {
2801d89ef4b8STobias Waldekranz 	struct mv88e6xxx_port_db_dump_vlan_ctx ctx = {
2802d89ef4b8STobias Waldekranz 		.port = port,
2803d89ef4b8STobias Waldekranz 		.cb = cb,
2804d89ef4b8STobias Waldekranz 		.data = data,
2805d89ef4b8STobias Waldekranz 	};
280683dabd1fSVivien Didelot 	u16 fid;
280783dabd1fSVivien Didelot 	int err;
280883dabd1fSVivien Didelot 
280983dabd1fSVivien Didelot 	/* Dump port's default Filtering Information Database (VLAN ID 0) */
2810b4e48c50SVivien Didelot 	err = mv88e6xxx_port_get_fid(chip, port, &fid);
281183dabd1fSVivien Didelot 	if (err)
281283dabd1fSVivien Didelot 		return err;
281383dabd1fSVivien Didelot 
28142bedde1aSArkadi Sharshevsky 	err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data);
281583dabd1fSVivien Didelot 	if (err)
281683dabd1fSVivien Didelot 		return err;
281783dabd1fSVivien Didelot 
2818d89ef4b8STobias Waldekranz 	return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_db_dump_vlan, &ctx);
281983dabd1fSVivien Didelot }
282083dabd1fSVivien Didelot 
2821fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
28222bedde1aSArkadi Sharshevsky 				   dsa_fdb_dump_cb_t *cb, void *data)
2823fad09c73SVivien Didelot {
282404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2825fcf15367SVivien Didelot 	int err;
2826fad09c73SVivien Didelot 
2827c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2828fcf15367SVivien Didelot 	err = mv88e6xxx_port_db_dump(chip, port, cb, data);
2829c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2830fcf15367SVivien Didelot 
2831fcf15367SVivien Didelot 	return err;
2832fad09c73SVivien Didelot }
2833fad09c73SVivien Didelot 
2834240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
2835d3eed0e5SVladimir Oltean 				struct dsa_bridge bridge)
2836240ea3efSVivien Didelot {
2837ef2025ecSVivien Didelot 	struct dsa_switch *ds = chip->ds;
2838ef2025ecSVivien Didelot 	struct dsa_switch_tree *dst = ds->dst;
2839ef2025ecSVivien Didelot 	struct dsa_port *dp;
2840240ea3efSVivien Didelot 	int err;
2841240ea3efSVivien Didelot 
2842ef2025ecSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list) {
2843d3eed0e5SVladimir Oltean 		if (dsa_port_offloads_bridge(dp, &bridge)) {
2844ef2025ecSVivien Didelot 			if (dp->ds == ds) {
2845ef2025ecSVivien Didelot 				/* This is a local bridge group member,
2846ef2025ecSVivien Didelot 				 * remap its Port VLAN Map.
2847ef2025ecSVivien Didelot 				 */
2848ef2025ecSVivien Didelot 				err = mv88e6xxx_port_vlan_map(chip, dp->index);
2849240ea3efSVivien Didelot 				if (err)
2850240ea3efSVivien Didelot 					return err;
2851ef2025ecSVivien Didelot 			} else {
2852ef2025ecSVivien Didelot 				/* This is an external bridge group member,
2853ef2025ecSVivien Didelot 				 * remap its cross-chip Port VLAN Table entry.
2854ef2025ecSVivien Didelot 				 */
2855ef2025ecSVivien Didelot 				err = mv88e6xxx_pvt_map(chip, dp->ds->index,
2856ef2025ecSVivien Didelot 							dp->index);
2857e96a6e02SVivien Didelot 				if (err)
2858e96a6e02SVivien Didelot 					return err;
2859e96a6e02SVivien Didelot 			}
2860e96a6e02SVivien Didelot 		}
2861e96a6e02SVivien Didelot 	}
2862e96a6e02SVivien Didelot 
2863240ea3efSVivien Didelot 	return 0;
2864240ea3efSVivien Didelot }
2865240ea3efSVivien Didelot 
2866857fdd74SVladimir Oltean /* Treat the software bridge as a virtual single-port switch behind the
2867857fdd74SVladimir Oltean  * CPU and map in the PVT. First dst->last_switch elements are taken by
2868857fdd74SVladimir Oltean  * physical switches, so start from beyond that range.
2869857fdd74SVladimir Oltean  */
2870857fdd74SVladimir Oltean static int mv88e6xxx_map_virtual_bridge_to_pvt(struct dsa_switch *ds,
2871857fdd74SVladimir Oltean 					       unsigned int bridge_num)
2872857fdd74SVladimir Oltean {
2873857fdd74SVladimir Oltean 	u8 dev = bridge_num + ds->dst->last_switch;
2874857fdd74SVladimir Oltean 	struct mv88e6xxx_chip *chip = ds->priv;
2875857fdd74SVladimir Oltean 
2876857fdd74SVladimir Oltean 	return mv88e6xxx_pvt_map(chip, dev, 0);
2877857fdd74SVladimir Oltean }
2878857fdd74SVladimir Oltean 
2879fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
2880b079922bSVladimir Oltean 				      struct dsa_bridge bridge,
288106b9cce4SVladimir Oltean 				      bool *tx_fwd_offload,
288206b9cce4SVladimir Oltean 				      struct netlink_ext_ack *extack)
2883fad09c73SVivien Didelot {
288404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2885240ea3efSVivien Didelot 	int err;
2886fad09c73SVivien Didelot 
2887c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
28885bded825SVladimir Oltean 
2889d3eed0e5SVladimir Oltean 	err = mv88e6xxx_bridge_map(chip, bridge);
28905bded825SVladimir Oltean 	if (err)
28915bded825SVladimir Oltean 		goto unlock;
28925bded825SVladimir Oltean 
28937af4a361STobias Waldekranz 	err = mv88e6xxx_port_set_map_da(chip, port, true);
28947af4a361STobias Waldekranz 	if (err)
2895ff624338SDan Carpenter 		goto unlock;
28967af4a361STobias Waldekranz 
28975bded825SVladimir Oltean 	err = mv88e6xxx_port_commit_pvid(chip, port);
28985bded825SVladimir Oltean 	if (err)
28995bded825SVladimir Oltean 		goto unlock;
29005bded825SVladimir Oltean 
2901857fdd74SVladimir Oltean 	if (mv88e6xxx_has_pvt(chip)) {
2902857fdd74SVladimir Oltean 		err = mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num);
2903857fdd74SVladimir Oltean 		if (err)
2904857fdd74SVladimir Oltean 			goto unlock;
2905857fdd74SVladimir Oltean 
2906857fdd74SVladimir Oltean 		*tx_fwd_offload = true;
2907857fdd74SVladimir Oltean 	}
2908857fdd74SVladimir Oltean 
29095bded825SVladimir Oltean unlock:
2910c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2911fad09c73SVivien Didelot 
2912fad09c73SVivien Didelot 	return err;
2913fad09c73SVivien Didelot }
2914fad09c73SVivien Didelot 
2915f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
2916d3eed0e5SVladimir Oltean 					struct dsa_bridge bridge)
2917fad09c73SVivien Didelot {
291804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
29195bded825SVladimir Oltean 	int err;
2920fad09c73SVivien Didelot 
2921c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
29225bded825SVladimir Oltean 
2923857fdd74SVladimir Oltean 	if (bridge.tx_fwd_offload &&
2924857fdd74SVladimir Oltean 	    mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num))
2925857fdd74SVladimir Oltean 		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
2926857fdd74SVladimir Oltean 
2927d3eed0e5SVladimir Oltean 	if (mv88e6xxx_bridge_map(chip, bridge) ||
2928240ea3efSVivien Didelot 	    mv88e6xxx_port_vlan_map(chip, port))
2929240ea3efSVivien Didelot 		dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
29305bded825SVladimir Oltean 
29317af4a361STobias Waldekranz 	err = mv88e6xxx_port_set_map_da(chip, port, false);
29327af4a361STobias Waldekranz 	if (err)
29337af4a361STobias Waldekranz 		dev_err(ds->dev,
29347af4a361STobias Waldekranz 			"port %d failed to restore map-DA: %pe\n",
29357af4a361STobias Waldekranz 			port, ERR_PTR(err));
29367af4a361STobias Waldekranz 
29375bded825SVladimir Oltean 	err = mv88e6xxx_port_commit_pvid(chip, port);
29385bded825SVladimir Oltean 	if (err)
29395bded825SVladimir Oltean 		dev_err(ds->dev,
29405bded825SVladimir Oltean 			"port %d failed to restore standalone pvid: %pe\n",
29415bded825SVladimir Oltean 			port, ERR_PTR(err));
29425bded825SVladimir Oltean 
2943c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2944fad09c73SVivien Didelot }
2945fad09c73SVivien Didelot 
2946f66a6a69SVladimir Oltean static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds,
2947f66a6a69SVladimir Oltean 					   int tree_index, int sw_index,
294806b9cce4SVladimir Oltean 					   int port, struct dsa_bridge bridge,
294906b9cce4SVladimir Oltean 					   struct netlink_ext_ack *extack)
2950aec5ac88SVivien Didelot {
2951aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2952aec5ac88SVivien Didelot 	int err;
2953aec5ac88SVivien Didelot 
2954f66a6a69SVladimir Oltean 	if (tree_index != ds->dst->index)
2955f66a6a69SVladimir Oltean 		return 0;
2956f66a6a69SVladimir Oltean 
2957c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2958f66a6a69SVladimir Oltean 	err = mv88e6xxx_pvt_map(chip, sw_index, port);
2959e0068620STobias Waldekranz 	err = err ? : mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num);
2960c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2961aec5ac88SVivien Didelot 
2962aec5ac88SVivien Didelot 	return err;
2963aec5ac88SVivien Didelot }
2964aec5ac88SVivien Didelot 
2965f66a6a69SVladimir Oltean static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds,
2966f66a6a69SVladimir Oltean 					     int tree_index, int sw_index,
2967d3eed0e5SVladimir Oltean 					     int port, struct dsa_bridge bridge)
2968aec5ac88SVivien Didelot {
2969aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2970aec5ac88SVivien Didelot 
2971f66a6a69SVladimir Oltean 	if (tree_index != ds->dst->index)
2972f66a6a69SVladimir Oltean 		return;
2973f66a6a69SVladimir Oltean 
2974c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2975e0068620STobias Waldekranz 	if (mv88e6xxx_pvt_map(chip, sw_index, port) ||
2976e0068620STobias Waldekranz 	    mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num))
2977aec5ac88SVivien Didelot 		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
2978c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2979aec5ac88SVivien Didelot }
2980aec5ac88SVivien Didelot 
298117e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
298217e708baSVivien Didelot {
298317e708baSVivien Didelot 	if (chip->info->ops->reset)
298417e708baSVivien Didelot 		return chip->info->ops->reset(chip);
298517e708baSVivien Didelot 
298617e708baSVivien Didelot 	return 0;
298717e708baSVivien Didelot }
298817e708baSVivien Didelot 
2989309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
2990309eca6dSVivien Didelot {
2991309eca6dSVivien Didelot 	struct gpio_desc *gpiod = chip->reset;
2992309eca6dSVivien Didelot 
2993309eca6dSVivien Didelot 	/* If there is a GPIO connected to the reset pin, toggle it */
2994309eca6dSVivien Didelot 	if (gpiod) {
2995309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 1);
2996309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2997309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 0);
2998309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2999a3dcb3e7SAndrew Lunn 
3000a3dcb3e7SAndrew Lunn 		mv88e6xxx_g1_wait_eeprom_done(chip);
3001309eca6dSVivien Didelot 	}
3002309eca6dSVivien Didelot }
3003309eca6dSVivien Didelot 
30044ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
30054ac4b5a6SVivien Didelot {
30064ac4b5a6SVivien Didelot 	int i, err;
30074ac4b5a6SVivien Didelot 
30084ac4b5a6SVivien Didelot 	/* Set all ports to the Disabled state */
30094ac4b5a6SVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
3010f894c29cSVivien Didelot 		err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED);
30114ac4b5a6SVivien Didelot 		if (err)
30124ac4b5a6SVivien Didelot 			return err;
30134ac4b5a6SVivien Didelot 	}
30144ac4b5a6SVivien Didelot 
30154ac4b5a6SVivien Didelot 	/* Wait for transmit queues to drain,
30164ac4b5a6SVivien Didelot 	 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
30174ac4b5a6SVivien Didelot 	 */
30184ac4b5a6SVivien Didelot 	usleep_range(2000, 4000);
30194ac4b5a6SVivien Didelot 
30204ac4b5a6SVivien Didelot 	return 0;
30214ac4b5a6SVivien Didelot }
30224ac4b5a6SVivien Didelot 
3023fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
3024fad09c73SVivien Didelot {
3025a935c052SVivien Didelot 	int err;
3026fad09c73SVivien Didelot 
30274ac4b5a6SVivien Didelot 	err = mv88e6xxx_disable_ports(chip);
30280e7b9925SAndrew Lunn 	if (err)
30290e7b9925SAndrew Lunn 		return err;
3030fad09c73SVivien Didelot 
3031309eca6dSVivien Didelot 	mv88e6xxx_hardware_reset(chip);
3032fad09c73SVivien Didelot 
303317e708baSVivien Didelot 	return mv88e6xxx_software_reset(chip);
3034fad09c73SVivien Didelot }
3035fad09c73SVivien Didelot 
30364314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
303731bef4e9SVivien Didelot 				   enum mv88e6xxx_frame_mode frame,
303831bef4e9SVivien Didelot 				   enum mv88e6xxx_egress_mode egress, u16 etype)
303956995cbcSAndrew Lunn {
304056995cbcSAndrew Lunn 	int err;
304156995cbcSAndrew Lunn 
30424314557cSVivien Didelot 	if (!chip->info->ops->port_set_frame_mode)
30434314557cSVivien Didelot 		return -EOPNOTSUPP;
30444314557cSVivien Didelot 
30454314557cSVivien Didelot 	err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
304656995cbcSAndrew Lunn 	if (err)
304756995cbcSAndrew Lunn 		return err;
304856995cbcSAndrew Lunn 
30494314557cSVivien Didelot 	err = chip->info->ops->port_set_frame_mode(chip, port, frame);
30504314557cSVivien Didelot 	if (err)
30514314557cSVivien Didelot 		return err;
30524314557cSVivien Didelot 
30534314557cSVivien Didelot 	if (chip->info->ops->port_set_ether_type)
30544314557cSVivien Didelot 		return chip->info->ops->port_set_ether_type(chip, port, etype);
30554314557cSVivien Didelot 
30564314557cSVivien Didelot 	return 0;
30574314557cSVivien Didelot }
30584314557cSVivien Didelot 
30594314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
30604314557cSVivien Didelot {
30614314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
306231bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
3063b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
30644314557cSVivien Didelot }
30654314557cSVivien Didelot 
30664314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
30674314557cSVivien Didelot {
30684314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
306931bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
3070b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
30714314557cSVivien Didelot }
30724314557cSVivien Didelot 
30734314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
30744314557cSVivien Didelot {
30754314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port,
30764314557cSVivien Didelot 				       MV88E6XXX_FRAME_MODE_ETHERTYPE,
307731bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_ETHERTYPE,
307831bef4e9SVivien Didelot 				       ETH_P_EDSA);
30794314557cSVivien Didelot }
30804314557cSVivien Didelot 
30814314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port)
30824314557cSVivien Didelot {
30834314557cSVivien Didelot 	if (dsa_is_dsa_port(chip->ds, port))
30844314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
30854314557cSVivien Didelot 
30862b3e9891SVivien Didelot 	if (dsa_is_user_port(chip->ds, port))
30874314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_normal(chip, port);
30884314557cSVivien Didelot 
30894314557cSVivien Didelot 	/* Setup CPU port mode depending on its supported tag format */
3090670bb80fSTobias Waldekranz 	if (chip->tag_protocol == DSA_TAG_PROTO_DSA)
30914314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
30924314557cSVivien Didelot 
3093670bb80fSTobias Waldekranz 	if (chip->tag_protocol == DSA_TAG_PROTO_EDSA)
30944314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_edsa(chip, port);
30954314557cSVivien Didelot 
30964314557cSVivien Didelot 	return -EINVAL;
30974314557cSVivien Didelot }
30984314557cSVivien Didelot 
3099ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
3100ea698f4fSVivien Didelot {
3101ea698f4fSVivien Didelot 	bool message = dsa_is_dsa_port(chip->ds, port);
3102ea698f4fSVivien Didelot 
3103ea698f4fSVivien Didelot 	return mv88e6xxx_port_set_message_port(chip, port, message);
3104ea698f4fSVivien Didelot }
3105ea698f4fSVivien Didelot 
3106601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
3107601aeed3SVivien Didelot {
3108a8b659e7SVladimir Oltean 	int err;
3109601aeed3SVivien Didelot 
3110a8b659e7SVladimir Oltean 	if (chip->info->ops->port_set_ucast_flood) {
31117b9f16feSTobias Waldekranz 		err = chip->info->ops->port_set_ucast_flood(chip, port, true);
3112a8b659e7SVladimir Oltean 		if (err)
3113a8b659e7SVladimir Oltean 			return err;
3114a8b659e7SVladimir Oltean 	}
3115a8b659e7SVladimir Oltean 	if (chip->info->ops->port_set_mcast_flood) {
31167b9f16feSTobias Waldekranz 		err = chip->info->ops->port_set_mcast_flood(chip, port, true);
3117a8b659e7SVladimir Oltean 		if (err)
3118a8b659e7SVladimir Oltean 			return err;
3119a8b659e7SVladimir Oltean 	}
3120407308f6SDavid S. Miller 
3121601aeed3SVivien Didelot 	return 0;
3122601aeed3SVivien Didelot }
3123601aeed3SVivien Didelot 
312445de77ffSVivien Didelot static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
312545de77ffSVivien Didelot {
312645de77ffSVivien Didelot 	struct mv88e6xxx_port *mvp = dev_id;
312745de77ffSVivien Didelot 	struct mv88e6xxx_chip *chip = mvp->chip;
312845de77ffSVivien Didelot 	irqreturn_t ret = IRQ_NONE;
312945de77ffSVivien Didelot 	int port = mvp->port;
3130193c5b26SPavana Sharma 	int lane;
313145de77ffSVivien Didelot 
313245de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
313345de77ffSVivien Didelot 	lane = mv88e6xxx_serdes_get_lane(chip, port);
3134193c5b26SPavana Sharma 	if (lane >= 0)
313545de77ffSVivien Didelot 		ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
313645de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
313745de77ffSVivien Didelot 
313845de77ffSVivien Didelot 	return ret;
313945de77ffSVivien Didelot }
314045de77ffSVivien Didelot 
314145de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
3142193c5b26SPavana Sharma 					int lane)
314345de77ffSVivien Didelot {
314445de77ffSVivien Didelot 	struct mv88e6xxx_port *dev_id = &chip->ports[port];
314545de77ffSVivien Didelot 	unsigned int irq;
314645de77ffSVivien Didelot 	int err;
314745de77ffSVivien Didelot 
314845de77ffSVivien Didelot 	/* Nothing to request if this SERDES port has no IRQ */
314945de77ffSVivien Didelot 	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
315045de77ffSVivien Didelot 	if (!irq)
315145de77ffSVivien Didelot 		return 0;
315245de77ffSVivien Didelot 
3153e6f2f6b8SAndrew Lunn 	snprintf(dev_id->serdes_irq_name, sizeof(dev_id->serdes_irq_name),
3154e6f2f6b8SAndrew Lunn 		 "mv88e6xxx-%s-serdes-%d", dev_name(chip->dev), port);
3155e6f2f6b8SAndrew Lunn 
315645de77ffSVivien Didelot 	/* Requesting the IRQ will trigger IRQ callbacks, so release the lock */
315745de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
315845de77ffSVivien Didelot 	err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn,
3159e6f2f6b8SAndrew Lunn 				   IRQF_ONESHOT, dev_id->serdes_irq_name,
3160e6f2f6b8SAndrew Lunn 				   dev_id);
316145de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
316245de77ffSVivien Didelot 	if (err)
316345de77ffSVivien Didelot 		return err;
316445de77ffSVivien Didelot 
316545de77ffSVivien Didelot 	dev_id->serdes_irq = irq;
316645de77ffSVivien Didelot 
316745de77ffSVivien Didelot 	return mv88e6xxx_serdes_irq_enable(chip, port, lane);
316845de77ffSVivien Didelot }
316945de77ffSVivien Didelot 
317045de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
3171193c5b26SPavana Sharma 				     int lane)
317245de77ffSVivien Didelot {
317345de77ffSVivien Didelot 	struct mv88e6xxx_port *dev_id = &chip->ports[port];
317445de77ffSVivien Didelot 	unsigned int irq = dev_id->serdes_irq;
317545de77ffSVivien Didelot 	int err;
317645de77ffSVivien Didelot 
317745de77ffSVivien Didelot 	/* Nothing to free if no IRQ has been requested */
317845de77ffSVivien Didelot 	if (!irq)
317945de77ffSVivien Didelot 		return 0;
318045de77ffSVivien Didelot 
318145de77ffSVivien Didelot 	err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
318245de77ffSVivien Didelot 
318345de77ffSVivien Didelot 	/* Freeing the IRQ will trigger IRQ callbacks, so release the lock */
318445de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
318545de77ffSVivien Didelot 	free_irq(irq, dev_id);
318645de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
318745de77ffSVivien Didelot 
318845de77ffSVivien Didelot 	dev_id->serdes_irq = 0;
318945de77ffSVivien Didelot 
319045de77ffSVivien Didelot 	return err;
319145de77ffSVivien Didelot }
319245de77ffSVivien Didelot 
31936d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
31946d91782fSAndrew Lunn 				  bool on)
31956d91782fSAndrew Lunn {
3196193c5b26SPavana Sharma 	int lane;
3197fc0bc019SVivien Didelot 	int err;
31986d91782fSAndrew Lunn 
3199dc272f60SVivien Didelot 	lane = mv88e6xxx_serdes_get_lane(chip, port);
3200193c5b26SPavana Sharma 	if (lane < 0)
3201523a8904SVivien Didelot 		return 0;
3202fc0bc019SVivien Didelot 
3203fc0bc019SVivien Didelot 	if (on) {
3204dc272f60SVivien Didelot 		err = mv88e6xxx_serdes_power_up(chip, port, lane);
3205fc0bc019SVivien Didelot 		if (err)
3206fc0bc019SVivien Didelot 			return err;
3207fc0bc019SVivien Didelot 
320845de77ffSVivien Didelot 		err = mv88e6xxx_serdes_irq_request(chip, port, lane);
3209fc0bc019SVivien Didelot 	} else {
321045de77ffSVivien Didelot 		err = mv88e6xxx_serdes_irq_free(chip, port, lane);
321145de77ffSVivien Didelot 		if (err)
321245de77ffSVivien Didelot 			return err;
3213fc0bc019SVivien Didelot 
3214dc272f60SVivien Didelot 		err = mv88e6xxx_serdes_power_down(chip, port, lane);
3215fc0bc019SVivien Didelot 	}
3216fc0bc019SVivien Didelot 
3217fc0bc019SVivien Didelot 	return err;
32186d91782fSAndrew Lunn }
32196d91782fSAndrew Lunn 
32202fda45f0SMarek Behún static int mv88e6xxx_set_egress_port(struct mv88e6xxx_chip *chip,
32212fda45f0SMarek Behún 				     enum mv88e6xxx_egress_direction direction,
32222fda45f0SMarek Behún 				     int port)
32232fda45f0SMarek Behún {
32242fda45f0SMarek Behún 	int err;
32252fda45f0SMarek Behún 
32262fda45f0SMarek Behún 	if (!chip->info->ops->set_egress_port)
32272fda45f0SMarek Behún 		return -EOPNOTSUPP;
32282fda45f0SMarek Behún 
32292fda45f0SMarek Behún 	err = chip->info->ops->set_egress_port(chip, direction, port);
32302fda45f0SMarek Behún 	if (err)
32312fda45f0SMarek Behún 		return err;
32322fda45f0SMarek Behún 
32332fda45f0SMarek Behún 	if (direction == MV88E6XXX_EGRESS_DIR_INGRESS)
32342fda45f0SMarek Behún 		chip->ingress_dest_port = port;
32352fda45f0SMarek Behún 	else
32362fda45f0SMarek Behún 		chip->egress_dest_port = port;
32372fda45f0SMarek Behún 
32382fda45f0SMarek Behún 	return 0;
32392fda45f0SMarek Behún }
32402fda45f0SMarek Behún 
3241fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
3242fa371c80SVivien Didelot {
3243fa371c80SVivien Didelot 	struct dsa_switch *ds = chip->ds;
3244fa371c80SVivien Didelot 	int upstream_port;
3245fa371c80SVivien Didelot 	int err;
3246fa371c80SVivien Didelot 
324707073c79SVivien Didelot 	upstream_port = dsa_upstream_port(ds, port);
3248fa371c80SVivien Didelot 	if (chip->info->ops->port_set_upstream_port) {
3249fa371c80SVivien Didelot 		err = chip->info->ops->port_set_upstream_port(chip, port,
3250fa371c80SVivien Didelot 							      upstream_port);
3251fa371c80SVivien Didelot 		if (err)
3252fa371c80SVivien Didelot 			return err;
3253fa371c80SVivien Didelot 	}
3254fa371c80SVivien Didelot 
32550ea54ddaSVivien Didelot 	if (port == upstream_port) {
32560ea54ddaSVivien Didelot 		if (chip->info->ops->set_cpu_port) {
32570ea54ddaSVivien Didelot 			err = chip->info->ops->set_cpu_port(chip,
32580ea54ddaSVivien Didelot 							    upstream_port);
32590ea54ddaSVivien Didelot 			if (err)
32600ea54ddaSVivien Didelot 				return err;
32610ea54ddaSVivien Didelot 		}
32620ea54ddaSVivien Didelot 
32632fda45f0SMarek Behún 		err = mv88e6xxx_set_egress_port(chip,
32645c74c54cSIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS,
32655c74c54cSIwan R Timmer 						upstream_port);
32662fda45f0SMarek Behún 		if (err && err != -EOPNOTSUPP)
32675c74c54cSIwan R Timmer 			return err;
32685c74c54cSIwan R Timmer 
32692fda45f0SMarek Behún 		err = mv88e6xxx_set_egress_port(chip,
32705c74c54cSIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS,
32710ea54ddaSVivien Didelot 						upstream_port);
32722fda45f0SMarek Behún 		if (err && err != -EOPNOTSUPP)
32730ea54ddaSVivien Didelot 			return err;
32740ea54ddaSVivien Didelot 	}
32750ea54ddaSVivien Didelot 
3276fa371c80SVivien Didelot 	return 0;
3277fa371c80SVivien Didelot }
3278fa371c80SVivien Didelot 
3279fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
3280fad09c73SVivien Didelot {
3281926eae60SHolger Brunck 	struct device_node *phy_handle = NULL;
3282fad09c73SVivien Didelot 	struct dsa_switch *ds = chip->ds;
3283926eae60SHolger Brunck 	struct dsa_port *dp;
3284926eae60SHolger Brunck 	int tx_amp;
32850e7b9925SAndrew Lunn 	int err;
3286fad09c73SVivien Didelot 	u16 reg;
3287fad09c73SVivien Didelot 
32887b898469SAndrew Lunn 	chip->ports[port].chip = chip;
32897b898469SAndrew Lunn 	chip->ports[port].port = port;
32907b898469SAndrew Lunn 
3291d78343d2SVivien Didelot 	/* MAC Forcing register: don't force link, speed, duplex or flow control
3292d78343d2SVivien Didelot 	 * state to any particular values on physical ports, but force the CPU
3293d78343d2SVivien Didelot 	 * port and all DSA ports to their maximum bandwidth and full duplex.
3294fad09c73SVivien Didelot 	 */
3295d78343d2SVivien Didelot 	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
3296d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
3297d78343d2SVivien Didelot 					       SPEED_MAX, DUPLEX_FULL,
329854186b91SAndrew Lunn 					       PAUSE_OFF,
3299d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
3300fad09c73SVivien Didelot 	else
3301d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
3302d78343d2SVivien Didelot 					       SPEED_UNFORCED, DUPLEX_UNFORCED,
330354186b91SAndrew Lunn 					       PAUSE_ON,
3304d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
33050e7b9925SAndrew Lunn 	if (err)
33060e7b9925SAndrew Lunn 		return err;
3307fad09c73SVivien Didelot 
3308fad09c73SVivien Didelot 	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
3309fad09c73SVivien Didelot 	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
3310fad09c73SVivien Didelot 	 * tunneling, determine priority by looking at 802.1p and IP
3311fad09c73SVivien Didelot 	 * priority fields (IP prio has precedence), and set STP state
3312fad09c73SVivien Didelot 	 * to Forwarding.
3313fad09c73SVivien Didelot 	 *
3314fad09c73SVivien Didelot 	 * If this is the CPU link, use DSA or EDSA tagging depending
3315fad09c73SVivien Didelot 	 * on which tagging mode was configured.
3316fad09c73SVivien Didelot 	 *
3317fad09c73SVivien Didelot 	 * If this is a link to another switch, use DSA tagging mode.
3318fad09c73SVivien Didelot 	 *
3319fad09c73SVivien Didelot 	 * If this is the upstream port for this switch, enable
3320fad09c73SVivien Didelot 	 * forwarding of unknown unicasts and multicasts.
3321fad09c73SVivien Didelot 	 */
3322a89b433bSVivien Didelot 	reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP |
3323a89b433bSVivien Didelot 		MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
3324a89b433bSVivien Didelot 		MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
3325a89b433bSVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
33260e7b9925SAndrew Lunn 	if (err)
33270e7b9925SAndrew Lunn 		return err;
332856995cbcSAndrew Lunn 
3329601aeed3SVivien Didelot 	err = mv88e6xxx_setup_port_mode(chip, port);
333056995cbcSAndrew Lunn 	if (err)
333156995cbcSAndrew Lunn 		return err;
3332fad09c73SVivien Didelot 
3333601aeed3SVivien Didelot 	err = mv88e6xxx_setup_egress_floods(chip, port);
33344314557cSVivien Didelot 	if (err)
33354314557cSVivien Didelot 		return err;
33364314557cSVivien Didelot 
3337b92ce2f5SAndrew Lunn 	/* Port Control 2: don't force a good FCS, set the MTU size to
33387af4a361STobias Waldekranz 	 * 10222 bytes, disable 802.1q tags checking, don't discard
33397af4a361STobias Waldekranz 	 * tagged or untagged frames on this port, skip destination
33407af4a361STobias Waldekranz 	 * address lookup on user ports, disable ARP mirroring and don't
33417af4a361STobias Waldekranz 	 * send a copy of all transmitted/received frames on this port
33427af4a361STobias Waldekranz 	 * to the CPU.
3343fad09c73SVivien Didelot 	 */
33447af4a361STobias Waldekranz 	err = mv88e6xxx_port_set_map_da(chip, port, !dsa_is_user_port(ds, port));
3345a23b2961SAndrew Lunn 	if (err)
3346a23b2961SAndrew Lunn 		return err;
3347a23b2961SAndrew Lunn 
3348fa371c80SVivien Didelot 	err = mv88e6xxx_setup_upstream_port(chip, port);
33490e7b9925SAndrew Lunn 	if (err)
33500e7b9925SAndrew Lunn 		return err;
3351fad09c73SVivien Didelot 
3352d352b20fSTobias Waldekranz 	/* On chips that support it, set all downstream DSA ports'
3353d352b20fSTobias Waldekranz 	 * VLAN policy to TRAP. In combination with loading
3354d352b20fSTobias Waldekranz 	 * MV88E6XXX_VID_STANDALONE as a policy entry in the VTU, this
3355d352b20fSTobias Waldekranz 	 * provides a better isolation barrier between standalone
3356d352b20fSTobias Waldekranz 	 * ports, as the ATU is bypassed on any intermediate switches
3357d352b20fSTobias Waldekranz 	 * between the incoming port and the CPU.
3358d352b20fSTobias Waldekranz 	 */
3359d352b20fSTobias Waldekranz 	if (dsa_is_downstream_port(ds, port) &&
3360d352b20fSTobias Waldekranz 	    chip->info->ops->port_set_policy) {
3361d352b20fSTobias Waldekranz 		err = chip->info->ops->port_set_policy(chip, port,
3362d352b20fSTobias Waldekranz 						MV88E6XXX_POLICY_MAPPING_VTU,
3363d352b20fSTobias Waldekranz 						MV88E6XXX_POLICY_ACTION_TRAP);
3364d352b20fSTobias Waldekranz 		if (err)
3365d352b20fSTobias Waldekranz 			return err;
3366d352b20fSTobias Waldekranz 	}
3367d352b20fSTobias Waldekranz 
3368d352b20fSTobias Waldekranz 	/* User ports start out in standalone mode and 802.1Q is
3369d352b20fSTobias Waldekranz 	 * therefore disabled. On DSA ports, all valid VIDs are always
3370d352b20fSTobias Waldekranz 	 * loaded in the VTU - therefore, enable 802.1Q in order to take
3371d352b20fSTobias Waldekranz 	 * advantage of VLAN policy on chips that supports it.
3372d352b20fSTobias Waldekranz 	 */
3373a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_8021q_mode(chip, port,
3374d352b20fSTobias Waldekranz 				dsa_is_user_port(ds, port) ?
3375d352b20fSTobias Waldekranz 				MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED :
3376d352b20fSTobias Waldekranz 				MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE);
3377d352b20fSTobias Waldekranz 	if (err)
3378d352b20fSTobias Waldekranz 		return err;
3379d352b20fSTobias Waldekranz 
3380d352b20fSTobias Waldekranz 	/* Bind MV88E6XXX_VID_STANDALONE to MV88E6XXX_FID_STANDALONE by
3381d352b20fSTobias Waldekranz 	 * virtue of the fact that mv88e6xxx_atu_new() will pick it as
3382d352b20fSTobias Waldekranz 	 * the first free FID. This will be used as the private PVID for
3383d352b20fSTobias Waldekranz 	 * unbridged ports. Shared (DSA and CPU) ports must also be
3384d352b20fSTobias Waldekranz 	 * members of this VID, in order to trap all frames assigned to
3385d352b20fSTobias Waldekranz 	 * it to the CPU.
3386d352b20fSTobias Waldekranz 	 */
3387d352b20fSTobias Waldekranz 	err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_STANDALONE,
3388d352b20fSTobias Waldekranz 				       MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED,
3389d352b20fSTobias Waldekranz 				       false);
3390a23b2961SAndrew Lunn 	if (err)
3391a23b2961SAndrew Lunn 		return err;
3392a23b2961SAndrew Lunn 
33935bded825SVladimir Oltean 	/* Associate MV88E6XXX_VID_BRIDGED with MV88E6XXX_FID_BRIDGED in the
33945bded825SVladimir Oltean 	 * ATU by virtue of the fact that mv88e6xxx_atu_new() will pick it as
33955bded825SVladimir Oltean 	 * the first free FID after MV88E6XXX_FID_STANDALONE. This will be used
33965bded825SVladimir Oltean 	 * as the private PVID on ports under a VLAN-unaware bridge.
33975bded825SVladimir Oltean 	 * Shared (DSA and CPU) ports must also be members of it, to translate
33985bded825SVladimir Oltean 	 * the VID from the DSA tag into MV88E6XXX_FID_BRIDGED, instead of
33995bded825SVladimir Oltean 	 * relying on their port default FID.
34005bded825SVladimir Oltean 	 */
34015bded825SVladimir Oltean 	err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_BRIDGED,
3402d352b20fSTobias Waldekranz 				       MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED,
34035bded825SVladimir Oltean 				       false);
34045bded825SVladimir Oltean 	if (err)
34055bded825SVladimir Oltean 		return err;
34065bded825SVladimir Oltean 
3407cd782656SVivien Didelot 	if (chip->info->ops->port_set_jumbo_size) {
3408b92ce2f5SAndrew Lunn 		err = chip->info->ops->port_set_jumbo_size(chip, port, 10218);
34095f436666SAndrew Lunn 		if (err)
34105f436666SAndrew Lunn 			return err;
34115f436666SAndrew Lunn 	}
34125f436666SAndrew Lunn 
3413041bd545STobias Waldekranz 	/* Port Association Vector: disable automatic address learning
3414041bd545STobias Waldekranz 	 * on all user ports since they start out in standalone
3415041bd545STobias Waldekranz 	 * mode. When joining a bridge, learning will be configured to
3416041bd545STobias Waldekranz 	 * match the bridge port settings. Enable learning on all
3417041bd545STobias Waldekranz 	 * DSA/CPU ports. NOTE: FROM_CPU frames always bypass the
3418041bd545STobias Waldekranz 	 * learning process.
3419041bd545STobias Waldekranz 	 *
3420041bd545STobias Waldekranz 	 * Disable HoldAt1, IntOnAgeOut, LockedPort, IgnoreWrongData,
3421041bd545STobias Waldekranz 	 * and RefreshLocked. I.e. setup standard automatic learning.
3422fad09c73SVivien Didelot 	 */
3423041bd545STobias Waldekranz 	if (dsa_is_user_port(ds, port))
3424fad09c73SVivien Didelot 		reg = 0;
3425041bd545STobias Waldekranz 	else
3426041bd545STobias Waldekranz 		reg = 1 << port;
3427fad09c73SVivien Didelot 
34282a4614e4SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
34292a4614e4SVivien Didelot 				   reg);
34300e7b9925SAndrew Lunn 	if (err)
34310e7b9925SAndrew Lunn 		return err;
3432fad09c73SVivien Didelot 
3433fad09c73SVivien Didelot 	/* Egress rate control 2: disable egress rate control. */
34342cb8cb14SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2,
34352cb8cb14SVivien Didelot 				   0x0000);
34360e7b9925SAndrew Lunn 	if (err)
34370e7b9925SAndrew Lunn 		return err;
3438fad09c73SVivien Didelot 
34390898432cSVivien Didelot 	if (chip->info->ops->port_pause_limit) {
34400898432cSVivien Didelot 		err = chip->info->ops->port_pause_limit(chip, port, 0, 0);
3441b35d322aSAndrew Lunn 		if (err)
3442b35d322aSAndrew Lunn 			return err;
3443b35d322aSAndrew Lunn 	}
3444b35d322aSAndrew Lunn 
3445c8c94891SVivien Didelot 	if (chip->info->ops->port_disable_learn_limit) {
3446c8c94891SVivien Didelot 		err = chip->info->ops->port_disable_learn_limit(chip, port);
3447c8c94891SVivien Didelot 		if (err)
3448c8c94891SVivien Didelot 			return err;
3449c8c94891SVivien Didelot 	}
3450c8c94891SVivien Didelot 
34519dbfb4e1SVivien Didelot 	if (chip->info->ops->port_disable_pri_override) {
34529dbfb4e1SVivien Didelot 		err = chip->info->ops->port_disable_pri_override(chip, port);
34530e7b9925SAndrew Lunn 		if (err)
34540e7b9925SAndrew Lunn 			return err;
3455ef0a7318SAndrew Lunn 	}
34562bbb33beSAndrew Lunn 
3457ef0a7318SAndrew Lunn 	if (chip->info->ops->port_tag_remap) {
3458ef0a7318SAndrew Lunn 		err = chip->info->ops->port_tag_remap(chip, port);
34590e7b9925SAndrew Lunn 		if (err)
34600e7b9925SAndrew Lunn 			return err;
3461fad09c73SVivien Didelot 	}
3462fad09c73SVivien Didelot 
3463ef70b111SAndrew Lunn 	if (chip->info->ops->port_egress_rate_limiting) {
3464ef70b111SAndrew Lunn 		err = chip->info->ops->port_egress_rate_limiting(chip, port);
34650e7b9925SAndrew Lunn 		if (err)
34660e7b9925SAndrew Lunn 			return err;
3467fad09c73SVivien Didelot 	}
3468fad09c73SVivien Didelot 
3469121b8fe2SHubert Feurstein 	if (chip->info->ops->port_setup_message_port) {
3470121b8fe2SHubert Feurstein 		err = chip->info->ops->port_setup_message_port(chip, port);
34710e7b9925SAndrew Lunn 		if (err)
34720e7b9925SAndrew Lunn 			return err;
3473121b8fe2SHubert Feurstein 	}
3474fad09c73SVivien Didelot 
3475926eae60SHolger Brunck 	if (chip->info->ops->serdes_set_tx_amplitude) {
3476926eae60SHolger Brunck 		dp = dsa_to_port(ds, port);
3477926eae60SHolger Brunck 		if (dp)
3478926eae60SHolger Brunck 			phy_handle = of_parse_phandle(dp->dn, "phy-handle", 0);
3479926eae60SHolger Brunck 
3480926eae60SHolger Brunck 		if (phy_handle && !of_property_read_u32(phy_handle,
3481926eae60SHolger Brunck 							"tx-p2p-microvolt",
3482926eae60SHolger Brunck 							&tx_amp))
3483926eae60SHolger Brunck 			err = chip->info->ops->serdes_set_tx_amplitude(chip,
3484926eae60SHolger Brunck 								port, tx_amp);
3485926eae60SHolger Brunck 		if (phy_handle) {
3486926eae60SHolger Brunck 			of_node_put(phy_handle);
3487926eae60SHolger Brunck 			if (err)
3488926eae60SHolger Brunck 				return err;
3489926eae60SHolger Brunck 		}
3490926eae60SHolger Brunck 	}
3491926eae60SHolger Brunck 
3492fad09c73SVivien Didelot 	/* Port based VLAN map: give each port the same default address
3493fad09c73SVivien Didelot 	 * database, and allow bidirectional communication between the
3494fad09c73SVivien Didelot 	 * CPU and DSA port(s), and the other ports.
3495fad09c73SVivien Didelot 	 */
34965bded825SVladimir Oltean 	err = mv88e6xxx_port_set_fid(chip, port, MV88E6XXX_FID_STANDALONE);
34970e7b9925SAndrew Lunn 	if (err)
34980e7b9925SAndrew Lunn 		return err;
3499fad09c73SVivien Didelot 
3500240ea3efSVivien Didelot 	err = mv88e6xxx_port_vlan_map(chip, port);
35010e7b9925SAndrew Lunn 	if (err)
35020e7b9925SAndrew Lunn 		return err;
3503fad09c73SVivien Didelot 
3504fad09c73SVivien Didelot 	/* Default VLAN ID and priority: don't set a default VLAN
3505fad09c73SVivien Didelot 	 * ID, and set the default packet priority to zero.
3506fad09c73SVivien Didelot 	 */
3507b7929fb3SVivien Didelot 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0);
3508fad09c73SVivien Didelot }
3509fad09c73SVivien Didelot 
35102a550aecSAndrew Lunn static int mv88e6xxx_get_max_mtu(struct dsa_switch *ds, int port)
35112a550aecSAndrew Lunn {
35122a550aecSAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
35132a550aecSAndrew Lunn 
35142a550aecSAndrew Lunn 	if (chip->info->ops->port_set_jumbo_size)
3515b9c587feSAndrew Lunn 		return 10240 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN;
35161baf0facSChris Packham 	else if (chip->info->ops->set_max_frame_size)
3517b9c587feSAndrew Lunn 		return 1632 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN;
3518b9c587feSAndrew Lunn 	return 1522 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN;
35192a550aecSAndrew Lunn }
35202a550aecSAndrew Lunn 
35212a550aecSAndrew Lunn static int mv88e6xxx_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
35222a550aecSAndrew Lunn {
35232a550aecSAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
35242a550aecSAndrew Lunn 	int ret = 0;
35252a550aecSAndrew Lunn 
3526b9c587feSAndrew Lunn 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
3527b9c587feSAndrew Lunn 		new_mtu += EDSA_HLEN;
3528b9c587feSAndrew Lunn 
35292a550aecSAndrew Lunn 	mv88e6xxx_reg_lock(chip);
35302a550aecSAndrew Lunn 	if (chip->info->ops->port_set_jumbo_size)
35312a550aecSAndrew Lunn 		ret = chip->info->ops->port_set_jumbo_size(chip, port, new_mtu);
35321baf0facSChris Packham 	else if (chip->info->ops->set_max_frame_size)
35331baf0facSChris Packham 		ret = chip->info->ops->set_max_frame_size(chip, new_mtu);
35342a550aecSAndrew Lunn 	else
35352a550aecSAndrew Lunn 		if (new_mtu > 1522)
35362a550aecSAndrew Lunn 			ret = -EINVAL;
35372a550aecSAndrew Lunn 	mv88e6xxx_reg_unlock(chip);
35382a550aecSAndrew Lunn 
35392a550aecSAndrew Lunn 	return ret;
35402a550aecSAndrew Lunn }
35412a550aecSAndrew Lunn 
354204aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
354304aca993SAndrew Lunn 				 struct phy_device *phydev)
354404aca993SAndrew Lunn {
354504aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
3546523a8904SVivien Didelot 	int err;
354704aca993SAndrew Lunn 
3548c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3549523a8904SVivien Didelot 	err = mv88e6xxx_serdes_power(chip, port, true);
3550c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
355104aca993SAndrew Lunn 
355204aca993SAndrew Lunn 	return err;
355304aca993SAndrew Lunn }
355404aca993SAndrew Lunn 
355575104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
355604aca993SAndrew Lunn {
355704aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
355804aca993SAndrew Lunn 
3559c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3560523a8904SVivien Didelot 	if (mv88e6xxx_serdes_power(chip, port, false))
3561523a8904SVivien Didelot 		dev_err(chip->dev, "failed to power off SERDES\n");
3562c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
356304aca993SAndrew Lunn }
356404aca993SAndrew Lunn 
35652cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
35662cfcd964SVivien Didelot 				     unsigned int ageing_time)
35672cfcd964SVivien Didelot {
356804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
35692cfcd964SVivien Didelot 	int err;
35702cfcd964SVivien Didelot 
3571c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3572720c6343SVivien Didelot 	err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
3573c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
35742cfcd964SVivien Didelot 
35752cfcd964SVivien Didelot 	return err;
35762cfcd964SVivien Didelot }
35772cfcd964SVivien Didelot 
3578447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
3579fad09c73SVivien Didelot {
3580fad09c73SVivien Didelot 	int err;
3581fad09c73SVivien Didelot 
3582de227387SAndrew Lunn 	/* Initialize the statistics unit */
3583447b1bb8SVivien Didelot 	if (chip->info->ops->stats_set_histogram) {
3584447b1bb8SVivien Didelot 		err = chip->info->ops->stats_set_histogram(chip);
3585de227387SAndrew Lunn 		if (err)
3586de227387SAndrew Lunn 			return err;
3587447b1bb8SVivien Didelot 	}
3588de227387SAndrew Lunn 
358940cff8fcSAndrew Lunn 	return mv88e6xxx_g1_stats_clear(chip);
35909729934cSVivien Didelot }
35919729934cSVivien Didelot 
3592ea89098eSAndrew Lunn /* Check if the errata has already been applied. */
3593ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
3594ea89098eSAndrew Lunn {
3595ea89098eSAndrew Lunn 	int port;
3596ea89098eSAndrew Lunn 	int err;
3597ea89098eSAndrew Lunn 	u16 val;
3598ea89098eSAndrew Lunn 
3599ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
360060907013SMarek Behún 		err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val);
3601ea89098eSAndrew Lunn 		if (err) {
3602ea89098eSAndrew Lunn 			dev_err(chip->dev,
3603ea89098eSAndrew Lunn 				"Error reading hidden register: %d\n", err);
3604ea89098eSAndrew Lunn 			return false;
3605ea89098eSAndrew Lunn 		}
3606ea89098eSAndrew Lunn 		if (val != 0x01c0)
3607ea89098eSAndrew Lunn 			return false;
3608ea89098eSAndrew Lunn 	}
3609ea89098eSAndrew Lunn 
3610ea89098eSAndrew Lunn 	return true;
3611ea89098eSAndrew Lunn }
3612ea89098eSAndrew Lunn 
3613ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic
3614ea89098eSAndrew Lunn  * values into undocumented hidden registers and then performing a
3615ea89098eSAndrew Lunn  * software reset.
3616ea89098eSAndrew Lunn  */
3617ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
3618ea89098eSAndrew Lunn {
3619ea89098eSAndrew Lunn 	int port;
3620ea89098eSAndrew Lunn 	int err;
3621ea89098eSAndrew Lunn 
3622ea89098eSAndrew Lunn 	if (mv88e6390_setup_errata_applied(chip))
3623ea89098eSAndrew Lunn 		return 0;
3624ea89098eSAndrew Lunn 
3625ea89098eSAndrew Lunn 	/* Set the ports into blocking mode */
3626ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
3627ea89098eSAndrew Lunn 		err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED);
3628ea89098eSAndrew Lunn 		if (err)
3629ea89098eSAndrew Lunn 			return err;
3630ea89098eSAndrew Lunn 	}
3631ea89098eSAndrew Lunn 
3632ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
363360907013SMarek Behún 		err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0);
3634ea89098eSAndrew Lunn 		if (err)
3635ea89098eSAndrew Lunn 			return err;
3636ea89098eSAndrew Lunn 	}
3637ea89098eSAndrew Lunn 
3638ea89098eSAndrew Lunn 	return mv88e6xxx_software_reset(chip);
3639ea89098eSAndrew Lunn }
3640ea89098eSAndrew Lunn 
364123e8b470SAndrew Lunn static void mv88e6xxx_teardown(struct dsa_switch *ds)
364223e8b470SAndrew Lunn {
364323e8b470SAndrew Lunn 	mv88e6xxx_teardown_devlink_params(ds);
3644e0c69ca7SAndrew Lunn 	dsa_devlink_resources_unregister(ds);
3645fd292c18SVladimir Oltean 	mv88e6xxx_teardown_devlink_regions_global(ds);
364623e8b470SAndrew Lunn }
364723e8b470SAndrew Lunn 
3648fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds)
3649fad09c73SVivien Didelot {
365004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
36512d2e1dd2SAndrew Lunn 	u8 cmode;
3652fad09c73SVivien Didelot 	int err;
3653fad09c73SVivien Didelot 	int i;
3654fad09c73SVivien Didelot 
3655fad09c73SVivien Didelot 	chip->ds = ds;
3656a3c53be5SAndrew Lunn 	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
3657fad09c73SVivien Didelot 
3658ce5df689SVladimir Oltean 	/* Since virtual bridges are mapped in the PVT, the number we support
3659ce5df689SVladimir Oltean 	 * depends on the physical switch topology. We need to let DSA figure
3660ce5df689SVladimir Oltean 	 * that out and therefore we cannot set this at dsa_register_switch()
3661ce5df689SVladimir Oltean 	 * time.
3662ce5df689SVladimir Oltean 	 */
3663ce5df689SVladimir Oltean 	if (mv88e6xxx_has_pvt(chip))
3664947c8746SVladimir Oltean 		ds->max_num_bridges = MV88E6XXX_MAX_PVT_SWITCHES -
3665ce5df689SVladimir Oltean 				      ds->dst->last_switch - 1;
3666ce5df689SVladimir Oltean 
3667c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3668fad09c73SVivien Didelot 
3669ea89098eSAndrew Lunn 	if (chip->info->ops->setup_errata) {
3670ea89098eSAndrew Lunn 		err = chip->info->ops->setup_errata(chip);
3671ea89098eSAndrew Lunn 		if (err)
3672ea89098eSAndrew Lunn 			goto unlock;
3673ea89098eSAndrew Lunn 	}
3674ea89098eSAndrew Lunn 
36752d2e1dd2SAndrew Lunn 	/* Cache the cmode of each port. */
36762d2e1dd2SAndrew Lunn 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
36772d2e1dd2SAndrew Lunn 		if (chip->info->ops->port_get_cmode) {
36782d2e1dd2SAndrew Lunn 			err = chip->info->ops->port_get_cmode(chip, i, &cmode);
36792d2e1dd2SAndrew Lunn 			if (err)
3680e29129fcSDan Carpenter 				goto unlock;
36812d2e1dd2SAndrew Lunn 
36822d2e1dd2SAndrew Lunn 			chip->ports[i].cmode = cmode;
36832d2e1dd2SAndrew Lunn 		}
36842d2e1dd2SAndrew Lunn 	}
36852d2e1dd2SAndrew Lunn 
36865bded825SVladimir Oltean 	err = mv88e6xxx_vtu_setup(chip);
36875bded825SVladimir Oltean 	if (err)
36885bded825SVladimir Oltean 		goto unlock;
36895bded825SVladimir Oltean 
369049c98c1dSTobias Waldekranz 	/* Must be called after mv88e6xxx_vtu_setup (which flushes the
369149c98c1dSTobias Waldekranz 	 * VTU, thereby also flushing the STU).
369249c98c1dSTobias Waldekranz 	 */
369349c98c1dSTobias Waldekranz 	err = mv88e6xxx_stu_setup(chip);
369449c98c1dSTobias Waldekranz 	if (err)
369549c98c1dSTobias Waldekranz 		goto unlock;
369649c98c1dSTobias Waldekranz 
36979729934cSVivien Didelot 	/* Setup Switch Port Registers */
3698370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
3699b759f528SVivien Didelot 		if (dsa_is_unused_port(ds, i))
3700b759f528SVivien Didelot 			continue;
3701b759f528SVivien Didelot 
3702c857486aSHubert Feurstein 		/* Prevent the use of an invalid port. */
3703b759f528SVivien Didelot 		if (mv88e6xxx_is_invalid_port(chip, i)) {
3704c857486aSHubert Feurstein 			dev_err(chip->dev, "port %d is invalid\n", i);
3705c857486aSHubert Feurstein 			err = -EINVAL;
3706c857486aSHubert Feurstein 			goto unlock;
3707c857486aSHubert Feurstein 		}
3708c857486aSHubert Feurstein 
37099729934cSVivien Didelot 		err = mv88e6xxx_setup_port(chip, i);
37109729934cSVivien Didelot 		if (err)
37119729934cSVivien Didelot 			goto unlock;
37129729934cSVivien Didelot 	}
37139729934cSVivien Didelot 
3714cd8da8bbSVivien Didelot 	err = mv88e6xxx_irl_setup(chip);
3715cd8da8bbSVivien Didelot 	if (err)
3716cd8da8bbSVivien Didelot 		goto unlock;
3717cd8da8bbSVivien Didelot 
371804a69a17SVivien Didelot 	err = mv88e6xxx_mac_setup(chip);
371904a69a17SVivien Didelot 	if (err)
372004a69a17SVivien Didelot 		goto unlock;
372104a69a17SVivien Didelot 
37221b17aedfSVivien Didelot 	err = mv88e6xxx_phy_setup(chip);
37231b17aedfSVivien Didelot 	if (err)
37241b17aedfSVivien Didelot 		goto unlock;
37251b17aedfSVivien Didelot 
372681228996SVivien Didelot 	err = mv88e6xxx_pvt_setup(chip);
372781228996SVivien Didelot 	if (err)
372881228996SVivien Didelot 		goto unlock;
372981228996SVivien Didelot 
3730a2ac29d2SVivien Didelot 	err = mv88e6xxx_atu_setup(chip);
3731a2ac29d2SVivien Didelot 	if (err)
3732a2ac29d2SVivien Didelot 		goto unlock;
3733a2ac29d2SVivien Didelot 
373487fa886eSAndrew Lunn 	err = mv88e6xxx_broadcast_setup(chip, 0);
373587fa886eSAndrew Lunn 	if (err)
373687fa886eSAndrew Lunn 		goto unlock;
373787fa886eSAndrew Lunn 
37389e907d73SVivien Didelot 	err = mv88e6xxx_pot_setup(chip);
37399e907d73SVivien Didelot 	if (err)
37409e907d73SVivien Didelot 		goto unlock;
37419e907d73SVivien Didelot 
37429e5baf9bSVivien Didelot 	err = mv88e6xxx_rmu_setup(chip);
37439e5baf9bSVivien Didelot 	if (err)
37449e5baf9bSVivien Didelot 		goto unlock;
37459e5baf9bSVivien Didelot 
374651c901a7SVivien Didelot 	err = mv88e6xxx_rsvd2cpu_setup(chip);
37476e55f698SAndrew Lunn 	if (err)
37486e55f698SAndrew Lunn 		goto unlock;
37496e55f698SAndrew Lunn 
3750b28f872dSVivien Didelot 	err = mv88e6xxx_trunk_setup(chip);
3751b28f872dSVivien Didelot 	if (err)
3752b28f872dSVivien Didelot 		goto unlock;
3753b28f872dSVivien Didelot 
3754c7f047b6SVivien Didelot 	err = mv88e6xxx_devmap_setup(chip);
3755c7f047b6SVivien Didelot 	if (err)
3756c7f047b6SVivien Didelot 		goto unlock;
3757c7f047b6SVivien Didelot 
375893e18d61SVivien Didelot 	err = mv88e6xxx_pri_setup(chip);
375993e18d61SVivien Didelot 	if (err)
376093e18d61SVivien Didelot 		goto unlock;
376193e18d61SVivien Didelot 
3762c6fe0ad2SBrandon Streiff 	/* Setup PTP Hardware Clock and timestamping */
37632fa8d3afSBrandon Streiff 	if (chip->info->ptp_support) {
37642fa8d3afSBrandon Streiff 		err = mv88e6xxx_ptp_setup(chip);
37652fa8d3afSBrandon Streiff 		if (err)
37662fa8d3afSBrandon Streiff 			goto unlock;
3767c6fe0ad2SBrandon Streiff 
3768c6fe0ad2SBrandon Streiff 		err = mv88e6xxx_hwtstamp_setup(chip);
3769c6fe0ad2SBrandon Streiff 		if (err)
3770c6fe0ad2SBrandon Streiff 			goto unlock;
37712fa8d3afSBrandon Streiff 	}
37722fa8d3afSBrandon Streiff 
3773447b1bb8SVivien Didelot 	err = mv88e6xxx_stats_setup(chip);
3774447b1bb8SVivien Didelot 	if (err)
3775447b1bb8SVivien Didelot 		goto unlock;
3776447b1bb8SVivien Didelot 
3777fad09c73SVivien Didelot unlock:
3778c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3779fad09c73SVivien Didelot 
3780e0c69ca7SAndrew Lunn 	if (err)
3781e0c69ca7SAndrew Lunn 		return err;
3782e0c69ca7SAndrew Lunn 
3783e0c69ca7SAndrew Lunn 	/* Have to be called without holding the register lock, since
3784e0c69ca7SAndrew Lunn 	 * they take the devlink lock, and we later take the locks in
3785e0c69ca7SAndrew Lunn 	 * the reverse order when getting/setting parameters or
3786e0c69ca7SAndrew Lunn 	 * resource occupancy.
378723e8b470SAndrew Lunn 	 */
3788e0c69ca7SAndrew Lunn 	err = mv88e6xxx_setup_devlink_resources(ds);
3789e0c69ca7SAndrew Lunn 	if (err)
3790e0c69ca7SAndrew Lunn 		return err;
3791e0c69ca7SAndrew Lunn 
3792e0c69ca7SAndrew Lunn 	err = mv88e6xxx_setup_devlink_params(ds);
3793e0c69ca7SAndrew Lunn 	if (err)
3794bfb25542SAndrew Lunn 		goto out_resources;
3795bfb25542SAndrew Lunn 
3796fd292c18SVladimir Oltean 	err = mv88e6xxx_setup_devlink_regions_global(ds);
3797bfb25542SAndrew Lunn 	if (err)
3798bfb25542SAndrew Lunn 		goto out_params;
3799bfb25542SAndrew Lunn 
3800bfb25542SAndrew Lunn 	return 0;
3801bfb25542SAndrew Lunn 
3802bfb25542SAndrew Lunn out_params:
3803bfb25542SAndrew Lunn 	mv88e6xxx_teardown_devlink_params(ds);
3804bfb25542SAndrew Lunn out_resources:
3805e0c69ca7SAndrew Lunn 	dsa_devlink_resources_unregister(ds);
3806e0c69ca7SAndrew Lunn 
3807e0c69ca7SAndrew Lunn 	return err;
3808fad09c73SVivien Didelot }
3809fad09c73SVivien Didelot 
3810fd292c18SVladimir Oltean static int mv88e6xxx_port_setup(struct dsa_switch *ds, int port)
3811fd292c18SVladimir Oltean {
3812fd292c18SVladimir Oltean 	return mv88e6xxx_setup_devlink_regions_port(ds, port);
3813fd292c18SVladimir Oltean }
3814fd292c18SVladimir Oltean 
3815fd292c18SVladimir Oltean static void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port)
3816fd292c18SVladimir Oltean {
3817fd292c18SVladimir Oltean 	mv88e6xxx_teardown_devlink_regions_port(ds, port);
3818fd292c18SVladimir Oltean }
3819fd292c18SVladimir Oltean 
38201fe976d3SPali Rohár /* prod_id for switch families which do not have a PHY model number */
38211fe976d3SPali Rohár static const u16 family_prod_id_table[] = {
38221fe976d3SPali Rohár 	[MV88E6XXX_FAMILY_6341] = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
38231fe976d3SPali Rohár 	[MV88E6XXX_FAMILY_6390] = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
3824c5d015b0SMarek Behún 	[MV88E6XXX_FAMILY_6393] = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
38251fe976d3SPali Rohár };
38261fe976d3SPali Rohár 
3827e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
3828fad09c73SVivien Didelot {
38290dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
38300dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
38311fe976d3SPali Rohár 	u16 prod_id;
3832e57e5e77SVivien Didelot 	u16 val;
3833e57e5e77SVivien Didelot 	int err;
3834fad09c73SVivien Didelot 
3835ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_read)
3836ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
3837ee26a228SAndrew Lunn 
3838c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3839ee26a228SAndrew Lunn 	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
3840c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3841e57e5e77SVivien Didelot 
3842ddc49acbSAndrew Lunn 	/* Some internal PHYs don't have a model number. */
38431fe976d3SPali Rohár 	if (reg == MII_PHYSID2 && !(val & 0x3f0) &&
38441fe976d3SPali Rohár 	    chip->info->family < ARRAY_SIZE(family_prod_id_table)) {
38451fe976d3SPali Rohár 		prod_id = family_prod_id_table[chip->info->family];
38461fe976d3SPali Rohár 		if (prod_id)
38471fe976d3SPali Rohár 			val |= prod_id >> 4;
3848da9f3301SAndrew Lunn 	}
3849da9f3301SAndrew Lunn 
3850e57e5e77SVivien Didelot 	return err ? err : val;
3851fad09c73SVivien Didelot }
3852fad09c73SVivien Didelot 
3853e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
3854fad09c73SVivien Didelot {
38550dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
38560dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
3857e57e5e77SVivien Didelot 	int err;
3858fad09c73SVivien Didelot 
3859ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_write)
3860ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
3861ee26a228SAndrew Lunn 
3862c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3863ee26a228SAndrew Lunn 	err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
3864c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3865e57e5e77SVivien Didelot 
3866e57e5e77SVivien Didelot 	return err;
3867fad09c73SVivien Didelot }
3868fad09c73SVivien Didelot 
3869fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
3870a3c53be5SAndrew Lunn 				   struct device_node *np,
3871a3c53be5SAndrew Lunn 				   bool external)
3872fad09c73SVivien Didelot {
3873fad09c73SVivien Didelot 	static int index;
38740dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
3875fad09c73SVivien Didelot 	struct mii_bus *bus;
3876fad09c73SVivien Didelot 	int err;
3877fad09c73SVivien Didelot 
38782510babcSAndrew Lunn 	if (external) {
3879c9acece0SRasmus Villemoes 		mv88e6xxx_reg_lock(chip);
38802510babcSAndrew Lunn 		err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
3881c9acece0SRasmus Villemoes 		mv88e6xxx_reg_unlock(chip);
38822510babcSAndrew Lunn 
38832510babcSAndrew Lunn 		if (err)
38842510babcSAndrew Lunn 			return err;
38852510babcSAndrew Lunn 	}
38862510babcSAndrew Lunn 
3887f53a2ce8SVladimir Oltean 	bus = mdiobus_alloc_size(sizeof(*mdio_bus));
3888fad09c73SVivien Didelot 	if (!bus)
3889fad09c73SVivien Didelot 		return -ENOMEM;
3890fad09c73SVivien Didelot 
38910dd12d54SAndrew Lunn 	mdio_bus = bus->priv;
3892a3c53be5SAndrew Lunn 	mdio_bus->bus = bus;
38930dd12d54SAndrew Lunn 	mdio_bus->chip = chip;
3894a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&mdio_bus->list);
3895a3c53be5SAndrew Lunn 	mdio_bus->external = external;
38960dd12d54SAndrew Lunn 
3897fad09c73SVivien Didelot 	if (np) {
3898fad09c73SVivien Didelot 		bus->name = np->full_name;
3899f7ce9103SRob Herring 		snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np);
3900fad09c73SVivien Didelot 	} else {
3901fad09c73SVivien Didelot 		bus->name = "mv88e6xxx SMI";
3902fad09c73SVivien Didelot 		snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
3903fad09c73SVivien Didelot 	}
3904fad09c73SVivien Didelot 
3905fad09c73SVivien Didelot 	bus->read = mv88e6xxx_mdio_read;
3906fad09c73SVivien Didelot 	bus->write = mv88e6xxx_mdio_write;
3907fad09c73SVivien Didelot 	bus->parent = chip->dev;
3908fad09c73SVivien Didelot 
39096f88284fSAndrew Lunn 	if (!external) {
39106f88284fSAndrew Lunn 		err = mv88e6xxx_g2_irq_mdio_setup(chip, bus);
39116f88284fSAndrew Lunn 		if (err)
3912f53a2ce8SVladimir Oltean 			goto out;
39136f88284fSAndrew Lunn 	}
39146f88284fSAndrew Lunn 
3915a3c53be5SAndrew Lunn 	err = of_mdiobus_register(bus, np);
3916fad09c73SVivien Didelot 	if (err) {
3917fad09c73SVivien Didelot 		dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
39186f88284fSAndrew Lunn 		mv88e6xxx_g2_irq_mdio_free(chip, bus);
3919f53a2ce8SVladimir Oltean 		goto out;
3920fad09c73SVivien Didelot 	}
3921fad09c73SVivien Didelot 
3922a3c53be5SAndrew Lunn 	if (external)
3923a3c53be5SAndrew Lunn 		list_add_tail(&mdio_bus->list, &chip->mdios);
3924a3c53be5SAndrew Lunn 	else
3925a3c53be5SAndrew Lunn 		list_add(&mdio_bus->list, &chip->mdios);
3926a3c53be5SAndrew Lunn 
3927a3c53be5SAndrew Lunn 	return 0;
3928f53a2ce8SVladimir Oltean 
3929f53a2ce8SVladimir Oltean out:
3930f53a2ce8SVladimir Oltean 	mdiobus_free(bus);
3931f53a2ce8SVladimir Oltean 	return err;
3932a3c53be5SAndrew Lunn }
3933a3c53be5SAndrew Lunn 
39343126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
39353126aeecSAndrew Lunn 
39363126aeecSAndrew Lunn {
393751a04ebfSVladimir Oltean 	struct mv88e6xxx_mdio_bus *mdio_bus, *p;
39383126aeecSAndrew Lunn 	struct mii_bus *bus;
39393126aeecSAndrew Lunn 
394051a04ebfSVladimir Oltean 	list_for_each_entry_safe(mdio_bus, p, &chip->mdios, list) {
39413126aeecSAndrew Lunn 		bus = mdio_bus->bus;
39423126aeecSAndrew Lunn 
39436f88284fSAndrew Lunn 		if (!mdio_bus->external)
39446f88284fSAndrew Lunn 			mv88e6xxx_g2_irq_mdio_free(chip, bus);
39456f88284fSAndrew Lunn 
39463126aeecSAndrew Lunn 		mdiobus_unregister(bus);
3947f53a2ce8SVladimir Oltean 		mdiobus_free(bus);
39483126aeecSAndrew Lunn 	}
39493126aeecSAndrew Lunn }
39503126aeecSAndrew Lunn 
3951a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
3952a3c53be5SAndrew Lunn 				    struct device_node *np)
3953a3c53be5SAndrew Lunn {
3954a3c53be5SAndrew Lunn 	struct device_node *child;
3955a3c53be5SAndrew Lunn 	int err;
3956a3c53be5SAndrew Lunn 
3957a3c53be5SAndrew Lunn 	/* Always register one mdio bus for the internal/default mdio
3958a3c53be5SAndrew Lunn 	 * bus. This maybe represented in the device tree, but is
3959a3c53be5SAndrew Lunn 	 * optional.
3960a3c53be5SAndrew Lunn 	 */
3961a3c53be5SAndrew Lunn 	child = of_get_child_by_name(np, "mdio");
3962a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdio_register(chip, child, false);
3963a3c53be5SAndrew Lunn 	if (err)
3964a3c53be5SAndrew Lunn 		return err;
3965a3c53be5SAndrew Lunn 
3966a3c53be5SAndrew Lunn 	/* Walk the device tree, and see if there are any other nodes
3967a3c53be5SAndrew Lunn 	 * which say they are compatible with the external mdio
3968a3c53be5SAndrew Lunn 	 * bus.
3969a3c53be5SAndrew Lunn 	 */
3970a3c53be5SAndrew Lunn 	for_each_available_child_of_node(np, child) {
3971ceb96faeSAndrew Lunn 		if (of_device_is_compatible(
3972ceb96faeSAndrew Lunn 			    child, "marvell,mv88e6xxx-mdio-external")) {
3973a3c53be5SAndrew Lunn 			err = mv88e6xxx_mdio_register(chip, child, true);
39743126aeecSAndrew Lunn 			if (err) {
39753126aeecSAndrew Lunn 				mv88e6xxx_mdios_unregister(chip);
397678e42040SNishka Dasgupta 				of_node_put(child);
3977a3c53be5SAndrew Lunn 				return err;
3978a3c53be5SAndrew Lunn 			}
3979a3c53be5SAndrew Lunn 		}
39803126aeecSAndrew Lunn 	}
3981a3c53be5SAndrew Lunn 
3982a3c53be5SAndrew Lunn 	return 0;
3983a3c53be5SAndrew Lunn }
3984a3c53be5SAndrew Lunn 
3985855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
3986855b1932SVivien Didelot {
398704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3988855b1932SVivien Didelot 
3989855b1932SVivien Didelot 	return chip->eeprom_len;
3990855b1932SVivien Didelot }
3991855b1932SVivien Didelot 
3992855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
3993855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
3994855b1932SVivien Didelot {
399504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3996855b1932SVivien Didelot 	int err;
3997855b1932SVivien Didelot 
3998ee4dc2e7SVivien Didelot 	if (!chip->info->ops->get_eeprom)
3999ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
4000ee4dc2e7SVivien Didelot 
4001c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
4002ee4dc2e7SVivien Didelot 	err = chip->info->ops->get_eeprom(chip, eeprom, data);
4003c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
4004855b1932SVivien Didelot 
4005855b1932SVivien Didelot 	if (err)
4006855b1932SVivien Didelot 		return err;
4007855b1932SVivien Didelot 
4008855b1932SVivien Didelot 	eeprom->magic = 0xc3ec4951;
4009855b1932SVivien Didelot 
4010855b1932SVivien Didelot 	return 0;
4011855b1932SVivien Didelot }
4012855b1932SVivien Didelot 
4013855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
4014855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
4015855b1932SVivien Didelot {
401604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
4017855b1932SVivien Didelot 	int err;
4018855b1932SVivien Didelot 
4019ee4dc2e7SVivien Didelot 	if (!chip->info->ops->set_eeprom)
4020ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
4021ee4dc2e7SVivien Didelot 
4022855b1932SVivien Didelot 	if (eeprom->magic != 0xc3ec4951)
4023855b1932SVivien Didelot 		return -EINVAL;
4024855b1932SVivien Didelot 
4025c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
4026ee4dc2e7SVivien Didelot 	err = chip->info->ops->set_eeprom(chip, eeprom, data);
4027c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
4028855b1932SVivien Didelot 
4029855b1932SVivien Didelot 	return err;
4030855b1932SVivien Didelot }
4031855b1932SVivien Didelot 
4032b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = {
40334b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6097 */
403493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
403593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4036cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4037b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
40387e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
40397e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
404008ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
40414efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4042f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4043ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
404456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4045a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4046a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
404756995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4048ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
40490898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4050c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
40519dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
40522d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
4053121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4054a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
405540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4056dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4057dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4058052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4059fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4060fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4061fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
406251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
40639e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
4064a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
4065a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
406617e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
40679e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
4068f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
40690ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4070c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
4071c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
4072d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6185_phylink_get_caps,
40731baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
4074b3469dd8SVivien Didelot };
4075b3469dd8SVivien Didelot 
4076b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = {
40774b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6095 */
407893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
407993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4080b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
40817e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
40827e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
408308ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
40844efe7662SChris Packham 	.port_sync_link = mv88e6185_port_sync_link,
4085f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
408656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
4087a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6185_port_set_forward_unknown,
4088a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6185_port_set_default_forward,
4089a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
40902d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
4091121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4092a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
409340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4094dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4095dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4096052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
409751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
4098f5be107cSChris Packham 	.serdes_power = mv88e6185_serdes_power,
4099f5be107cSChris Packham 	.serdes_get_lane = mv88e6185_serdes_get_lane,
4100f5be107cSChris Packham 	.serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
4101a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
4102a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
410317e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
4104f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
41050ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4106d0b78ab1STobias Waldekranz 	.phylink_get_caps = mv88e6095_phylink_get_caps,
41071baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
4108b3469dd8SVivien Didelot };
4109b3469dd8SVivien Didelot 
41107d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = {
411115da3cc8SStefan Eichenberger 	/* MV88E6XXX_FAMILY_6097 */
411293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
411393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4114cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
41157d381a02SStefan Eichenberger 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
41167d381a02SStefan Eichenberger 	.phy_read = mv88e6xxx_g2_smi_phy_read,
41177d381a02SStefan Eichenberger 	.phy_write = mv88e6xxx_g2_smi_phy_write,
41187d381a02SStefan Eichenberger 	.port_set_link = mv88e6xxx_port_set_link,
41194efe7662SChris Packham 	.port_sync_link = mv88e6185_port_sync_link,
4120f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4121ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
4122585d42bbSTobias Waldekranz 	.port_set_policy = mv88e6352_port_set_policy,
412356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4124a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4125a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
412656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4127ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
41280898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4129c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
41309dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
41312d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
4132121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
41337d381a02SStefan Eichenberger 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
413440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
41357d381a02SStefan Eichenberger 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
41367d381a02SStefan Eichenberger 	.stats_get_strings = mv88e6095_stats_get_strings,
41377d381a02SStefan Eichenberger 	.stats_get_stats = mv88e6095_stats_get_stats,
4138fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4139fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
414091eaa475SVolodymyr Bendiuga 	.watchdog_ops = &mv88e6097_watchdog_ops,
414151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
4142f5be107cSChris Packham 	.serdes_power = mv88e6185_serdes_power,
4143f5be107cSChris Packham 	.serdes_get_lane = mv88e6185_serdes_get_lane,
4144f5be107cSChris Packham 	.serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
41455c19bc8bSChris Packham 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
41465c19bc8bSChris Packham 	.serdes_irq_enable = mv88e6097_serdes_irq_enable,
41475c19bc8bSChris Packham 	.serdes_irq_status = mv88e6097_serdes_irq_status,
41489e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
414917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
41509e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
4151f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
41520ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4153d0b78ab1STobias Waldekranz 	.phylink_get_caps = mv88e6095_phylink_get_caps,
415449c98c1dSTobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
415549c98c1dSTobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
41561baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
41577d381a02SStefan Eichenberger };
41587d381a02SStefan Eichenberger 
4159b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = {
41604b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
416193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
416293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4163cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4164b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4165ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4166ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
416708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
41684efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4169f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
417056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
4171a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4172a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4173c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
41749dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
41752d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
4176121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
41770ac64c39SAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
417840cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4179dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4180dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4181052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4182fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4183fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4184fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
418551c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
41869e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
418717e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
418823e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
418923e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4190f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
41910ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4192c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
4193c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
4194d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6185_phylink_get_caps,
41951baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
4196b3469dd8SVivien Didelot };
4197b3469dd8SVivien Didelot 
4198b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = {
41994b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
420093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
420193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4202b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
42037e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
42047e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
420508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
42064efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4207f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4208ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
420956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4210a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6185_port_set_forward_unknown,
4211a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6185_port_set_default_forward,
421256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4213a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
4214cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4215ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
42160898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
421754186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
42182d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
4219121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4220a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
422140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4222dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4223dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4224052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4225fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4226fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4227fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
422851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
4229a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
423002317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
4231a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
423217e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
4233f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
42340ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4235d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6185_phylink_get_caps,
4236b3469dd8SVivien Didelot };
4237b3469dd8SVivien Didelot 
4238990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = {
4239990e27b0SVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
424093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
424193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4242cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4243990e27b0SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
4244990e27b0SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
4245990e27b0SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4246990e27b0SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4247990e27b0SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
4248990e27b0SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
42494efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4250990e27b0SVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4251f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
42527cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
4253990e27b0SVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
42547da467d8SMarek Behún 	.port_set_policy = mv88e6352_port_set_policy,
4255990e27b0SVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4256a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4257a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4258990e27b0SVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4259cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4260990e27b0SVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
42610898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4262990e27b0SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4263990e27b0SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
42642d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
42657a3007d2SMarek Behún 	.port_set_cmode = mv88e6341_port_set_cmode,
4266121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4267990e27b0SVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
426811527f3cSMarek Behún 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4269990e27b0SVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4270990e27b0SVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
4271990e27b0SVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
4272fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4273fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
4274990e27b0SVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
4275990e27b0SVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
42769e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
4277990e27b0SVivien Didelot 	.reset = mv88e6352_g1_reset,
427837094887SMarek Behún 	.rmu_disable = mv88e6390_g1_rmu_disable,
4279c07fff34SMarek Behún 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
4280c07fff34SMarek Behún 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4281f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
42820ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4283c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
4284c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
4285d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
4286d3cf7d8fSMarek Behún 	.serdes_get_lane = mv88e6341_serdes_get_lane,
4287a5a6858bSRussell King 	/* Check status register pause & lpa register */
4288a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4289a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4290a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4291a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
42924241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
429361a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4294907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
4295a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
4296a03b98d6SMarek Behún 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
4297a03b98d6SMarek Behún 	.serdes_get_strings = mv88e6390_serdes_get_strings,
4298a03b98d6SMarek Behún 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4299953b0dcbSMarek Behún 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4300953b0dcbSMarek Behún 	.serdes_get_regs = mv88e6390_serdes_get_regs,
4301d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6341_phylink_get_caps,
4302990e27b0SVivien Didelot };
4303990e27b0SVivien Didelot 
4304b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = {
43054b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
430693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
430793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4308cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4309b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4310ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4311ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
431208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
43134efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4314f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4315ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
431656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4317a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4318a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
431956995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4320ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
43210898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4322c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
43239dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
43242d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
4325121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4326a6da21bbSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
432740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4328dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4329dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4330052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4331fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4332fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4333fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
433451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
43359e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
433617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
433723e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
433823e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4339f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
43400ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4341c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
4342c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
4343a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
4344dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
4345d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6185_phylink_get_caps,
4346fe230361SAndrew Lunn 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
4347b3469dd8SVivien Didelot };
4348b3469dd8SVivien Didelot 
4349b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = {
43504b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
435193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
435293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4353cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4354b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4355efb3e74dSAndrew Lunn 	.phy_read = mv88e6165_phy_read,
4356efb3e74dSAndrew Lunn 	.phy_write = mv88e6165_phy_write,
435708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
43584efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4359f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4360c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
43619dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
43622d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
4363121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4364a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
436540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4366dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4367dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4368052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4369fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4370fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4371fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
437251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
43739e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
437417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
437523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
437623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4377f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
43780ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4379c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
4380c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
4381a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
4382dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
4383d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6185_phylink_get_caps,
4384b3469dd8SVivien Didelot };
4385b3469dd8SVivien Didelot 
4386b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = {
43874b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
438893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
438993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4390cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4391b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4392b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4393b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
439408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
43954efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
439694d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4397f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4398ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
439956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4400a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4401a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
440256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4403cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4404ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
44050898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4406c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
44079dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
44082d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4409121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4410a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
441140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4412dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4413dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4414052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4415fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4416fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4417fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
441851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
44199e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
442017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
442123e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
442223e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4423f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
44240ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4425c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
4426c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
4427d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6185_phylink_get_caps,
4428b3469dd8SVivien Didelot };
4429b3469dd8SVivien Didelot 
4430b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = {
44314b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
443293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
443393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4434cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4435ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4436ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4437b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4438b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4439b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
444008ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
44414efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4442a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4443f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
4444ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
4445f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
444656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4447a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4448a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
444956995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4450cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4451ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
44520898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4453c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
44549dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
44552d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4456121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4457a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
445840cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4459dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4460dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4461052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4462fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4463fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4464fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
446551c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
44669e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
446717e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
44689e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
446923e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
447023e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4471f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
44720ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4473c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
4474c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
44759db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
4476a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
4477a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
4478a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
4479a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
44806d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
4481d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
4482d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
4483a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
4484d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6352_phylink_get_caps,
4485b3469dd8SVivien Didelot };
4486b3469dd8SVivien Didelot 
4487b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = {
44884b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
448993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
449093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4491cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4492b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4493b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4494b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
449508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
44964efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
449794d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4498f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4499ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
450056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4501a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4502a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
450356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4504cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4505ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
45060898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4507c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
45089dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
45092d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4510121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4511a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
451240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4513dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4514dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4515052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4516fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4517fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4518fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
451951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
45209e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
452117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
452223e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
452323e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4524f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
45250ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4526c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
4527c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
4528d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6185_phylink_get_caps,
4529b3469dd8SVivien Didelot };
4530b3469dd8SVivien Didelot 
4531b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = {
45324b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
453393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
453493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4535cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4536ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4537ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4538b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4539b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4540b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
454108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
45424efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4543a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4544f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
4545ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
4546f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
454756995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4548a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4549a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
455056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4551cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4552ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
45530898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4554c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
45559dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
45562d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4557121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4558a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
455940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4560dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4561dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4562052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4563fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4564fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4565fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
456651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
45679e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
456817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
45699e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
457023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
457123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4572f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
45730ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4574c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
4575c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
45769db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
4577a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
4578a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
4579a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
4580a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
45816d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
45824241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
458361a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4584907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
4585d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
4586d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
4587926eae60SHolger Brunck 	.serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude,
4588a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
4589d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6352_phylink_get_caps,
4590b3469dd8SVivien Didelot };
4591b3469dd8SVivien Didelot 
4592b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = {
45934b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
459493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
459593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4596b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
45977e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
45987e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
459908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
46004efe7662SChris Packham 	.port_sync_link = mv88e6185_port_sync_link,
4601f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
460256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
4603a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6185_port_set_forward_unknown,
4604a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6185_port_set_default_forward,
4605ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
4606a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
460754186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
46082d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
4609121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4610a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
461140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4612dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4613dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4614052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4615fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4616fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4617fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
461851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
4619f5be107cSChris Packham 	.serdes_power = mv88e6185_serdes_power,
4620f5be107cSChris Packham 	.serdes_get_lane = mv88e6185_serdes_get_lane,
4621f5be107cSChris Packham 	.serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
462202317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
4623a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
4624a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
462517e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
4626f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
46270ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4628d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6185_phylink_get_caps,
46291baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
4630b3469dd8SVivien Didelot };
4631b3469dd8SVivien Didelot 
46321a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = {
46334b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4634ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4635cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
463698fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
463798fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
46381a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
46391a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
46401a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
46411a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
46424efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
46431a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4644f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
46457cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4646ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4647f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
464856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4649a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4650a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
465156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4652e8b34c67SChris Packham 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
46530898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4654c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
46559dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
46562d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4657fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4658121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
465979523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4660de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4661dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4662dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4663e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4664fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4665fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
466661303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
46676e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
46689e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
466917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
46709e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
467123e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
467223e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4673931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4674931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4675c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6390_g1_stu_getnext,
4676c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
46776335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
467817deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
4679a5a6858bSRussell King 	/* Check status register pause & lpa register */
4680a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4681a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4682a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4683a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
46844241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
468561a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4686907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
46874262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
46884262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4689bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4690bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
4691a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
4692d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6390_phylink_get_caps,
46931a3b39ecSAndrew Lunn };
46941a3b39ecSAndrew Lunn 
46951a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = {
46964b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4697ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4698cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
469998fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
470098fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
47011a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
47021a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
47031a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
47041a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
47054efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
47061a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4707f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
47087cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
4709ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4710f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
471156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4712a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4713a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
471456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4715e8b34c67SChris Packham 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
47160898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4717c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
47189dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
47192d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4720fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
4721121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
472279523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4723de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4724dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4725dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4726e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4727fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4728fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
472961303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
47306e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
47319e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
473217e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
47339e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
473423e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
473523e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4736931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4737931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4738c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6390_g1_stu_getnext,
4739c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
4740d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
474117deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390x_serdes_get_lane,
4742a5a6858bSRussell King 	/* Check status register pause & lpa register */
4743a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4744a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4745a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4746a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
47474241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
474861a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4749907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
47504262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
47514262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4752bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4753bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
4754a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
4755d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6390x_phylink_get_caps,
47561a3b39ecSAndrew Lunn };
47571a3b39ecSAndrew Lunn 
47581a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = {
47594b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4760ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4761cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
476298fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
476398fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
47641a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
47651a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
47661a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
47671a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
47684efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
47691a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4770f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
47717cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4772ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
477356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4774a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4775a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
477656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
47770898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4778c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
47799dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
47802d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4781fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4782121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
478379523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4784de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4785dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4786dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4787e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4788fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4789fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
479061303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
47916e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
47929e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
479317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
47949e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
479523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
479623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4797931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4798931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4799c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6390_g1_stu_getnext,
4800c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
48016335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
480217deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
4803a5a6858bSRussell King 	/* Check status register pause & lpa register */
4804a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4805a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4806a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4807a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
48084241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
480961a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4810907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
48114262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
48124262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4813bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4814bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
48156d2ac8eeSAndrew Lunn 	.avb_ops = &mv88e6390_avb_ops,
48166d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
4817d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6390_phylink_get_caps,
48181a3b39ecSAndrew Lunn };
48191a3b39ecSAndrew Lunn 
4820b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = {
48214b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
482293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
482393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4824cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4825ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4826ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4827b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4828b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4829b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
483008ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
48314efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4832a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4833f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
4834ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
4835f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
483656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4837a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4838a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
483956995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4840cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4841ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
48420898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4843c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
48449dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
48452d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4846121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4847a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
484840cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4849dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4850dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4851052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4852fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4853fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4854fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
485551c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
48569e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
485717e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
48589e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
485923e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
486023e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4861f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
48620ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4863c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
4864c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
48659db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
4866a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
4867a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
4868a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
4869a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
48706d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
48714241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
487261a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4873907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
4874d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
4875d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
4876926eae60SHolger Brunck 	.serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude,
4877a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
48780d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
48796d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
4880d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6352_phylink_get_caps,
4881b3469dd8SVivien Didelot };
4882b3469dd8SVivien Didelot 
48831f71836fSRasmus Villemoes static const struct mv88e6xxx_ops mv88e6250_ops = {
48841f71836fSRasmus Villemoes 	/* MV88E6XXX_FAMILY_6250 */
48851f71836fSRasmus Villemoes 	.ieee_pri_map = mv88e6250_g1_ieee_pri_map,
48861f71836fSRasmus Villemoes 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
48871f71836fSRasmus Villemoes 	.irl_init_all = mv88e6352_g2_irl_init_all,
48881f71836fSRasmus Villemoes 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
48891f71836fSRasmus Villemoes 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
48901f71836fSRasmus Villemoes 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
48911f71836fSRasmus Villemoes 	.phy_read = mv88e6xxx_g2_smi_phy_read,
48921f71836fSRasmus Villemoes 	.phy_write = mv88e6xxx_g2_smi_phy_write,
48931f71836fSRasmus Villemoes 	.port_set_link = mv88e6xxx_port_set_link,
48944efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
48951f71836fSRasmus Villemoes 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4896f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6250_port_set_speed_duplex,
48971f71836fSRasmus Villemoes 	.port_tag_remap = mv88e6095_port_tag_remap,
48981f71836fSRasmus Villemoes 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4899a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4900a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
49011f71836fSRasmus Villemoes 	.port_set_ether_type = mv88e6351_port_set_ether_type,
49021f71836fSRasmus Villemoes 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
49031f71836fSRasmus Villemoes 	.port_pause_limit = mv88e6097_port_pause_limit,
49041f71836fSRasmus Villemoes 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
49051f71836fSRasmus Villemoes 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
49061f71836fSRasmus Villemoes 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
49071f71836fSRasmus Villemoes 	.stats_get_sset_count = mv88e6250_stats_get_sset_count,
49081f71836fSRasmus Villemoes 	.stats_get_strings = mv88e6250_stats_get_strings,
49091f71836fSRasmus Villemoes 	.stats_get_stats = mv88e6250_stats_get_stats,
49101f71836fSRasmus Villemoes 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
49111f71836fSRasmus Villemoes 	.set_egress_port = mv88e6095_g1_set_egress_port,
49121f71836fSRasmus Villemoes 	.watchdog_ops = &mv88e6250_watchdog_ops,
49131f71836fSRasmus Villemoes 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
49141f71836fSRasmus Villemoes 	.pot_clear = mv88e6xxx_g2_pot_clear,
49151f71836fSRasmus Villemoes 	.reset = mv88e6250_g1_reset,
491667c9ed1cSRasmus Villemoes 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
4917b28f3f3cSRasmus Villemoes 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
491871509614SHubert Feurstein 	.avb_ops = &mv88e6352_avb_ops,
491971509614SHubert Feurstein 	.ptp_ops = &mv88e6250_ptp_ops,
4920d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6250_phylink_get_caps,
49211f71836fSRasmus Villemoes };
49221f71836fSRasmus Villemoes 
49231a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = {
49244b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4925ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4926cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
492798fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
492898fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
49291a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
49301a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
49311a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
49321a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
49334efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
49341a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4935f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
49367cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4937ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4938f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
493956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4940a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4941a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
494256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
49430898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4944c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
49459dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
49462d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4947fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4948121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
494979523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4950de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4951dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4952dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4953e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4954fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4955fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
495661303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
49576e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
49589e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
495917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
49609e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
496123e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
496223e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4963931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4964931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4965c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6390_g1_stu_getnext,
4966c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
49676335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
496817deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
4969a5a6858bSRussell King 	/* Check status register pause & lpa register */
4970a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4971a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4972a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4973a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
49744241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
497561a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4976907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
49774262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
49784262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4979bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4980bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
4981a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
49820d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
49836d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
4984d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6390_phylink_get_caps,
49851a3b39ecSAndrew Lunn };
49861a3b39ecSAndrew Lunn 
4987b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = {
49884b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6320 */
498993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
499093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4991cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4992ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4993ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4994b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4995b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4996b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
499708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
49984efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4999f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
5000ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
500156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
5002a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
5003a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
500456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
5005cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
5006ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
50070898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
5008c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
50099dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
50102d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
5011121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
5012a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
501340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
5014dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
5015dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
5016052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
5017fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
5018fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
50199c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
502051c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
50219e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
502217e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
5023f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
50240ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
5025a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
50260d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
50276d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
5028d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6185_phylink_get_caps,
5029b3469dd8SVivien Didelot };
5030b3469dd8SVivien Didelot 
5031b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = {
5032bd807204SVivien Didelot 	/* MV88E6XXX_FAMILY_6320 */
503393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
503493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
5035cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
5036ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
5037ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
5038b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
5039b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
5040b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
504108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
50424efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
5043f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
5044ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
504556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
5046a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
5047a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
504856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
5049cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
5050ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
50510898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
5052c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
50539dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
50542d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
5055121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
5056a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
505740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
5058dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
5059dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
5060052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
5061fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
5062fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
50639c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
506417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
5065f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
50660ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
5067a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
50680d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
50696d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
5070d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6185_phylink_get_caps,
5071b3469dd8SVivien Didelot };
5072b3469dd8SVivien Didelot 
507316e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = {
507416e329aeSVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
507593e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
507693e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
5077cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
507816e329aeSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
507916e329aeSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
508016e329aeSVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
508116e329aeSVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
508216e329aeSVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
508316e329aeSVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
50844efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
508516e329aeSVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
5086f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
50877cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
508816e329aeSVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
50897da467d8SMarek Behún 	.port_set_policy = mv88e6352_port_set_policy,
509016e329aeSVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
5091a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
5092a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
509316e329aeSVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
5094cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
509516e329aeSVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
50960898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
509716e329aeSVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
509816e329aeSVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
50992d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
51007a3007d2SMarek Behún 	.port_set_cmode = mv88e6341_port_set_cmode,
5101121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
510216e329aeSVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
510311527f3cSMarek Behún 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
510416e329aeSVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
510516e329aeSVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
510616e329aeSVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
5107fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
5108fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
510916e329aeSVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
511016e329aeSVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
51119e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
511216e329aeSVivien Didelot 	.reset = mv88e6352_g1_reset,
511337094887SMarek Behún 	.rmu_disable = mv88e6390_g1_rmu_disable,
5114c07fff34SMarek Behún 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
5115c07fff34SMarek Behún 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
5116f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
51170ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
5118c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
5119c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
5120d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
5121d3cf7d8fSMarek Behún 	.serdes_get_lane = mv88e6341_serdes_get_lane,
5122a5a6858bSRussell King 	/* Check status register pause & lpa register */
5123a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
5124a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
5125a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
5126a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
51274241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
512861a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
5129907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
5130a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
51310d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
51326d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
5133a03b98d6SMarek Behún 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
5134a03b98d6SMarek Behún 	.serdes_get_strings = mv88e6390_serdes_get_strings,
5135a03b98d6SMarek Behún 	.serdes_get_stats = mv88e6390_serdes_get_stats,
5136953b0dcbSMarek Behún 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
5137953b0dcbSMarek Behún 	.serdes_get_regs = mv88e6390_serdes_get_regs,
5138d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6341_phylink_get_caps,
513916e329aeSVivien Didelot };
514016e329aeSVivien Didelot 
5141b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = {
51424b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
514393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
514493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
5145cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
5146b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
5147b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
5148b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
514908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
51504efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
515194d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
5152f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
5153ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
515456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
5155a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
5156a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
515756995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
5158cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
5159ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
51600898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
5161c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
51629dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
51632d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
5164121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
5165a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
516640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
5167dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
5168dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
5169052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
5170fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
5171fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
5172fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
517351c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
51749e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
517517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
517623e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
517723e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
5178f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
51790ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
5180c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
5181c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
5182d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6185_phylink_get_caps,
5183b3469dd8SVivien Didelot };
5184b3469dd8SVivien Didelot 
5185b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = {
51864b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
518793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
518893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
5189cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
5190b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
5191b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
5192b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
519308ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
51944efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
519594d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
5196f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
5197ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
519856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
5199a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
5200a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
520156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
5202cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
5203ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
52040898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
5205c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
52069dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
52072d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
5208121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
5209a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
521040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
5211dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
5212dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
5213052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
5214fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
5215fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
5216fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
521751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
52189e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
521917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
522023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
522123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
5222f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
52230ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
5224c050f5e9STobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
5225c050f5e9STobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
52260d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
52276d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
5228d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6185_phylink_get_caps,
5229b3469dd8SVivien Didelot };
5230b3469dd8SVivien Didelot 
5231b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = {
52324b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
523393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
523493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
5235cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
5236ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
5237ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
5238b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
5239b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
5240b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
524108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
52424efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
5243a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
5244f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
5245ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
5246f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
524756995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
5248a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
5249a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
525056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
5251cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
5252ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
52530898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
5254c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
52559dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
52562d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
5257121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
5258a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
525940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
5260dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
5261dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
5262052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
5263fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
5264fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
5265fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
526651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
52679e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
526817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
52699e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
527023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
527123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
5272f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
52730ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
527449c98c1dSTobias Waldekranz 	.stu_getnext = mv88e6352_g1_stu_getnext,
527549c98c1dSTobias Waldekranz 	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
52769db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
5277a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
5278a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
5279a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
5280a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
52816d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
52824241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
528361a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
5284907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
5285a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
52860d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
52876d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
5288cda9f4aaSAndrew Lunn 	.serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
5289cda9f4aaSAndrew Lunn 	.serdes_get_strings = mv88e6352_serdes_get_strings,
5290cda9f4aaSAndrew Lunn 	.serdes_get_stats = mv88e6352_serdes_get_stats,
5291d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
5292d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
5293926eae60SHolger Brunck 	.serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude,
5294d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6352_phylink_get_caps,
5295b3469dd8SVivien Didelot };
5296b3469dd8SVivien Didelot 
52971a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = {
52984b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
5299ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
5300cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
530198fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
530298fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
53031a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
53041a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
53051a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
53061a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
53074efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
53081a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
5309f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
53107cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
5311ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
5312f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
531356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
5314a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
5315a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
531656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
5317cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
5318ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
53190898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
5320c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
53219dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
53222d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
5323fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
5324121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
532579523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
5326de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
5327dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
5328dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
5329e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
5330fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
5331fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
533261303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
53336e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
53349e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
533517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
53369e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
533723e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
533823e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
5339931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
5340931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
534149c98c1dSTobias Waldekranz 	.stu_getnext = mv88e6390_g1_stu_getnext,
534249c98c1dSTobias Waldekranz 	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
53436335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
534417deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
5345a5a6858bSRussell King 	/* Check status register pause & lpa register */
5346a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
5347a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
5348a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
5349a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
53504241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
535161a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
5352907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
5353a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
53540d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
53556d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
53560df95287SNikita Yushchenko 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
53570df95287SNikita Yushchenko 	.serdes_get_strings = mv88e6390_serdes_get_strings,
53580df95287SNikita Yushchenko 	.serdes_get_stats = mv88e6390_serdes_get_stats,
5359bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
5360bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
5361d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6390_phylink_get_caps,
53621a3b39ecSAndrew Lunn };
53631a3b39ecSAndrew Lunn 
53641a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = {
53654b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
5366ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
5367cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
536898fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
536998fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
53701a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
53711a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
53721a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
53731a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
53744efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
53751a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
5376f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
53777cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
5378ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
5379f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
538056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
5381a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
5382a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
538356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
5384cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
5385ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
53860898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
5387c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
53889dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
53892d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
5390b3dce4daSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
5391121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
539279523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
5393de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
5394dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
5395dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
5396e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
5397fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
5398fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
539961303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
54006e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
54019e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
540217e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
54039e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
540423e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
540523e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
5406931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
5407931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
540849c98c1dSTobias Waldekranz 	.stu_getnext = mv88e6390_g1_stu_getnext,
540949c98c1dSTobias Waldekranz 	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
5410d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
541117deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390x_serdes_get_lane,
5412a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
5413a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
5414a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
5415a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
54164241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
541761a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
5418907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
54194262c38dSAndrew Lunn 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
54204262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
54214262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
5422bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
5423bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
5424a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
54250d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
54266d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
5427d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6390x_phylink_get_caps,
54281a3b39ecSAndrew Lunn };
54291a3b39ecSAndrew Lunn 
5430de776d0dSPavana Sharma static const struct mv88e6xxx_ops mv88e6393x_ops = {
5431de776d0dSPavana Sharma 	/* MV88E6XXX_FAMILY_6393 */
5432de776d0dSPavana Sharma 	.setup_errata = mv88e6393x_serdes_setup_errata,
5433de776d0dSPavana Sharma 	.irl_init_all = mv88e6390_g2_irl_init_all,
5434de776d0dSPavana Sharma 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
5435de776d0dSPavana Sharma 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
5436de776d0dSPavana Sharma 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
5437de776d0dSPavana Sharma 	.phy_read = mv88e6xxx_g2_smi_phy_read,
5438de776d0dSPavana Sharma 	.phy_write = mv88e6xxx_g2_smi_phy_write,
5439de776d0dSPavana Sharma 	.port_set_link = mv88e6xxx_port_set_link,
5440de776d0dSPavana Sharma 	.port_sync_link = mv88e6xxx_port_sync_link,
5441de776d0dSPavana Sharma 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
5442de776d0dSPavana Sharma 	.port_set_speed_duplex = mv88e6393x_port_set_speed_duplex,
5443de776d0dSPavana Sharma 	.port_max_speed_mode = mv88e6393x_port_max_speed_mode,
5444de776d0dSPavana Sharma 	.port_tag_remap = mv88e6390_port_tag_remap,
54456584b260SMarek Behún 	.port_set_policy = mv88e6393x_port_set_policy,
5446de776d0dSPavana Sharma 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
5447de776d0dSPavana Sharma 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
5448de776d0dSPavana Sharma 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
5449de776d0dSPavana Sharma 	.port_set_ether_type = mv88e6393x_port_set_ether_type,
5450de776d0dSPavana Sharma 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
5451de776d0dSPavana Sharma 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
5452de776d0dSPavana Sharma 	.port_pause_limit = mv88e6390_port_pause_limit,
5453de776d0dSPavana Sharma 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
5454de776d0dSPavana Sharma 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
5455de776d0dSPavana Sharma 	.port_get_cmode = mv88e6352_port_get_cmode,
5456de776d0dSPavana Sharma 	.port_set_cmode = mv88e6393x_port_set_cmode,
5457de776d0dSPavana Sharma 	.port_setup_message_port = mv88e6xxx_setup_message_port,
5458de776d0dSPavana Sharma 	.port_set_upstream_port = mv88e6393x_port_set_upstream_port,
5459de776d0dSPavana Sharma 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
5460de776d0dSPavana Sharma 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
5461de776d0dSPavana Sharma 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
5462de776d0dSPavana Sharma 	.stats_get_strings = mv88e6320_stats_get_strings,
5463de776d0dSPavana Sharma 	.stats_get_stats = mv88e6390_stats_get_stats,
5464de776d0dSPavana Sharma 	/* .set_cpu_port is missing because this family does not support a global
5465de776d0dSPavana Sharma 	 * CPU port, only per port CPU port which is set via
5466de776d0dSPavana Sharma 	 * .port_set_upstream_port method.
5467de776d0dSPavana Sharma 	 */
5468de776d0dSPavana Sharma 	.set_egress_port = mv88e6393x_set_egress_port,
5469de776d0dSPavana Sharma 	.watchdog_ops = &mv88e6390_watchdog_ops,
5470de776d0dSPavana Sharma 	.mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu,
5471de776d0dSPavana Sharma 	.pot_clear = mv88e6xxx_g2_pot_clear,
5472de776d0dSPavana Sharma 	.reset = mv88e6352_g1_reset,
5473de776d0dSPavana Sharma 	.rmu_disable = mv88e6390_g1_rmu_disable,
5474de776d0dSPavana Sharma 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
5475de776d0dSPavana Sharma 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
5476de776d0dSPavana Sharma 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
5477de776d0dSPavana Sharma 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
547849c98c1dSTobias Waldekranz 	.stu_getnext = mv88e6390_g1_stu_getnext,
547949c98c1dSTobias Waldekranz 	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
5480de776d0dSPavana Sharma 	.serdes_power = mv88e6393x_serdes_power,
5481de776d0dSPavana Sharma 	.serdes_get_lane = mv88e6393x_serdes_get_lane,
5482de776d0dSPavana Sharma 	.serdes_pcs_get_state = mv88e6393x_serdes_pcs_get_state,
5483de776d0dSPavana Sharma 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
5484de776d0dSPavana Sharma 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
5485de776d0dSPavana Sharma 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
5486de776d0dSPavana Sharma 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
5487de776d0dSPavana Sharma 	.serdes_irq_enable = mv88e6393x_serdes_irq_enable,
5488de776d0dSPavana Sharma 	.serdes_irq_status = mv88e6393x_serdes_irq_status,
5489de776d0dSPavana Sharma 	/* TODO: serdes stats */
5490de776d0dSPavana Sharma 	.gpio_ops = &mv88e6352_gpio_ops,
5491de776d0dSPavana Sharma 	.avb_ops = &mv88e6390_avb_ops,
5492de776d0dSPavana Sharma 	.ptp_ops = &mv88e6352_ptp_ops,
5493d4ebf12bSRussell King (Oracle) 	.phylink_get_caps = mv88e6393x_phylink_get_caps,
5494de776d0dSPavana Sharma };
5495de776d0dSPavana Sharma 
5496fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = {
5497fad09c73SVivien Didelot 	[MV88E6085] = {
5498107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
5499fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6097,
5500fad09c73SVivien Didelot 		.name = "Marvell 88E6085",
5501fad09c73SVivien Didelot 		.num_databases = 4096,
5502d9ea5620SAndrew Lunn 		.num_macs = 8192,
5503fad09c73SVivien Didelot 		.num_ports = 10,
5504bc393155SAndrew Lunn 		.num_internal_phys = 5,
55053cf3c846SVivien Didelot 		.max_vid = 4095,
5506c050f5e9STobias Waldekranz 		.max_sid = 63,
5507fad09c73SVivien Didelot 		.port_base_addr = 0x10,
55089255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5509a935c052SVivien Didelot 		.global1_addr = 0x1b,
55109069c13aSVivien Didelot 		.global2_addr = 0x1c,
5511acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5512dc30c35bSAndrew Lunn 		.g1_irqs = 8,
5513d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5514e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5515f3645652SVivien Didelot 		.pvt = true,
5516b3e05aa1SVivien Didelot 		.multi_chip = true,
5517b3469dd8SVivien Didelot 		.ops = &mv88e6085_ops,
5518fad09c73SVivien Didelot 	},
5519fad09c73SVivien Didelot 
5520fad09c73SVivien Didelot 	[MV88E6095] = {
5521107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095,
5522fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6095,
5523fad09c73SVivien Didelot 		.name = "Marvell 88E6095/88E6095F",
5524fad09c73SVivien Didelot 		.num_databases = 256,
5525d9ea5620SAndrew Lunn 		.num_macs = 8192,
5526fad09c73SVivien Didelot 		.num_ports = 11,
5527bc393155SAndrew Lunn 		.num_internal_phys = 0,
55283cf3c846SVivien Didelot 		.max_vid = 4095,
5529fad09c73SVivien Didelot 		.port_base_addr = 0x10,
55309255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5531a935c052SVivien Didelot 		.global1_addr = 0x1b,
55329069c13aSVivien Didelot 		.global2_addr = 0x1c,
5533acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5534dc30c35bSAndrew Lunn 		.g1_irqs = 8,
5535e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5536b3e05aa1SVivien Didelot 		.multi_chip = true,
5537b3469dd8SVivien Didelot 		.ops = &mv88e6095_ops,
5538fad09c73SVivien Didelot 	},
5539fad09c73SVivien Didelot 
55407d381a02SStefan Eichenberger 	[MV88E6097] = {
5541107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097,
55427d381a02SStefan Eichenberger 		.family = MV88E6XXX_FAMILY_6097,
55437d381a02SStefan Eichenberger 		.name = "Marvell 88E6097/88E6097F",
55447d381a02SStefan Eichenberger 		.num_databases = 4096,
5545d9ea5620SAndrew Lunn 		.num_macs = 8192,
55467d381a02SStefan Eichenberger 		.num_ports = 11,
5547bc393155SAndrew Lunn 		.num_internal_phys = 8,
55483cf3c846SVivien Didelot 		.max_vid = 4095,
554949c98c1dSTobias Waldekranz 		.max_sid = 63,
55507d381a02SStefan Eichenberger 		.port_base_addr = 0x10,
55519255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
55527d381a02SStefan Eichenberger 		.global1_addr = 0x1b,
55539069c13aSVivien Didelot 		.global2_addr = 0x1c,
55547d381a02SStefan Eichenberger 		.age_time_coeff = 15000,
5555c534178bSStefan Eichenberger 		.g1_irqs = 8,
5556d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5557e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5558f3645652SVivien Didelot 		.pvt = true,
5559b3e05aa1SVivien Didelot 		.multi_chip = true,
5560670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
55617d381a02SStefan Eichenberger 		.ops = &mv88e6097_ops,
55627d381a02SStefan Eichenberger 	},
55637d381a02SStefan Eichenberger 
5564fad09c73SVivien Didelot 	[MV88E6123] = {
5565107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123,
5566fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
5567fad09c73SVivien Didelot 		.name = "Marvell 88E6123",
5568fad09c73SVivien Didelot 		.num_databases = 4096,
5569d9ea5620SAndrew Lunn 		.num_macs = 1024,
5570fad09c73SVivien Didelot 		.num_ports = 3,
5571bc393155SAndrew Lunn 		.num_internal_phys = 5,
55723cf3c846SVivien Didelot 		.max_vid = 4095,
5573c050f5e9STobias Waldekranz 		.max_sid = 63,
5574fad09c73SVivien Didelot 		.port_base_addr = 0x10,
55759255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5576a935c052SVivien Didelot 		.global1_addr = 0x1b,
55779069c13aSVivien Didelot 		.global2_addr = 0x1c,
5578acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5579dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5580d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5581e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5582f3645652SVivien Didelot 		.pvt = true,
5583b3e05aa1SVivien Didelot 		.multi_chip = true,
5584670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5585b3469dd8SVivien Didelot 		.ops = &mv88e6123_ops,
5586fad09c73SVivien Didelot 	},
5587fad09c73SVivien Didelot 
5588fad09c73SVivien Didelot 	[MV88E6131] = {
5589107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131,
5590fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
5591fad09c73SVivien Didelot 		.name = "Marvell 88E6131",
5592fad09c73SVivien Didelot 		.num_databases = 256,
5593d9ea5620SAndrew Lunn 		.num_macs = 8192,
5594fad09c73SVivien Didelot 		.num_ports = 8,
5595bc393155SAndrew Lunn 		.num_internal_phys = 0,
55963cf3c846SVivien Didelot 		.max_vid = 4095,
5597fad09c73SVivien Didelot 		.port_base_addr = 0x10,
55989255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5599a935c052SVivien Didelot 		.global1_addr = 0x1b,
56009069c13aSVivien Didelot 		.global2_addr = 0x1c,
5601acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5602dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5603e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5604b3e05aa1SVivien Didelot 		.multi_chip = true,
5605b3469dd8SVivien Didelot 		.ops = &mv88e6131_ops,
5606fad09c73SVivien Didelot 	},
5607fad09c73SVivien Didelot 
5608990e27b0SVivien Didelot 	[MV88E6141] = {
5609107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141,
5610990e27b0SVivien Didelot 		.family = MV88E6XXX_FAMILY_6341,
561179a68b26SUwe Kleine-König 		.name = "Marvell 88E6141",
5612990e27b0SVivien Didelot 		.num_databases = 4096,
5613d9ea5620SAndrew Lunn 		.num_macs = 2048,
5614990e27b0SVivien Didelot 		.num_ports = 6,
5615bc393155SAndrew Lunn 		.num_internal_phys = 5,
5616a73ccd61SBrandon Streiff 		.num_gpio = 11,
56173cf3c846SVivien Didelot 		.max_vid = 4095,
5618c050f5e9STobias Waldekranz 		.max_sid = 63,
5619990e27b0SVivien Didelot 		.port_base_addr = 0x10,
56209255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
5621990e27b0SVivien Didelot 		.global1_addr = 0x1b,
56229069c13aSVivien Didelot 		.global2_addr = 0x1c,
5623990e27b0SVivien Didelot 		.age_time_coeff = 3750,
5624990e27b0SVivien Didelot 		.atu_move_port_mask = 0x1f,
5625adfccf11SAndrew Lunn 		.g1_irqs = 9,
5626d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5627f3645652SVivien Didelot 		.pvt = true,
5628b3e05aa1SVivien Didelot 		.multi_chip = true,
5629670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5630990e27b0SVivien Didelot 		.ops = &mv88e6141_ops,
5631990e27b0SVivien Didelot 	},
5632990e27b0SVivien Didelot 
5633fad09c73SVivien Didelot 	[MV88E6161] = {
5634107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161,
5635fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
5636fad09c73SVivien Didelot 		.name = "Marvell 88E6161",
5637fad09c73SVivien Didelot 		.num_databases = 4096,
5638d9ea5620SAndrew Lunn 		.num_macs = 1024,
5639fad09c73SVivien Didelot 		.num_ports = 6,
5640bc393155SAndrew Lunn 		.num_internal_phys = 5,
56413cf3c846SVivien Didelot 		.max_vid = 4095,
5642c050f5e9STobias Waldekranz 		.max_sid = 63,
5643fad09c73SVivien Didelot 		.port_base_addr = 0x10,
56449255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5645a935c052SVivien Didelot 		.global1_addr = 0x1b,
56469069c13aSVivien Didelot 		.global2_addr = 0x1c,
5647acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5648dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5649d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5650e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5651f3645652SVivien Didelot 		.pvt = true,
5652b3e05aa1SVivien Didelot 		.multi_chip = true,
5653670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5654dfa54348SAndrew Lunn 		.ptp_support = true,
5655b3469dd8SVivien Didelot 		.ops = &mv88e6161_ops,
5656fad09c73SVivien Didelot 	},
5657fad09c73SVivien Didelot 
5658fad09c73SVivien Didelot 	[MV88E6165] = {
5659107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165,
5660fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
5661fad09c73SVivien Didelot 		.name = "Marvell 88E6165",
5662fad09c73SVivien Didelot 		.num_databases = 4096,
5663d9ea5620SAndrew Lunn 		.num_macs = 8192,
5664fad09c73SVivien Didelot 		.num_ports = 6,
5665bc393155SAndrew Lunn 		.num_internal_phys = 0,
56663cf3c846SVivien Didelot 		.max_vid = 4095,
5667c050f5e9STobias Waldekranz 		.max_sid = 63,
5668fad09c73SVivien Didelot 		.port_base_addr = 0x10,
56699255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5670a935c052SVivien Didelot 		.global1_addr = 0x1b,
56719069c13aSVivien Didelot 		.global2_addr = 0x1c,
5672acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5673dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5674d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5675e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5676f3645652SVivien Didelot 		.pvt = true,
5677b3e05aa1SVivien Didelot 		.multi_chip = true,
5678dfa54348SAndrew Lunn 		.ptp_support = true,
5679b3469dd8SVivien Didelot 		.ops = &mv88e6165_ops,
5680fad09c73SVivien Didelot 	},
5681fad09c73SVivien Didelot 
5682fad09c73SVivien Didelot 	[MV88E6171] = {
5683107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171,
5684fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5685fad09c73SVivien Didelot 		.name = "Marvell 88E6171",
5686fad09c73SVivien Didelot 		.num_databases = 4096,
5687d9ea5620SAndrew Lunn 		.num_macs = 8192,
5688fad09c73SVivien Didelot 		.num_ports = 7,
5689bc393155SAndrew Lunn 		.num_internal_phys = 5,
56903cf3c846SVivien Didelot 		.max_vid = 4095,
5691c050f5e9STobias Waldekranz 		.max_sid = 63,
5692fad09c73SVivien Didelot 		.port_base_addr = 0x10,
56939255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5694a935c052SVivien Didelot 		.global1_addr = 0x1b,
56959069c13aSVivien Didelot 		.global2_addr = 0x1c,
5696acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5697dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5698d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5699e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5700f3645652SVivien Didelot 		.pvt = true,
5701b3e05aa1SVivien Didelot 		.multi_chip = true,
5702670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5703b3469dd8SVivien Didelot 		.ops = &mv88e6171_ops,
5704fad09c73SVivien Didelot 	},
5705fad09c73SVivien Didelot 
5706fad09c73SVivien Didelot 	[MV88E6172] = {
5707107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172,
5708fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
5709fad09c73SVivien Didelot 		.name = "Marvell 88E6172",
5710fad09c73SVivien Didelot 		.num_databases = 4096,
5711d9ea5620SAndrew Lunn 		.num_macs = 8192,
5712fad09c73SVivien Didelot 		.num_ports = 7,
5713bc393155SAndrew Lunn 		.num_internal_phys = 5,
5714a73ccd61SBrandon Streiff 		.num_gpio = 15,
57153cf3c846SVivien Didelot 		.max_vid = 4095,
5716c050f5e9STobias Waldekranz 		.max_sid = 63,
5717fad09c73SVivien Didelot 		.port_base_addr = 0x10,
57189255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5719a935c052SVivien Didelot 		.global1_addr = 0x1b,
57209069c13aSVivien Didelot 		.global2_addr = 0x1c,
5721acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5722dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5723d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5724e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5725f3645652SVivien Didelot 		.pvt = true,
5726b3e05aa1SVivien Didelot 		.multi_chip = true,
5727670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5728b3469dd8SVivien Didelot 		.ops = &mv88e6172_ops,
5729fad09c73SVivien Didelot 	},
5730fad09c73SVivien Didelot 
5731fad09c73SVivien Didelot 	[MV88E6175] = {
5732107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175,
5733fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5734fad09c73SVivien Didelot 		.name = "Marvell 88E6175",
5735fad09c73SVivien Didelot 		.num_databases = 4096,
5736d9ea5620SAndrew Lunn 		.num_macs = 8192,
5737fad09c73SVivien Didelot 		.num_ports = 7,
5738bc393155SAndrew Lunn 		.num_internal_phys = 5,
57393cf3c846SVivien Didelot 		.max_vid = 4095,
5740c050f5e9STobias Waldekranz 		.max_sid = 63,
5741fad09c73SVivien Didelot 		.port_base_addr = 0x10,
57429255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5743a935c052SVivien Didelot 		.global1_addr = 0x1b,
57449069c13aSVivien Didelot 		.global2_addr = 0x1c,
5745acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5746dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5747d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5748e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5749f3645652SVivien Didelot 		.pvt = true,
5750b3e05aa1SVivien Didelot 		.multi_chip = true,
5751670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5752b3469dd8SVivien Didelot 		.ops = &mv88e6175_ops,
5753fad09c73SVivien Didelot 	},
5754fad09c73SVivien Didelot 
5755fad09c73SVivien Didelot 	[MV88E6176] = {
5756107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176,
5757fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
5758fad09c73SVivien Didelot 		.name = "Marvell 88E6176",
5759fad09c73SVivien Didelot 		.num_databases = 4096,
5760d9ea5620SAndrew Lunn 		.num_macs = 8192,
5761fad09c73SVivien Didelot 		.num_ports = 7,
5762bc393155SAndrew Lunn 		.num_internal_phys = 5,
5763a73ccd61SBrandon Streiff 		.num_gpio = 15,
57643cf3c846SVivien Didelot 		.max_vid = 4095,
5765c050f5e9STobias Waldekranz 		.max_sid = 63,
5766fad09c73SVivien Didelot 		.port_base_addr = 0x10,
57679255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5768a935c052SVivien Didelot 		.global1_addr = 0x1b,
57699069c13aSVivien Didelot 		.global2_addr = 0x1c,
5770acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5771dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5772d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5773e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5774f3645652SVivien Didelot 		.pvt = true,
5775b3e05aa1SVivien Didelot 		.multi_chip = true,
5776670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5777b3469dd8SVivien Didelot 		.ops = &mv88e6176_ops,
5778fad09c73SVivien Didelot 	},
5779fad09c73SVivien Didelot 
5780fad09c73SVivien Didelot 	[MV88E6185] = {
5781107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185,
5782fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
5783fad09c73SVivien Didelot 		.name = "Marvell 88E6185",
5784fad09c73SVivien Didelot 		.num_databases = 256,
5785d9ea5620SAndrew Lunn 		.num_macs = 8192,
5786fad09c73SVivien Didelot 		.num_ports = 10,
5787bc393155SAndrew Lunn 		.num_internal_phys = 0,
57883cf3c846SVivien Didelot 		.max_vid = 4095,
5789fad09c73SVivien Didelot 		.port_base_addr = 0x10,
57909255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5791a935c052SVivien Didelot 		.global1_addr = 0x1b,
57929069c13aSVivien Didelot 		.global2_addr = 0x1c,
5793acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5794dc30c35bSAndrew Lunn 		.g1_irqs = 8,
5795e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5796b3e05aa1SVivien Didelot 		.multi_chip = true,
5797670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5798b3469dd8SVivien Didelot 		.ops = &mv88e6185_ops,
5799fad09c73SVivien Didelot 	},
5800fad09c73SVivien Didelot 
58011a3b39ecSAndrew Lunn 	[MV88E6190] = {
5802107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190,
58031a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
58041a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190",
58051a3b39ecSAndrew Lunn 		.num_databases = 4096,
5806d9ea5620SAndrew Lunn 		.num_macs = 16384,
58071a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
580895150f29SHeiner Kallweit 		.num_internal_phys = 9,
5809a73ccd61SBrandon Streiff 		.num_gpio = 16,
5810931d1822SVivien Didelot 		.max_vid = 8191,
581149c98c1dSTobias Waldekranz 		.max_sid = 63,
58121a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
58139255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
58141a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
58159069c13aSVivien Didelot 		.global2_addr = 0x1c,
5816b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
58171a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5818d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5819f3645652SVivien Didelot 		.pvt = true,
5820b3e05aa1SVivien Didelot 		.multi_chip = true,
5821e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
58221a3b39ecSAndrew Lunn 		.ops = &mv88e6190_ops,
58231a3b39ecSAndrew Lunn 	},
58241a3b39ecSAndrew Lunn 
58251a3b39ecSAndrew Lunn 	[MV88E6190X] = {
5826107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X,
58271a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
58281a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190X",
58291a3b39ecSAndrew Lunn 		.num_databases = 4096,
5830d9ea5620SAndrew Lunn 		.num_macs = 16384,
58311a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
583295150f29SHeiner Kallweit 		.num_internal_phys = 9,
5833a73ccd61SBrandon Streiff 		.num_gpio = 16,
5834931d1822SVivien Didelot 		.max_vid = 8191,
583549c98c1dSTobias Waldekranz 		.max_sid = 63,
58361a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
58379255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
58381a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
58399069c13aSVivien Didelot 		.global2_addr = 0x1c,
5840b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
58411a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5842d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5843e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5844f3645652SVivien Didelot 		.pvt = true,
5845b3e05aa1SVivien Didelot 		.multi_chip = true,
58461a3b39ecSAndrew Lunn 		.ops = &mv88e6190x_ops,
58471a3b39ecSAndrew Lunn 	},
58481a3b39ecSAndrew Lunn 
58491a3b39ecSAndrew Lunn 	[MV88E6191] = {
5850107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191,
58511a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
58521a3b39ecSAndrew Lunn 		.name = "Marvell 88E6191",
58531a3b39ecSAndrew Lunn 		.num_databases = 4096,
5854d9ea5620SAndrew Lunn 		.num_macs = 16384,
58551a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
585695150f29SHeiner Kallweit 		.num_internal_phys = 9,
5857931d1822SVivien Didelot 		.max_vid = 8191,
585849c98c1dSTobias Waldekranz 		.max_sid = 63,
58591a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
58609255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
58611a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
58629069c13aSVivien Didelot 		.global2_addr = 0x1c,
5863b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
5864443d5a1bSAndrew Lunn 		.g1_irqs = 9,
5865d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5866e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5867f3645652SVivien Didelot 		.pvt = true,
5868b3e05aa1SVivien Didelot 		.multi_chip = true,
58692fa8d3afSBrandon Streiff 		.ptp_support = true,
58702cf4cefbSVivien Didelot 		.ops = &mv88e6191_ops,
58711a3b39ecSAndrew Lunn 	},
58721a3b39ecSAndrew Lunn 
5873de776d0dSPavana Sharma 	[MV88E6191X] = {
5874de776d0dSPavana Sharma 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X,
5875de776d0dSPavana Sharma 		.family = MV88E6XXX_FAMILY_6393,
5876de776d0dSPavana Sharma 		.name = "Marvell 88E6191X",
5877de776d0dSPavana Sharma 		.num_databases = 4096,
5878de776d0dSPavana Sharma 		.num_ports = 11,	/* 10 + Z80 */
5879de776d0dSPavana Sharma 		.num_internal_phys = 9,
5880de776d0dSPavana Sharma 		.max_vid = 8191,
588149c98c1dSTobias Waldekranz 		.max_sid = 63,
5882de776d0dSPavana Sharma 		.port_base_addr = 0x0,
5883de776d0dSPavana Sharma 		.phy_base_addr = 0x0,
5884de776d0dSPavana Sharma 		.global1_addr = 0x1b,
5885de776d0dSPavana Sharma 		.global2_addr = 0x1c,
5886de776d0dSPavana Sharma 		.age_time_coeff = 3750,
5887de776d0dSPavana Sharma 		.g1_irqs = 10,
5888de776d0dSPavana Sharma 		.g2_irqs = 14,
5889de776d0dSPavana Sharma 		.atu_move_port_mask = 0x1f,
5890de776d0dSPavana Sharma 		.pvt = true,
5891de776d0dSPavana Sharma 		.multi_chip = true,
5892de776d0dSPavana Sharma 		.ptp_support = true,
5893de776d0dSPavana Sharma 		.ops = &mv88e6393x_ops,
5894de776d0dSPavana Sharma 	},
5895de776d0dSPavana Sharma 
5896de776d0dSPavana Sharma 	[MV88E6193X] = {
5897de776d0dSPavana Sharma 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6193X,
5898de776d0dSPavana Sharma 		.family = MV88E6XXX_FAMILY_6393,
5899de776d0dSPavana Sharma 		.name = "Marvell 88E6193X",
5900de776d0dSPavana Sharma 		.num_databases = 4096,
5901de776d0dSPavana Sharma 		.num_ports = 11,	/* 10 + Z80 */
5902de776d0dSPavana Sharma 		.num_internal_phys = 9,
5903de776d0dSPavana Sharma 		.max_vid = 8191,
590449c98c1dSTobias Waldekranz 		.max_sid = 63,
5905de776d0dSPavana Sharma 		.port_base_addr = 0x0,
5906de776d0dSPavana Sharma 		.phy_base_addr = 0x0,
5907de776d0dSPavana Sharma 		.global1_addr = 0x1b,
5908de776d0dSPavana Sharma 		.global2_addr = 0x1c,
5909de776d0dSPavana Sharma 		.age_time_coeff = 3750,
5910de776d0dSPavana Sharma 		.g1_irqs = 10,
5911de776d0dSPavana Sharma 		.g2_irqs = 14,
5912de776d0dSPavana Sharma 		.atu_move_port_mask = 0x1f,
5913de776d0dSPavana Sharma 		.pvt = true,
5914de776d0dSPavana Sharma 		.multi_chip = true,
5915de776d0dSPavana Sharma 		.ptp_support = true,
5916de776d0dSPavana Sharma 		.ops = &mv88e6393x_ops,
5917de776d0dSPavana Sharma 	},
5918de776d0dSPavana Sharma 
591949022647SHubert Feurstein 	[MV88E6220] = {
592049022647SHubert Feurstein 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
592149022647SHubert Feurstein 		.family = MV88E6XXX_FAMILY_6250,
592249022647SHubert Feurstein 		.name = "Marvell 88E6220",
592349022647SHubert Feurstein 		.num_databases = 64,
592449022647SHubert Feurstein 
592549022647SHubert Feurstein 		/* Ports 2-4 are not routed to pins
592649022647SHubert Feurstein 		 * => usable ports 0, 1, 5, 6
592749022647SHubert Feurstein 		 */
592849022647SHubert Feurstein 		.num_ports = 7,
592949022647SHubert Feurstein 		.num_internal_phys = 2,
5930c857486aSHubert Feurstein 		.invalid_port_mask = BIT(2) | BIT(3) | BIT(4),
593149022647SHubert Feurstein 		.max_vid = 4095,
593249022647SHubert Feurstein 		.port_base_addr = 0x08,
593349022647SHubert Feurstein 		.phy_base_addr = 0x00,
593449022647SHubert Feurstein 		.global1_addr = 0x0f,
593549022647SHubert Feurstein 		.global2_addr = 0x07,
593649022647SHubert Feurstein 		.age_time_coeff = 15000,
593749022647SHubert Feurstein 		.g1_irqs = 9,
593849022647SHubert Feurstein 		.g2_irqs = 10,
593949022647SHubert Feurstein 		.atu_move_port_mask = 0xf,
594049022647SHubert Feurstein 		.dual_chip = true,
594171509614SHubert Feurstein 		.ptp_support = true,
594249022647SHubert Feurstein 		.ops = &mv88e6250_ops,
594349022647SHubert Feurstein 	},
594449022647SHubert Feurstein 
5945fad09c73SVivien Didelot 	[MV88E6240] = {
5946107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240,
5947fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
5948fad09c73SVivien Didelot 		.name = "Marvell 88E6240",
5949fad09c73SVivien Didelot 		.num_databases = 4096,
5950d9ea5620SAndrew Lunn 		.num_macs = 8192,
5951fad09c73SVivien Didelot 		.num_ports = 7,
5952bc393155SAndrew Lunn 		.num_internal_phys = 5,
5953a73ccd61SBrandon Streiff 		.num_gpio = 15,
59543cf3c846SVivien Didelot 		.max_vid = 4095,
5955c050f5e9STobias Waldekranz 		.max_sid = 63,
5956fad09c73SVivien Didelot 		.port_base_addr = 0x10,
59579255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5958a935c052SVivien Didelot 		.global1_addr = 0x1b,
59599069c13aSVivien Didelot 		.global2_addr = 0x1c,
5960acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5961dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5962d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5963e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5964f3645652SVivien Didelot 		.pvt = true,
5965b3e05aa1SVivien Didelot 		.multi_chip = true,
5966670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
59672fa8d3afSBrandon Streiff 		.ptp_support = true,
5968b3469dd8SVivien Didelot 		.ops = &mv88e6240_ops,
5969fad09c73SVivien Didelot 	},
5970fad09c73SVivien Didelot 
59711f71836fSRasmus Villemoes 	[MV88E6250] = {
59721f71836fSRasmus Villemoes 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250,
59731f71836fSRasmus Villemoes 		.family = MV88E6XXX_FAMILY_6250,
59741f71836fSRasmus Villemoes 		.name = "Marvell 88E6250",
59751f71836fSRasmus Villemoes 		.num_databases = 64,
59761f71836fSRasmus Villemoes 		.num_ports = 7,
59771f71836fSRasmus Villemoes 		.num_internal_phys = 5,
59781f71836fSRasmus Villemoes 		.max_vid = 4095,
59791f71836fSRasmus Villemoes 		.port_base_addr = 0x08,
59801f71836fSRasmus Villemoes 		.phy_base_addr = 0x00,
59811f71836fSRasmus Villemoes 		.global1_addr = 0x0f,
59821f71836fSRasmus Villemoes 		.global2_addr = 0x07,
59831f71836fSRasmus Villemoes 		.age_time_coeff = 15000,
59841f71836fSRasmus Villemoes 		.g1_irqs = 9,
59851f71836fSRasmus Villemoes 		.g2_irqs = 10,
59861f71836fSRasmus Villemoes 		.atu_move_port_mask = 0xf,
59871f71836fSRasmus Villemoes 		.dual_chip = true,
598871509614SHubert Feurstein 		.ptp_support = true,
59891f71836fSRasmus Villemoes 		.ops = &mv88e6250_ops,
59901f71836fSRasmus Villemoes 	},
59911f71836fSRasmus Villemoes 
59921a3b39ecSAndrew Lunn 	[MV88E6290] = {
5993107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
59941a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
59951a3b39ecSAndrew Lunn 		.name = "Marvell 88E6290",
59961a3b39ecSAndrew Lunn 		.num_databases = 4096,
59971a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
599895150f29SHeiner Kallweit 		.num_internal_phys = 9,
5999a73ccd61SBrandon Streiff 		.num_gpio = 16,
6000931d1822SVivien Didelot 		.max_vid = 8191,
6001c050f5e9STobias Waldekranz 		.max_sid = 63,
60021a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
60039255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
60041a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
60059069c13aSVivien Didelot 		.global2_addr = 0x1c,
6006b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
60071a3b39ecSAndrew Lunn 		.g1_irqs = 9,
6008d6c5e6afSVivien Didelot 		.g2_irqs = 14,
6009e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
6010f3645652SVivien Didelot 		.pvt = true,
6011b3e05aa1SVivien Didelot 		.multi_chip = true,
60122fa8d3afSBrandon Streiff 		.ptp_support = true,
60131a3b39ecSAndrew Lunn 		.ops = &mv88e6290_ops,
60141a3b39ecSAndrew Lunn 	},
60151a3b39ecSAndrew Lunn 
6016fad09c73SVivien Didelot 	[MV88E6320] = {
6017107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320,
6018fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
6019fad09c73SVivien Didelot 		.name = "Marvell 88E6320",
6020fad09c73SVivien Didelot 		.num_databases = 4096,
6021d9ea5620SAndrew Lunn 		.num_macs = 8192,
6022fad09c73SVivien Didelot 		.num_ports = 7,
6023bc393155SAndrew Lunn 		.num_internal_phys = 5,
6024a73ccd61SBrandon Streiff 		.num_gpio = 15,
60253cf3c846SVivien Didelot 		.max_vid = 4095,
6026fad09c73SVivien Didelot 		.port_base_addr = 0x10,
60279255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
6028a935c052SVivien Didelot 		.global1_addr = 0x1b,
60299069c13aSVivien Didelot 		.global2_addr = 0x1c,
6030acddbd21SVivien Didelot 		.age_time_coeff = 15000,
6031dc30c35bSAndrew Lunn 		.g1_irqs = 8,
6032bc393155SAndrew Lunn 		.g2_irqs = 10,
6033e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
6034f3645652SVivien Didelot 		.pvt = true,
6035b3e05aa1SVivien Didelot 		.multi_chip = true,
6036670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
60372fa8d3afSBrandon Streiff 		.ptp_support = true,
6038b3469dd8SVivien Didelot 		.ops = &mv88e6320_ops,
6039fad09c73SVivien Didelot 	},
6040fad09c73SVivien Didelot 
6041fad09c73SVivien Didelot 	[MV88E6321] = {
6042107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321,
6043fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
6044fad09c73SVivien Didelot 		.name = "Marvell 88E6321",
6045fad09c73SVivien Didelot 		.num_databases = 4096,
6046d9ea5620SAndrew Lunn 		.num_macs = 8192,
6047fad09c73SVivien Didelot 		.num_ports = 7,
6048bc393155SAndrew Lunn 		.num_internal_phys = 5,
6049a73ccd61SBrandon Streiff 		.num_gpio = 15,
60503cf3c846SVivien Didelot 		.max_vid = 4095,
6051fad09c73SVivien Didelot 		.port_base_addr = 0x10,
60529255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
6053a935c052SVivien Didelot 		.global1_addr = 0x1b,
60549069c13aSVivien Didelot 		.global2_addr = 0x1c,
6055acddbd21SVivien Didelot 		.age_time_coeff = 15000,
6056dc30c35bSAndrew Lunn 		.g1_irqs = 8,
6057bc393155SAndrew Lunn 		.g2_irqs = 10,
6058e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
6059b3e05aa1SVivien Didelot 		.multi_chip = true,
6060670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
60612fa8d3afSBrandon Streiff 		.ptp_support = true,
6062b3469dd8SVivien Didelot 		.ops = &mv88e6321_ops,
6063fad09c73SVivien Didelot 	},
6064fad09c73SVivien Didelot 
6065a75961d0SGregory CLEMENT 	[MV88E6341] = {
6066107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
6067a75961d0SGregory CLEMENT 		.family = MV88E6XXX_FAMILY_6341,
6068a75961d0SGregory CLEMENT 		.name = "Marvell 88E6341",
6069a75961d0SGregory CLEMENT 		.num_databases = 4096,
6070d9ea5620SAndrew Lunn 		.num_macs = 2048,
6071bc393155SAndrew Lunn 		.num_internal_phys = 5,
6072a75961d0SGregory CLEMENT 		.num_ports = 6,
6073a73ccd61SBrandon Streiff 		.num_gpio = 11,
60743cf3c846SVivien Didelot 		.max_vid = 4095,
6075c050f5e9STobias Waldekranz 		.max_sid = 63,
6076a75961d0SGregory CLEMENT 		.port_base_addr = 0x10,
60779255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
6078a75961d0SGregory CLEMENT 		.global1_addr = 0x1b,
60799069c13aSVivien Didelot 		.global2_addr = 0x1c,
6080a75961d0SGregory CLEMENT 		.age_time_coeff = 3750,
6081e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
6082adfccf11SAndrew Lunn 		.g1_irqs = 9,
6083d6c5e6afSVivien Didelot 		.g2_irqs = 10,
6084f3645652SVivien Didelot 		.pvt = true,
6085b3e05aa1SVivien Didelot 		.multi_chip = true,
6086670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
60872fa8d3afSBrandon Streiff 		.ptp_support = true,
6088a75961d0SGregory CLEMENT 		.ops = &mv88e6341_ops,
6089a75961d0SGregory CLEMENT 	},
6090a75961d0SGregory CLEMENT 
6091fad09c73SVivien Didelot 	[MV88E6350] = {
6092107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350,
6093fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
6094fad09c73SVivien Didelot 		.name = "Marvell 88E6350",
6095fad09c73SVivien Didelot 		.num_databases = 4096,
6096d9ea5620SAndrew Lunn 		.num_macs = 8192,
6097fad09c73SVivien Didelot 		.num_ports = 7,
6098bc393155SAndrew Lunn 		.num_internal_phys = 5,
60993cf3c846SVivien Didelot 		.max_vid = 4095,
6100c050f5e9STobias Waldekranz 		.max_sid = 63,
6101fad09c73SVivien Didelot 		.port_base_addr = 0x10,
61029255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
6103a935c052SVivien Didelot 		.global1_addr = 0x1b,
61049069c13aSVivien Didelot 		.global2_addr = 0x1c,
6105acddbd21SVivien Didelot 		.age_time_coeff = 15000,
6106dc30c35bSAndrew Lunn 		.g1_irqs = 9,
6107d6c5e6afSVivien Didelot 		.g2_irqs = 10,
6108e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
6109f3645652SVivien Didelot 		.pvt = true,
6110b3e05aa1SVivien Didelot 		.multi_chip = true,
6111670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
6112b3469dd8SVivien Didelot 		.ops = &mv88e6350_ops,
6113fad09c73SVivien Didelot 	},
6114fad09c73SVivien Didelot 
6115fad09c73SVivien Didelot 	[MV88E6351] = {
6116107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351,
6117fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
6118fad09c73SVivien Didelot 		.name = "Marvell 88E6351",
6119fad09c73SVivien Didelot 		.num_databases = 4096,
6120d9ea5620SAndrew Lunn 		.num_macs = 8192,
6121fad09c73SVivien Didelot 		.num_ports = 7,
6122bc393155SAndrew Lunn 		.num_internal_phys = 5,
61233cf3c846SVivien Didelot 		.max_vid = 4095,
6124c050f5e9STobias Waldekranz 		.max_sid = 63,
6125fad09c73SVivien Didelot 		.port_base_addr = 0x10,
61269255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
6127a935c052SVivien Didelot 		.global1_addr = 0x1b,
61289069c13aSVivien Didelot 		.global2_addr = 0x1c,
6129acddbd21SVivien Didelot 		.age_time_coeff = 15000,
6130dc30c35bSAndrew Lunn 		.g1_irqs = 9,
6131d6c5e6afSVivien Didelot 		.g2_irqs = 10,
6132e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
6133f3645652SVivien Didelot 		.pvt = true,
6134b3e05aa1SVivien Didelot 		.multi_chip = true,
6135670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
6136b3469dd8SVivien Didelot 		.ops = &mv88e6351_ops,
6137fad09c73SVivien Didelot 	},
6138fad09c73SVivien Didelot 
6139fad09c73SVivien Didelot 	[MV88E6352] = {
6140107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352,
6141fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
6142fad09c73SVivien Didelot 		.name = "Marvell 88E6352",
6143fad09c73SVivien Didelot 		.num_databases = 4096,
6144d9ea5620SAndrew Lunn 		.num_macs = 8192,
6145fad09c73SVivien Didelot 		.num_ports = 7,
6146bc393155SAndrew Lunn 		.num_internal_phys = 5,
6147a73ccd61SBrandon Streiff 		.num_gpio = 15,
61483cf3c846SVivien Didelot 		.max_vid = 4095,
614949c98c1dSTobias Waldekranz 		.max_sid = 63,
6150fad09c73SVivien Didelot 		.port_base_addr = 0x10,
61519255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
6152a935c052SVivien Didelot 		.global1_addr = 0x1b,
61539069c13aSVivien Didelot 		.global2_addr = 0x1c,
6154acddbd21SVivien Didelot 		.age_time_coeff = 15000,
6155dc30c35bSAndrew Lunn 		.g1_irqs = 9,
6156d6c5e6afSVivien Didelot 		.g2_irqs = 10,
6157e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
6158f3645652SVivien Didelot 		.pvt = true,
6159b3e05aa1SVivien Didelot 		.multi_chip = true,
6160670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
61612fa8d3afSBrandon Streiff 		.ptp_support = true,
6162b3469dd8SVivien Didelot 		.ops = &mv88e6352_ops,
6163fad09c73SVivien Didelot 	},
61641a3b39ecSAndrew Lunn 	[MV88E6390] = {
6165107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
61661a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
61671a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390",
61681a3b39ecSAndrew Lunn 		.num_databases = 4096,
6169d9ea5620SAndrew Lunn 		.num_macs = 16384,
61701a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
617195150f29SHeiner Kallweit 		.num_internal_phys = 9,
6172a73ccd61SBrandon Streiff 		.num_gpio = 16,
6173931d1822SVivien Didelot 		.max_vid = 8191,
617449c98c1dSTobias Waldekranz 		.max_sid = 63,
61751a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
61769255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
61771a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
61789069c13aSVivien Didelot 		.global2_addr = 0x1c,
6179b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
61801a3b39ecSAndrew Lunn 		.g1_irqs = 9,
6181d6c5e6afSVivien Didelot 		.g2_irqs = 14,
6182e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
6183f3645652SVivien Didelot 		.pvt = true,
6184b3e05aa1SVivien Didelot 		.multi_chip = true,
6185670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED,
61862fa8d3afSBrandon Streiff 		.ptp_support = true,
61871a3b39ecSAndrew Lunn 		.ops = &mv88e6390_ops,
61881a3b39ecSAndrew Lunn 	},
61891a3b39ecSAndrew Lunn 	[MV88E6390X] = {
6190107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X,
61911a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
61921a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390X",
61931a3b39ecSAndrew Lunn 		.num_databases = 4096,
6194d9ea5620SAndrew Lunn 		.num_macs = 16384,
61951a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
619695150f29SHeiner Kallweit 		.num_internal_phys = 9,
6197a73ccd61SBrandon Streiff 		.num_gpio = 16,
6198931d1822SVivien Didelot 		.max_vid = 8191,
619949c98c1dSTobias Waldekranz 		.max_sid = 63,
62001a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
62019255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
62021a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
62039069c13aSVivien Didelot 		.global2_addr = 0x1c,
6204b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
62051a3b39ecSAndrew Lunn 		.g1_irqs = 9,
6206d6c5e6afSVivien Didelot 		.g2_irqs = 14,
6207e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
6208f3645652SVivien Didelot 		.pvt = true,
6209b3e05aa1SVivien Didelot 		.multi_chip = true,
6210670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED,
62112fa8d3afSBrandon Streiff 		.ptp_support = true,
62121a3b39ecSAndrew Lunn 		.ops = &mv88e6390x_ops,
62131a3b39ecSAndrew Lunn 	},
6214de776d0dSPavana Sharma 
6215de776d0dSPavana Sharma 	[MV88E6393X] = {
6216de776d0dSPavana Sharma 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
6217de776d0dSPavana Sharma 		.family = MV88E6XXX_FAMILY_6393,
6218de776d0dSPavana Sharma 		.name = "Marvell 88E6393X",
6219de776d0dSPavana Sharma 		.num_databases = 4096,
6220de776d0dSPavana Sharma 		.num_ports = 11,	/* 10 + Z80 */
6221de776d0dSPavana Sharma 		.num_internal_phys = 9,
6222de776d0dSPavana Sharma 		.max_vid = 8191,
622349c98c1dSTobias Waldekranz 		.max_sid = 63,
6224de776d0dSPavana Sharma 		.port_base_addr = 0x0,
6225de776d0dSPavana Sharma 		.phy_base_addr = 0x0,
6226de776d0dSPavana Sharma 		.global1_addr = 0x1b,
6227de776d0dSPavana Sharma 		.global2_addr = 0x1c,
6228de776d0dSPavana Sharma 		.age_time_coeff = 3750,
6229de776d0dSPavana Sharma 		.g1_irqs = 10,
6230de776d0dSPavana Sharma 		.g2_irqs = 14,
6231de776d0dSPavana Sharma 		.atu_move_port_mask = 0x1f,
6232de776d0dSPavana Sharma 		.pvt = true,
6233de776d0dSPavana Sharma 		.multi_chip = true,
6234de776d0dSPavana Sharma 		.ptp_support = true,
6235de776d0dSPavana Sharma 		.ops = &mv88e6393x_ops,
6236de776d0dSPavana Sharma 	},
6237fad09c73SVivien Didelot };
6238fad09c73SVivien Didelot 
6239fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
6240fad09c73SVivien Didelot {
6241fad09c73SVivien Didelot 	int i;
6242fad09c73SVivien Didelot 
6243fad09c73SVivien Didelot 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
6244fad09c73SVivien Didelot 		if (mv88e6xxx_table[i].prod_num == prod_num)
6245fad09c73SVivien Didelot 			return &mv88e6xxx_table[i];
6246fad09c73SVivien Didelot 
6247fad09c73SVivien Didelot 	return NULL;
6248fad09c73SVivien Didelot }
6249fad09c73SVivien Didelot 
6250fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
6251fad09c73SVivien Didelot {
6252fad09c73SVivien Didelot 	const struct mv88e6xxx_info *info;
62538f6345b2SVivien Didelot 	unsigned int prod_num, rev;
62548f6345b2SVivien Didelot 	u16 id;
62558f6345b2SVivien Didelot 	int err;
6256fad09c73SVivien Didelot 
6257c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
6258107fcc10SVivien Didelot 	err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
6259c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
62608f6345b2SVivien Didelot 	if (err)
62618f6345b2SVivien Didelot 		return err;
6262fad09c73SVivien Didelot 
6263107fcc10SVivien Didelot 	prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK;
6264107fcc10SVivien Didelot 	rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK;
6265fad09c73SVivien Didelot 
6266fad09c73SVivien Didelot 	info = mv88e6xxx_lookup_info(prod_num);
6267fad09c73SVivien Didelot 	if (!info)
6268fad09c73SVivien Didelot 		return -ENODEV;
6269fad09c73SVivien Didelot 
6270fad09c73SVivien Didelot 	/* Update the compatible info with the probed one */
6271fad09c73SVivien Didelot 	chip->info = info;
6272fad09c73SVivien Didelot 
6273fad09c73SVivien Didelot 	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
6274fad09c73SVivien Didelot 		 chip->info->prod_num, chip->info->name, rev);
6275fad09c73SVivien Didelot 
6276fad09c73SVivien Didelot 	return 0;
6277fad09c73SVivien Didelot }
6278fad09c73SVivien Didelot 
62795da66099SNathan Rossi static int mv88e6xxx_single_chip_detect(struct mv88e6xxx_chip *chip,
62805da66099SNathan Rossi 					struct mdio_device *mdiodev)
62815da66099SNathan Rossi {
62825da66099SNathan Rossi 	int err;
62835da66099SNathan Rossi 
62845da66099SNathan Rossi 	/* dual_chip takes precedence over single/multi-chip modes */
62855da66099SNathan Rossi 	if (chip->info->dual_chip)
62865da66099SNathan Rossi 		return -EINVAL;
62875da66099SNathan Rossi 
62885da66099SNathan Rossi 	/* If the mdio addr is 16 indicating the first port address of a switch
62895da66099SNathan Rossi 	 * (e.g. mv88e6*41) in single chip addressing mode the device may be
62905da66099SNathan Rossi 	 * configured in single chip addressing mode. Setup the smi access as
62915da66099SNathan Rossi 	 * single chip addressing mode and attempt to detect the model of the
62925da66099SNathan Rossi 	 * switch, if this fails the device is not configured in single chip
62935da66099SNathan Rossi 	 * addressing mode.
62945da66099SNathan Rossi 	 */
62955da66099SNathan Rossi 	if (mdiodev->addr != 16)
62965da66099SNathan Rossi 		return -EINVAL;
62975da66099SNathan Rossi 
62985da66099SNathan Rossi 	err = mv88e6xxx_smi_init(chip, mdiodev->bus, 0);
62995da66099SNathan Rossi 	if (err)
63005da66099SNathan Rossi 		return err;
63015da66099SNathan Rossi 
63025da66099SNathan Rossi 	return mv88e6xxx_detect(chip);
63035da66099SNathan Rossi }
63045da66099SNathan Rossi 
6305fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
6306fad09c73SVivien Didelot {
6307fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
6308fad09c73SVivien Didelot 
6309fad09c73SVivien Didelot 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
6310fad09c73SVivien Didelot 	if (!chip)
6311fad09c73SVivien Didelot 		return NULL;
6312fad09c73SVivien Didelot 
6313fad09c73SVivien Didelot 	chip->dev = dev;
6314fad09c73SVivien Didelot 
6315fad09c73SVivien Didelot 	mutex_init(&chip->reg_lock);
6316a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&chip->mdios);
6317da7dc875SVivien Didelot 	idr_init(&chip->policies);
6318acaf4d2eSTobias Waldekranz 	INIT_LIST_HEAD(&chip->msts);
6319fad09c73SVivien Didelot 
6320fad09c73SVivien Didelot 	return chip;
6321fad09c73SVivien Didelot }
6322fad09c73SVivien Didelot 
63235ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
63244d776482SFlorian Fainelli 							int port,
63254d776482SFlorian Fainelli 							enum dsa_tag_protocol m)
63267b314362SAndrew Lunn {
632704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
63282bbb33beSAndrew Lunn 
6329670bb80fSTobias Waldekranz 	return chip->tag_protocol;
63307b314362SAndrew Lunn }
63317b314362SAndrew Lunn 
6332*bacf93b0SVladimir Oltean static int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds,
63339a99bef5STobias Waldekranz 					 enum dsa_tag_protocol proto)
63349a99bef5STobias Waldekranz {
63359a99bef5STobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
63369a99bef5STobias Waldekranz 	enum dsa_tag_protocol old_protocol;
6337*bacf93b0SVladimir Oltean 	struct dsa_port *cpu_dp;
63389a99bef5STobias Waldekranz 	int err;
63399a99bef5STobias Waldekranz 
63409a99bef5STobias Waldekranz 	switch (proto) {
63419a99bef5STobias Waldekranz 	case DSA_TAG_PROTO_EDSA:
63429a99bef5STobias Waldekranz 		switch (chip->info->edsa_support) {
63439a99bef5STobias Waldekranz 		case MV88E6XXX_EDSA_UNSUPPORTED:
63449a99bef5STobias Waldekranz 			return -EPROTONOSUPPORT;
63459a99bef5STobias Waldekranz 		case MV88E6XXX_EDSA_UNDOCUMENTED:
63469a99bef5STobias Waldekranz 			dev_warn(chip->dev, "Relying on undocumented EDSA tagging behavior\n");
63479a99bef5STobias Waldekranz 			fallthrough;
63489a99bef5STobias Waldekranz 		case MV88E6XXX_EDSA_SUPPORTED:
63499a99bef5STobias Waldekranz 			break;
63509a99bef5STobias Waldekranz 		}
63519a99bef5STobias Waldekranz 		break;
63529a99bef5STobias Waldekranz 	case DSA_TAG_PROTO_DSA:
63539a99bef5STobias Waldekranz 		break;
63549a99bef5STobias Waldekranz 	default:
63559a99bef5STobias Waldekranz 		return -EPROTONOSUPPORT;
63569a99bef5STobias Waldekranz 	}
63579a99bef5STobias Waldekranz 
63589a99bef5STobias Waldekranz 	old_protocol = chip->tag_protocol;
63599a99bef5STobias Waldekranz 	chip->tag_protocol = proto;
63609a99bef5STobias Waldekranz 
63619a99bef5STobias Waldekranz 	mv88e6xxx_reg_lock(chip);
6362*bacf93b0SVladimir Oltean 	dsa_switch_for_each_cpu_port(cpu_dp, ds) {
6363*bacf93b0SVladimir Oltean 		err = mv88e6xxx_setup_port_mode(chip, cpu_dp->index);
6364*bacf93b0SVladimir Oltean 		if (err) {
6365*bacf93b0SVladimir Oltean 			mv88e6xxx_reg_unlock(chip);
6366*bacf93b0SVladimir Oltean 			goto unwind;
6367*bacf93b0SVladimir Oltean 		}
6368*bacf93b0SVladimir Oltean 	}
63699a99bef5STobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
63709a99bef5STobias Waldekranz 
6371*bacf93b0SVladimir Oltean 	return 0;
6372*bacf93b0SVladimir Oltean 
6373*bacf93b0SVladimir Oltean unwind:
63749a99bef5STobias Waldekranz 	chip->tag_protocol = old_protocol;
63759a99bef5STobias Waldekranz 
6376*bacf93b0SVladimir Oltean 	mv88e6xxx_reg_lock(chip);
6377*bacf93b0SVladimir Oltean 	dsa_switch_for_each_cpu_port_continue_reverse(cpu_dp, ds)
6378*bacf93b0SVladimir Oltean 		mv88e6xxx_setup_port_mode(chip, cpu_dp->index);
6379*bacf93b0SVladimir Oltean 	mv88e6xxx_reg_unlock(chip);
6380*bacf93b0SVladimir Oltean 
63819a99bef5STobias Waldekranz 	return err;
63829a99bef5STobias Waldekranz }
63839a99bef5STobias Waldekranz 
6384a52b2da7SVladimir Oltean static int mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
6385c2693363SVladimir Oltean 				  const struct switchdev_obj_port_mdb *mdb,
6386c2693363SVladimir Oltean 				  struct dsa_db db)
63877df8fbddSVivien Didelot {
638804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
6389a52b2da7SVladimir Oltean 	int err;
63907df8fbddSVivien Didelot 
6391c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
6392a52b2da7SVladimir Oltean 	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
6393a52b2da7SVladimir Oltean 					   MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC);
6394c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
6395a52b2da7SVladimir Oltean 
6396a52b2da7SVladimir Oltean 	return err;
63977df8fbddSVivien Didelot }
63987df8fbddSVivien Didelot 
63997df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
6400c2693363SVladimir Oltean 				  const struct switchdev_obj_port_mdb *mdb,
6401c2693363SVladimir Oltean 				  struct dsa_db db)
64027df8fbddSVivien Didelot {
640304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
64047df8fbddSVivien Didelot 	int err;
64057df8fbddSVivien Didelot 
6406c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
6407d8291a95SVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0);
6408c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
64097df8fbddSVivien Didelot 
64107df8fbddSVivien Didelot 	return err;
64117df8fbddSVivien Didelot }
64127df8fbddSVivien Didelot 
6413f0942e00SIwan R Timmer static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
6414f0942e00SIwan R Timmer 				     struct dsa_mall_mirror_tc_entry *mirror,
64150148bb50SVladimir Oltean 				     bool ingress,
64160148bb50SVladimir Oltean 				     struct netlink_ext_ack *extack)
6417f0942e00SIwan R Timmer {
6418f0942e00SIwan R Timmer 	enum mv88e6xxx_egress_direction direction = ingress ?
6419f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS :
6420f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS;
6421f0942e00SIwan R Timmer 	struct mv88e6xxx_chip *chip = ds->priv;
6422f0942e00SIwan R Timmer 	bool other_mirrors = false;
6423f0942e00SIwan R Timmer 	int i;
6424f0942e00SIwan R Timmer 	int err;
6425f0942e00SIwan R Timmer 
6426f0942e00SIwan R Timmer 	mutex_lock(&chip->reg_lock);
6427f0942e00SIwan R Timmer 	if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
6428f0942e00SIwan R Timmer 	    mirror->to_local_port) {
6429f0942e00SIwan R Timmer 		for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
6430f0942e00SIwan R Timmer 			other_mirrors |= ingress ?
6431f0942e00SIwan R Timmer 					 chip->ports[i].mirror_ingress :
6432f0942e00SIwan R Timmer 					 chip->ports[i].mirror_egress;
6433f0942e00SIwan R Timmer 
6434f0942e00SIwan R Timmer 		/* Can't change egress port when other mirror is active */
6435f0942e00SIwan R Timmer 		if (other_mirrors) {
6436f0942e00SIwan R Timmer 			err = -EBUSY;
6437f0942e00SIwan R Timmer 			goto out;
6438f0942e00SIwan R Timmer 		}
6439f0942e00SIwan R Timmer 
64402fda45f0SMarek Behún 		err = mv88e6xxx_set_egress_port(chip, direction,
6441f0942e00SIwan R Timmer 						mirror->to_local_port);
6442f0942e00SIwan R Timmer 		if (err)
6443f0942e00SIwan R Timmer 			goto out;
6444f0942e00SIwan R Timmer 	}
6445f0942e00SIwan R Timmer 
6446f0942e00SIwan R Timmer 	err = mv88e6xxx_port_set_mirror(chip, port, direction, true);
6447f0942e00SIwan R Timmer out:
6448f0942e00SIwan R Timmer 	mutex_unlock(&chip->reg_lock);
6449f0942e00SIwan R Timmer 
6450f0942e00SIwan R Timmer 	return err;
6451f0942e00SIwan R Timmer }
6452f0942e00SIwan R Timmer 
6453f0942e00SIwan R Timmer static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
6454f0942e00SIwan R Timmer 				      struct dsa_mall_mirror_tc_entry *mirror)
6455f0942e00SIwan R Timmer {
6456f0942e00SIwan R Timmer 	enum mv88e6xxx_egress_direction direction = mirror->ingress ?
6457f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS :
6458f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS;
6459f0942e00SIwan R Timmer 	struct mv88e6xxx_chip *chip = ds->priv;
6460f0942e00SIwan R Timmer 	bool other_mirrors = false;
6461f0942e00SIwan R Timmer 	int i;
6462f0942e00SIwan R Timmer 
6463f0942e00SIwan R Timmer 	mutex_lock(&chip->reg_lock);
6464f0942e00SIwan R Timmer 	if (mv88e6xxx_port_set_mirror(chip, port, direction, false))
6465f0942e00SIwan R Timmer 		dev_err(ds->dev, "p%d: failed to disable mirroring\n", port);
6466f0942e00SIwan R Timmer 
6467f0942e00SIwan R Timmer 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
6468f0942e00SIwan R Timmer 		other_mirrors |= mirror->ingress ?
6469f0942e00SIwan R Timmer 				 chip->ports[i].mirror_ingress :
6470f0942e00SIwan R Timmer 				 chip->ports[i].mirror_egress;
6471f0942e00SIwan R Timmer 
6472f0942e00SIwan R Timmer 	/* Reset egress port when no other mirror is active */
6473f0942e00SIwan R Timmer 	if (!other_mirrors) {
64742fda45f0SMarek Behún 		if (mv88e6xxx_set_egress_port(chip, direction,
64752fda45f0SMarek Behún 					      dsa_upstream_port(ds, port)))
6476f0942e00SIwan R Timmer 			dev_err(ds->dev, "failed to set egress port\n");
6477f0942e00SIwan R Timmer 	}
6478f0942e00SIwan R Timmer 
6479f0942e00SIwan R Timmer 	mutex_unlock(&chip->reg_lock);
6480f0942e00SIwan R Timmer }
6481f0942e00SIwan R Timmer 
6482a8b659e7SVladimir Oltean static int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port,
6483a8b659e7SVladimir Oltean 					   struct switchdev_brport_flags flags,
6484a8b659e7SVladimir Oltean 					   struct netlink_ext_ack *extack)
6485a8b659e7SVladimir Oltean {
6486a8b659e7SVladimir Oltean 	struct mv88e6xxx_chip *chip = ds->priv;
6487a8b659e7SVladimir Oltean 	const struct mv88e6xxx_ops *ops;
6488a8b659e7SVladimir Oltean 
64898d1d8298STobias Waldekranz 	if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
649034ea415fSHans Schultz 			   BR_BCAST_FLOOD | BR_PORT_LOCKED))
6491a8b659e7SVladimir Oltean 		return -EINVAL;
6492a8b659e7SVladimir Oltean 
6493a8b659e7SVladimir Oltean 	ops = chip->info->ops;
6494a8b659e7SVladimir Oltean 
6495a8b659e7SVladimir Oltean 	if ((flags.mask & BR_FLOOD) && !ops->port_set_ucast_flood)
6496a8b659e7SVladimir Oltean 		return -EINVAL;
6497a8b659e7SVladimir Oltean 
6498a8b659e7SVladimir Oltean 	if ((flags.mask & BR_MCAST_FLOOD) && !ops->port_set_mcast_flood)
6499a8b659e7SVladimir Oltean 		return -EINVAL;
6500a8b659e7SVladimir Oltean 
6501a8b659e7SVladimir Oltean 	return 0;
6502a8b659e7SVladimir Oltean }
6503a8b659e7SVladimir Oltean 
6504a8b659e7SVladimir Oltean static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
6505a8b659e7SVladimir Oltean 				       struct switchdev_brport_flags flags,
6506a8b659e7SVladimir Oltean 				       struct netlink_ext_ack *extack)
65074f85901fSRussell King {
65084f85901fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
65094f85901fSRussell King 	int err = -EOPNOTSUPP;
65104f85901fSRussell King 
6511c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
6512a8b659e7SVladimir Oltean 
6513041bd545STobias Waldekranz 	if (flags.mask & BR_LEARNING) {
6514041bd545STobias Waldekranz 		bool learning = !!(flags.val & BR_LEARNING);
6515041bd545STobias Waldekranz 		u16 pav = learning ? (1 << port) : 0;
6516041bd545STobias Waldekranz 
6517041bd545STobias Waldekranz 		err = mv88e6xxx_port_set_assoc_vector(chip, port, pav);
6518041bd545STobias Waldekranz 		if (err)
6519041bd545STobias Waldekranz 			goto out;
6520041bd545STobias Waldekranz 	}
6521041bd545STobias Waldekranz 
6522a8b659e7SVladimir Oltean 	if (flags.mask & BR_FLOOD) {
6523a8b659e7SVladimir Oltean 		bool unicast = !!(flags.val & BR_FLOOD);
6524a8b659e7SVladimir Oltean 
6525a8b659e7SVladimir Oltean 		err = chip->info->ops->port_set_ucast_flood(chip, port,
6526a8b659e7SVladimir Oltean 							    unicast);
6527a8b659e7SVladimir Oltean 		if (err)
6528a8b659e7SVladimir Oltean 			goto out;
6529a8b659e7SVladimir Oltean 	}
6530a8b659e7SVladimir Oltean 
6531a8b659e7SVladimir Oltean 	if (flags.mask & BR_MCAST_FLOOD) {
6532a8b659e7SVladimir Oltean 		bool multicast = !!(flags.val & BR_MCAST_FLOOD);
6533a8b659e7SVladimir Oltean 
6534a8b659e7SVladimir Oltean 		err = chip->info->ops->port_set_mcast_flood(chip, port,
65354f85901fSRussell King 							    multicast);
6536a8b659e7SVladimir Oltean 		if (err)
6537a8b659e7SVladimir Oltean 			goto out;
6538a8b659e7SVladimir Oltean 	}
6539a8b659e7SVladimir Oltean 
65408d1d8298STobias Waldekranz 	if (flags.mask & BR_BCAST_FLOOD) {
65418d1d8298STobias Waldekranz 		bool broadcast = !!(flags.val & BR_BCAST_FLOOD);
65428d1d8298STobias Waldekranz 
65438d1d8298STobias Waldekranz 		err = mv88e6xxx_port_broadcast_sync(chip, port, broadcast);
65448d1d8298STobias Waldekranz 		if (err)
65458d1d8298STobias Waldekranz 			goto out;
65468d1d8298STobias Waldekranz 	}
65478d1d8298STobias Waldekranz 
654834ea415fSHans Schultz 	if (flags.mask & BR_PORT_LOCKED) {
654934ea415fSHans Schultz 		bool locked = !!(flags.val & BR_PORT_LOCKED);
655034ea415fSHans Schultz 
655134ea415fSHans Schultz 		err = mv88e6xxx_port_set_lock(chip, port, locked);
655234ea415fSHans Schultz 		if (err)
655334ea415fSHans Schultz 			goto out;
655434ea415fSHans Schultz 	}
6555a8b659e7SVladimir Oltean out:
6556a8b659e7SVladimir Oltean 	mv88e6xxx_reg_unlock(chip);
6557a8b659e7SVladimir Oltean 
6558a8b659e7SVladimir Oltean 	return err;
6559a8b659e7SVladimir Oltean }
6560a8b659e7SVladimir Oltean 
656157e661aaSTobias Waldekranz static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds,
6562dedd6a00SVladimir Oltean 				      struct dsa_lag lag,
656357e661aaSTobias Waldekranz 				      struct netdev_lag_upper_info *info)
656457e661aaSTobias Waldekranz {
6565b80dc51bSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
656657e661aaSTobias Waldekranz 	struct dsa_port *dp;
6567dedd6a00SVladimir Oltean 	int members = 0;
656857e661aaSTobias Waldekranz 
6569b80dc51bSTobias Waldekranz 	if (!mv88e6xxx_has_lag(chip))
6570b80dc51bSTobias Waldekranz 		return false;
6571b80dc51bSTobias Waldekranz 
6572dedd6a00SVladimir Oltean 	if (!lag.id)
657357e661aaSTobias Waldekranz 		return false;
657457e661aaSTobias Waldekranz 
6575dedd6a00SVladimir Oltean 	dsa_lag_foreach_port(dp, ds->dst, &lag)
657657e661aaSTobias Waldekranz 		/* Includes the port joining the LAG */
657757e661aaSTobias Waldekranz 		members++;
657857e661aaSTobias Waldekranz 
657957e661aaSTobias Waldekranz 	if (members > 8)
658057e661aaSTobias Waldekranz 		return false;
658157e661aaSTobias Waldekranz 
658257e661aaSTobias Waldekranz 	/* We could potentially relax this to include active
658357e661aaSTobias Waldekranz 	 * backup in the future.
658457e661aaSTobias Waldekranz 	 */
658557e661aaSTobias Waldekranz 	if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH)
658657e661aaSTobias Waldekranz 		return false;
658757e661aaSTobias Waldekranz 
658857e661aaSTobias Waldekranz 	/* Ideally we would also validate that the hash type matches
658957e661aaSTobias Waldekranz 	 * the hardware. Alas, this is always set to unknown on team
659057e661aaSTobias Waldekranz 	 * interfaces.
659157e661aaSTobias Waldekranz 	 */
659257e661aaSTobias Waldekranz 	return true;
659357e661aaSTobias Waldekranz }
659457e661aaSTobias Waldekranz 
6595dedd6a00SVladimir Oltean static int mv88e6xxx_lag_sync_map(struct dsa_switch *ds, struct dsa_lag lag)
659657e661aaSTobias Waldekranz {
659757e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
659857e661aaSTobias Waldekranz 	struct dsa_port *dp;
659957e661aaSTobias Waldekranz 	u16 map = 0;
660057e661aaSTobias Waldekranz 	int id;
660157e661aaSTobias Waldekranz 
66023d4a0a2aSVladimir Oltean 	/* DSA LAG IDs are one-based, hardware is zero-based */
6603dedd6a00SVladimir Oltean 	id = lag.id - 1;
660457e661aaSTobias Waldekranz 
660557e661aaSTobias Waldekranz 	/* Build the map of all ports to distribute flows destined for
660657e661aaSTobias Waldekranz 	 * this LAG. This can be either a local user port, or a DSA
660757e661aaSTobias Waldekranz 	 * port if the LAG port is on a remote chip.
660857e661aaSTobias Waldekranz 	 */
6609dedd6a00SVladimir Oltean 	dsa_lag_foreach_port(dp, ds->dst, &lag)
661057e661aaSTobias Waldekranz 		map |= BIT(dsa_towards_port(ds, dp->ds->index, dp->index));
661157e661aaSTobias Waldekranz 
661257e661aaSTobias Waldekranz 	return mv88e6xxx_g2_trunk_mapping_write(chip, id, map);
661357e661aaSTobias Waldekranz }
661457e661aaSTobias Waldekranz 
661557e661aaSTobias Waldekranz static const u8 mv88e6xxx_lag_mask_table[8][8] = {
661657e661aaSTobias Waldekranz 	/* Row number corresponds to the number of active members in a
661757e661aaSTobias Waldekranz 	 * LAG. Each column states which of the eight hash buckets are
661857e661aaSTobias Waldekranz 	 * mapped to the column:th port in the LAG.
661957e661aaSTobias Waldekranz 	 *
662057e661aaSTobias Waldekranz 	 * Example: In a LAG with three active ports, the second port
662157e661aaSTobias Waldekranz 	 * ([2][1]) would be selected for traffic mapped to buckets
662257e661aaSTobias Waldekranz 	 * 3,4,5 (0x38).
662357e661aaSTobias Waldekranz 	 */
662457e661aaSTobias Waldekranz 	{ 0xff,    0,    0,    0,    0,    0,    0,    0 },
662557e661aaSTobias Waldekranz 	{ 0x0f, 0xf0,    0,    0,    0,    0,    0,    0 },
662657e661aaSTobias Waldekranz 	{ 0x07, 0x38, 0xc0,    0,    0,    0,    0,    0 },
662757e661aaSTobias Waldekranz 	{ 0x03, 0x0c, 0x30, 0xc0,    0,    0,    0,    0 },
662857e661aaSTobias Waldekranz 	{ 0x03, 0x0c, 0x30, 0x40, 0x80,    0,    0,    0 },
662957e661aaSTobias Waldekranz 	{ 0x03, 0x0c, 0x10, 0x20, 0x40, 0x80,    0,    0 },
663057e661aaSTobias Waldekranz 	{ 0x03, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,    0 },
663157e661aaSTobias Waldekranz 	{ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 },
663257e661aaSTobias Waldekranz };
663357e661aaSTobias Waldekranz 
663457e661aaSTobias Waldekranz static void mv88e6xxx_lag_set_port_mask(u16 *mask, int port,
663557e661aaSTobias Waldekranz 					int num_tx, int nth)
663657e661aaSTobias Waldekranz {
663757e661aaSTobias Waldekranz 	u8 active = 0;
663857e661aaSTobias Waldekranz 	int i;
663957e661aaSTobias Waldekranz 
664057e661aaSTobias Waldekranz 	num_tx = num_tx <= 8 ? num_tx : 8;
664157e661aaSTobias Waldekranz 	if (nth < num_tx)
664257e661aaSTobias Waldekranz 		active = mv88e6xxx_lag_mask_table[num_tx - 1][nth];
664357e661aaSTobias Waldekranz 
664457e661aaSTobias Waldekranz 	for (i = 0; i < 8; i++) {
664557e661aaSTobias Waldekranz 		if (BIT(i) & active)
664657e661aaSTobias Waldekranz 			mask[i] |= BIT(port);
664757e661aaSTobias Waldekranz 	}
664857e661aaSTobias Waldekranz }
664957e661aaSTobias Waldekranz 
665057e661aaSTobias Waldekranz static int mv88e6xxx_lag_sync_masks(struct dsa_switch *ds)
665157e661aaSTobias Waldekranz {
665257e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
665357e661aaSTobias Waldekranz 	unsigned int id, num_tx;
665457e661aaSTobias Waldekranz 	struct dsa_port *dp;
6655dedd6a00SVladimir Oltean 	struct dsa_lag *lag;
665657e661aaSTobias Waldekranz 	int i, err, nth;
665757e661aaSTobias Waldekranz 	u16 mask[8];
665857e661aaSTobias Waldekranz 	u16 ivec;
665957e661aaSTobias Waldekranz 
666057e661aaSTobias Waldekranz 	/* Assume no port is a member of any LAG. */
666157e661aaSTobias Waldekranz 	ivec = BIT(mv88e6xxx_num_ports(chip)) - 1;
666257e661aaSTobias Waldekranz 
666357e661aaSTobias Waldekranz 	/* Disable all masks for ports that _are_ members of a LAG. */
6664b99dbdf0SVladimir Oltean 	dsa_switch_for_each_port(dp, ds) {
6665dedd6a00SVladimir Oltean 		if (!dp->lag)
666657e661aaSTobias Waldekranz 			continue;
666757e661aaSTobias Waldekranz 
666857e661aaSTobias Waldekranz 		ivec &= ~BIT(dp->index);
666957e661aaSTobias Waldekranz 	}
667057e661aaSTobias Waldekranz 
667157e661aaSTobias Waldekranz 	for (i = 0; i < 8; i++)
667257e661aaSTobias Waldekranz 		mask[i] = ivec;
667357e661aaSTobias Waldekranz 
667457e661aaSTobias Waldekranz 	/* Enable the correct subset of masks for all LAG ports that
667557e661aaSTobias Waldekranz 	 * are in the Tx set.
667657e661aaSTobias Waldekranz 	 */
667757e661aaSTobias Waldekranz 	dsa_lags_foreach_id(id, ds->dst) {
6678dedd6a00SVladimir Oltean 		lag = dsa_lag_by_id(ds->dst, id);
6679dedd6a00SVladimir Oltean 		if (!lag)
668057e661aaSTobias Waldekranz 			continue;
668157e661aaSTobias Waldekranz 
668257e661aaSTobias Waldekranz 		num_tx = 0;
6683dedd6a00SVladimir Oltean 		dsa_lag_foreach_port(dp, ds->dst, lag) {
668457e661aaSTobias Waldekranz 			if (dp->lag_tx_enabled)
668557e661aaSTobias Waldekranz 				num_tx++;
668657e661aaSTobias Waldekranz 		}
668757e661aaSTobias Waldekranz 
668857e661aaSTobias Waldekranz 		if (!num_tx)
668957e661aaSTobias Waldekranz 			continue;
669057e661aaSTobias Waldekranz 
669157e661aaSTobias Waldekranz 		nth = 0;
6692dedd6a00SVladimir Oltean 		dsa_lag_foreach_port(dp, ds->dst, lag) {
669357e661aaSTobias Waldekranz 			if (!dp->lag_tx_enabled)
669457e661aaSTobias Waldekranz 				continue;
669557e661aaSTobias Waldekranz 
669657e661aaSTobias Waldekranz 			if (dp->ds == ds)
669757e661aaSTobias Waldekranz 				mv88e6xxx_lag_set_port_mask(mask, dp->index,
669857e661aaSTobias Waldekranz 							    num_tx, nth);
669957e661aaSTobias Waldekranz 
670057e661aaSTobias Waldekranz 			nth++;
670157e661aaSTobias Waldekranz 		}
670257e661aaSTobias Waldekranz 	}
670357e661aaSTobias Waldekranz 
670457e661aaSTobias Waldekranz 	for (i = 0; i < 8; i++) {
670557e661aaSTobias Waldekranz 		err = mv88e6xxx_g2_trunk_mask_write(chip, i, true, mask[i]);
670657e661aaSTobias Waldekranz 		if (err)
670757e661aaSTobias Waldekranz 			return err;
670857e661aaSTobias Waldekranz 	}
670957e661aaSTobias Waldekranz 
671057e661aaSTobias Waldekranz 	return 0;
671157e661aaSTobias Waldekranz }
671257e661aaSTobias Waldekranz 
671357e661aaSTobias Waldekranz static int mv88e6xxx_lag_sync_masks_map(struct dsa_switch *ds,
6714dedd6a00SVladimir Oltean 					struct dsa_lag lag)
671557e661aaSTobias Waldekranz {
671657e661aaSTobias Waldekranz 	int err;
671757e661aaSTobias Waldekranz 
671857e661aaSTobias Waldekranz 	err = mv88e6xxx_lag_sync_masks(ds);
671957e661aaSTobias Waldekranz 
672057e661aaSTobias Waldekranz 	if (!err)
6721dedd6a00SVladimir Oltean 		err = mv88e6xxx_lag_sync_map(ds, lag);
672257e661aaSTobias Waldekranz 
672357e661aaSTobias Waldekranz 	return err;
672457e661aaSTobias Waldekranz }
672557e661aaSTobias Waldekranz 
672657e661aaSTobias Waldekranz static int mv88e6xxx_port_lag_change(struct dsa_switch *ds, int port)
672757e661aaSTobias Waldekranz {
672857e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
672957e661aaSTobias Waldekranz 	int err;
673057e661aaSTobias Waldekranz 
673157e661aaSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
673257e661aaSTobias Waldekranz 	err = mv88e6xxx_lag_sync_masks(ds);
673357e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
673457e661aaSTobias Waldekranz 	return err;
673557e661aaSTobias Waldekranz }
673657e661aaSTobias Waldekranz 
673757e661aaSTobias Waldekranz static int mv88e6xxx_port_lag_join(struct dsa_switch *ds, int port,
6738dedd6a00SVladimir Oltean 				   struct dsa_lag lag,
673957e661aaSTobias Waldekranz 				   struct netdev_lag_upper_info *info)
674057e661aaSTobias Waldekranz {
674157e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
674257e661aaSTobias Waldekranz 	int err, id;
674357e661aaSTobias Waldekranz 
6744dedd6a00SVladimir Oltean 	if (!mv88e6xxx_lag_can_offload(ds, lag, info))
674557e661aaSTobias Waldekranz 		return -EOPNOTSUPP;
674657e661aaSTobias Waldekranz 
67473d4a0a2aSVladimir Oltean 	/* DSA LAG IDs are one-based */
6748dedd6a00SVladimir Oltean 	id = lag.id - 1;
674957e661aaSTobias Waldekranz 
675057e661aaSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
675157e661aaSTobias Waldekranz 
675257e661aaSTobias Waldekranz 	err = mv88e6xxx_port_set_trunk(chip, port, true, id);
675357e661aaSTobias Waldekranz 	if (err)
675457e661aaSTobias Waldekranz 		goto err_unlock;
675557e661aaSTobias Waldekranz 
6756dedd6a00SVladimir Oltean 	err = mv88e6xxx_lag_sync_masks_map(ds, lag);
675757e661aaSTobias Waldekranz 	if (err)
675857e661aaSTobias Waldekranz 		goto err_clear_trunk;
675957e661aaSTobias Waldekranz 
676057e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
676157e661aaSTobias Waldekranz 	return 0;
676257e661aaSTobias Waldekranz 
676357e661aaSTobias Waldekranz err_clear_trunk:
676457e661aaSTobias Waldekranz 	mv88e6xxx_port_set_trunk(chip, port, false, 0);
676557e661aaSTobias Waldekranz err_unlock:
676657e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
676757e661aaSTobias Waldekranz 	return err;
676857e661aaSTobias Waldekranz }
676957e661aaSTobias Waldekranz 
677057e661aaSTobias Waldekranz static int mv88e6xxx_port_lag_leave(struct dsa_switch *ds, int port,
6771dedd6a00SVladimir Oltean 				    struct dsa_lag lag)
677257e661aaSTobias Waldekranz {
677357e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
677457e661aaSTobias Waldekranz 	int err_sync, err_trunk;
677557e661aaSTobias Waldekranz 
677657e661aaSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
6777dedd6a00SVladimir Oltean 	err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag);
677857e661aaSTobias Waldekranz 	err_trunk = mv88e6xxx_port_set_trunk(chip, port, false, 0);
677957e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
678057e661aaSTobias Waldekranz 	return err_sync ? : err_trunk;
678157e661aaSTobias Waldekranz }
678257e661aaSTobias Waldekranz 
678357e661aaSTobias Waldekranz static int mv88e6xxx_crosschip_lag_change(struct dsa_switch *ds, int sw_index,
678457e661aaSTobias Waldekranz 					  int port)
678557e661aaSTobias Waldekranz {
678657e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
678757e661aaSTobias Waldekranz 	int err;
678857e661aaSTobias Waldekranz 
678957e661aaSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
679057e661aaSTobias Waldekranz 	err = mv88e6xxx_lag_sync_masks(ds);
679157e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
679257e661aaSTobias Waldekranz 	return err;
679357e661aaSTobias Waldekranz }
679457e661aaSTobias Waldekranz 
679557e661aaSTobias Waldekranz static int mv88e6xxx_crosschip_lag_join(struct dsa_switch *ds, int sw_index,
6796dedd6a00SVladimir Oltean 					int port, struct dsa_lag lag,
679757e661aaSTobias Waldekranz 					struct netdev_lag_upper_info *info)
679857e661aaSTobias Waldekranz {
679957e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
680057e661aaSTobias Waldekranz 	int err;
680157e661aaSTobias Waldekranz 
6802dedd6a00SVladimir Oltean 	if (!mv88e6xxx_lag_can_offload(ds, lag, info))
680357e661aaSTobias Waldekranz 		return -EOPNOTSUPP;
680457e661aaSTobias Waldekranz 
680557e661aaSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
680657e661aaSTobias Waldekranz 
6807dedd6a00SVladimir Oltean 	err = mv88e6xxx_lag_sync_masks_map(ds, lag);
680857e661aaSTobias Waldekranz 	if (err)
680957e661aaSTobias Waldekranz 		goto unlock;
681057e661aaSTobias Waldekranz 
681157e661aaSTobias Waldekranz 	err = mv88e6xxx_pvt_map(chip, sw_index, port);
681257e661aaSTobias Waldekranz 
681357e661aaSTobias Waldekranz unlock:
681457e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
681557e661aaSTobias Waldekranz 	return err;
681657e661aaSTobias Waldekranz }
681757e661aaSTobias Waldekranz 
681857e661aaSTobias Waldekranz static int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index,
6819dedd6a00SVladimir Oltean 					 int port, struct dsa_lag lag)
682057e661aaSTobias Waldekranz {
682157e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
682257e661aaSTobias Waldekranz 	int err_sync, err_pvt;
682357e661aaSTobias Waldekranz 
682457e661aaSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
6825dedd6a00SVladimir Oltean 	err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag);
682657e661aaSTobias Waldekranz 	err_pvt = mv88e6xxx_pvt_map(chip, sw_index, port);
682757e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
682857e661aaSTobias Waldekranz 	return err_sync ? : err_pvt;
682957e661aaSTobias Waldekranz }
683057e661aaSTobias Waldekranz 
6831a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
68327b314362SAndrew Lunn 	.get_tag_protocol	= mv88e6xxx_get_tag_protocol,
68339a99bef5STobias Waldekranz 	.change_tag_protocol	= mv88e6xxx_change_tag_protocol,
6834fad09c73SVivien Didelot 	.setup			= mv88e6xxx_setup,
683523e8b470SAndrew Lunn 	.teardown		= mv88e6xxx_teardown,
6836fd292c18SVladimir Oltean 	.port_setup		= mv88e6xxx_port_setup,
6837fd292c18SVladimir Oltean 	.port_teardown		= mv88e6xxx_port_teardown,
6838d4ebf12bSRussell King (Oracle) 	.phylink_get_caps	= mv88e6xxx_get_caps,
6839a5a6858bSRussell King 	.phylink_mac_link_state	= mv88e6xxx_serdes_pcs_get_state,
6840c9a2356fSRussell King 	.phylink_mac_config	= mv88e6xxx_mac_config,
6841a5a6858bSRussell King 	.phylink_mac_an_restart	= mv88e6xxx_serdes_pcs_an_restart,
6842c9a2356fSRussell King 	.phylink_mac_link_down	= mv88e6xxx_mac_link_down,
6843c9a2356fSRussell King 	.phylink_mac_link_up	= mv88e6xxx_mac_link_up,
6844fad09c73SVivien Didelot 	.get_strings		= mv88e6xxx_get_strings,
6845fad09c73SVivien Didelot 	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
6846fad09c73SVivien Didelot 	.get_sset_count		= mv88e6xxx_get_sset_count,
684704aca993SAndrew Lunn 	.port_enable		= mv88e6xxx_port_enable,
684804aca993SAndrew Lunn 	.port_disable		= mv88e6xxx_port_disable,
68492a550aecSAndrew Lunn 	.port_max_mtu		= mv88e6xxx_get_max_mtu,
68502a550aecSAndrew Lunn 	.port_change_mtu	= mv88e6xxx_change_mtu,
685108f50061SVivien Didelot 	.get_mac_eee		= mv88e6xxx_get_mac_eee,
685208f50061SVivien Didelot 	.set_mac_eee		= mv88e6xxx_set_mac_eee,
6853fad09c73SVivien Didelot 	.get_eeprom_len		= mv88e6xxx_get_eeprom_len,
6854fad09c73SVivien Didelot 	.get_eeprom		= mv88e6xxx_get_eeprom,
6855fad09c73SVivien Didelot 	.set_eeprom		= mv88e6xxx_set_eeprom,
6856fad09c73SVivien Didelot 	.get_regs_len		= mv88e6xxx_get_regs_len,
6857fad09c73SVivien Didelot 	.get_regs		= mv88e6xxx_get_regs,
6858da7dc875SVivien Didelot 	.get_rxnfc		= mv88e6xxx_get_rxnfc,
6859da7dc875SVivien Didelot 	.set_rxnfc		= mv88e6xxx_set_rxnfc,
68602cfcd964SVivien Didelot 	.set_ageing_time	= mv88e6xxx_set_ageing_time,
6861fad09c73SVivien Didelot 	.port_bridge_join	= mv88e6xxx_port_bridge_join,
6862fad09c73SVivien Didelot 	.port_bridge_leave	= mv88e6xxx_port_bridge_leave,
6863a8b659e7SVladimir Oltean 	.port_pre_bridge_flags	= mv88e6xxx_port_pre_bridge_flags,
6864a8b659e7SVladimir Oltean 	.port_bridge_flags	= mv88e6xxx_port_bridge_flags,
6865fad09c73SVivien Didelot 	.port_stp_state_set	= mv88e6xxx_port_stp_state_set,
6866acaf4d2eSTobias Waldekranz 	.port_mst_state_set	= mv88e6xxx_port_mst_state_set,
6867749efcb8SVivien Didelot 	.port_fast_age		= mv88e6xxx_port_fast_age,
6868acaf4d2eSTobias Waldekranz 	.port_vlan_fast_age	= mv88e6xxx_port_vlan_fast_age,
6869fad09c73SVivien Didelot 	.port_vlan_filtering	= mv88e6xxx_port_vlan_filtering,
6870fad09c73SVivien Didelot 	.port_vlan_add		= mv88e6xxx_port_vlan_add,
6871fad09c73SVivien Didelot 	.port_vlan_del		= mv88e6xxx_port_vlan_del,
6872acaf4d2eSTobias Waldekranz 	.vlan_msti_set		= mv88e6xxx_vlan_msti_set,
6873fad09c73SVivien Didelot 	.port_fdb_add		= mv88e6xxx_port_fdb_add,
6874fad09c73SVivien Didelot 	.port_fdb_del		= mv88e6xxx_port_fdb_del,
6875fad09c73SVivien Didelot 	.port_fdb_dump		= mv88e6xxx_port_fdb_dump,
68767df8fbddSVivien Didelot 	.port_mdb_add		= mv88e6xxx_port_mdb_add,
68777df8fbddSVivien Didelot 	.port_mdb_del		= mv88e6xxx_port_mdb_del,
6878f0942e00SIwan R Timmer 	.port_mirror_add	= mv88e6xxx_port_mirror_add,
6879f0942e00SIwan R Timmer 	.port_mirror_del	= mv88e6xxx_port_mirror_del,
6880aec5ac88SVivien Didelot 	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
6881aec5ac88SVivien Didelot 	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
6882c6fe0ad2SBrandon Streiff 	.port_hwtstamp_set	= mv88e6xxx_port_hwtstamp_set,
6883c6fe0ad2SBrandon Streiff 	.port_hwtstamp_get	= mv88e6xxx_port_hwtstamp_get,
6884c6fe0ad2SBrandon Streiff 	.port_txtstamp		= mv88e6xxx_port_txtstamp,
6885c6fe0ad2SBrandon Streiff 	.port_rxtstamp		= mv88e6xxx_port_rxtstamp,
6886c6fe0ad2SBrandon Streiff 	.get_ts_info		= mv88e6xxx_get_ts_info,
688723e8b470SAndrew Lunn 	.devlink_param_get	= mv88e6xxx_devlink_param_get,
688823e8b470SAndrew Lunn 	.devlink_param_set	= mv88e6xxx_devlink_param_set,
688993157307SAndrew Lunn 	.devlink_info_get	= mv88e6xxx_devlink_info_get,
689057e661aaSTobias Waldekranz 	.port_lag_change	= mv88e6xxx_port_lag_change,
689157e661aaSTobias Waldekranz 	.port_lag_join		= mv88e6xxx_port_lag_join,
689257e661aaSTobias Waldekranz 	.port_lag_leave		= mv88e6xxx_port_lag_leave,
689357e661aaSTobias Waldekranz 	.crosschip_lag_change	= mv88e6xxx_crosschip_lag_change,
689457e661aaSTobias Waldekranz 	.crosschip_lag_join	= mv88e6xxx_crosschip_lag_join,
689557e661aaSTobias Waldekranz 	.crosschip_lag_leave	= mv88e6xxx_crosschip_lag_leave,
6896fad09c73SVivien Didelot };
6897fad09c73SVivien Didelot 
689855ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
6899fad09c73SVivien Didelot {
6900fad09c73SVivien Didelot 	struct device *dev = chip->dev;
6901fad09c73SVivien Didelot 	struct dsa_switch *ds;
6902fad09c73SVivien Didelot 
69037e99e347SVivien Didelot 	ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
6904fad09c73SVivien Didelot 	if (!ds)
6905fad09c73SVivien Didelot 		return -ENOMEM;
6906fad09c73SVivien Didelot 
69077e99e347SVivien Didelot 	ds->dev = dev;
69087e99e347SVivien Didelot 	ds->num_ports = mv88e6xxx_num_ports(chip);
6909fad09c73SVivien Didelot 	ds->priv = chip;
6910877b7cb0SAndrew Lunn 	ds->dev = dev;
69119d490b4eSVivien Didelot 	ds->ops = &mv88e6xxx_switch_ops;
69129ff74f24SVivien Didelot 	ds->ageing_time_min = chip->info->age_time_coeff;
69139ff74f24SVivien Didelot 	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
6914fad09c73SVivien Didelot 
691557e661aaSTobias Waldekranz 	/* Some chips support up to 32, but that requires enabling the
691657e661aaSTobias Waldekranz 	 * 5-bit port mode, which we do not support. 640k^W16 ought to
691757e661aaSTobias Waldekranz 	 * be enough for anyone.
691857e661aaSTobias Waldekranz 	 */
6919b80dc51bSTobias Waldekranz 	ds->num_lag_ids = mv88e6xxx_has_lag(chip) ? 16 : 0;
692057e661aaSTobias Waldekranz 
6921fad09c73SVivien Didelot 	dev_set_drvdata(dev, ds);
6922fad09c73SVivien Didelot 
692323c9ee49SVivien Didelot 	return dsa_register_switch(ds);
6924fad09c73SVivien Didelot }
6925fad09c73SVivien Didelot 
6926fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
6927fad09c73SVivien Didelot {
6928fad09c73SVivien Didelot 	dsa_unregister_switch(chip->ds);
6929fad09c73SVivien Didelot }
6930fad09c73SVivien Didelot 
6931877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev)
6932877b7cb0SAndrew Lunn {
6933877b7cb0SAndrew Lunn 	const struct of_device_id *matches = dev->driver->of_match_table;
6934877b7cb0SAndrew Lunn 	const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data;
6935877b7cb0SAndrew Lunn 
6936877b7cb0SAndrew Lunn 	for (; matches->name[0] || matches->type[0] || matches->compatible[0];
6937877b7cb0SAndrew Lunn 	     matches++) {
6938877b7cb0SAndrew Lunn 		if (!strcmp(pdata->compatible, matches->compatible))
6939877b7cb0SAndrew Lunn 			return matches->data;
6940877b7cb0SAndrew Lunn 	}
6941877b7cb0SAndrew Lunn 	return NULL;
6942877b7cb0SAndrew Lunn }
6943877b7cb0SAndrew Lunn 
6944bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration
6945bcd3d9d9SMiquel Raynal  * would be lost after a power cycle so prevent it to be suspended.
6946bcd3d9d9SMiquel Raynal  */
6947bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev)
6948bcd3d9d9SMiquel Raynal {
6949bcd3d9d9SMiquel Raynal 	return -EOPNOTSUPP;
6950bcd3d9d9SMiquel Raynal }
6951bcd3d9d9SMiquel Raynal 
6952bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev)
6953bcd3d9d9SMiquel Raynal {
6954bcd3d9d9SMiquel Raynal 	return 0;
6955bcd3d9d9SMiquel Raynal }
6956bcd3d9d9SMiquel Raynal 
6957bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume);
6958bcd3d9d9SMiquel Raynal 
6959fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev)
6960fad09c73SVivien Didelot {
6961877b7cb0SAndrew Lunn 	struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data;
69627ddae24fSDavid S. Miller 	const struct mv88e6xxx_info *compat_info = NULL;
6963fad09c73SVivien Didelot 	struct device *dev = &mdiodev->dev;
6964fad09c73SVivien Didelot 	struct device_node *np = dev->of_node;
6965fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
6966877b7cb0SAndrew Lunn 	int port;
6967fad09c73SVivien Didelot 	int err;
6968fad09c73SVivien Didelot 
69697bb8c996SAndrew Lunn 	if (!np && !pdata)
69707bb8c996SAndrew Lunn 		return -EINVAL;
69717bb8c996SAndrew Lunn 
6972877b7cb0SAndrew Lunn 	if (np)
6973fad09c73SVivien Didelot 		compat_info = of_device_get_match_data(dev);
6974877b7cb0SAndrew Lunn 
6975877b7cb0SAndrew Lunn 	if (pdata) {
6976877b7cb0SAndrew Lunn 		compat_info = pdata_device_get_match_data(dev);
6977877b7cb0SAndrew Lunn 
6978877b7cb0SAndrew Lunn 		if (!pdata->netdev)
6979877b7cb0SAndrew Lunn 			return -EINVAL;
6980877b7cb0SAndrew Lunn 
6981877b7cb0SAndrew Lunn 		for (port = 0; port < DSA_MAX_PORTS; port++) {
6982877b7cb0SAndrew Lunn 			if (!(pdata->enabled_ports & (1 << port)))
6983877b7cb0SAndrew Lunn 				continue;
6984877b7cb0SAndrew Lunn 			if (strcmp(pdata->cd.port_names[port], "cpu"))
6985877b7cb0SAndrew Lunn 				continue;
6986877b7cb0SAndrew Lunn 			pdata->cd.netdev[port] = &pdata->netdev->dev;
6987877b7cb0SAndrew Lunn 			break;
6988877b7cb0SAndrew Lunn 		}
6989877b7cb0SAndrew Lunn 	}
6990877b7cb0SAndrew Lunn 
6991fad09c73SVivien Didelot 	if (!compat_info)
6992fad09c73SVivien Didelot 		return -EINVAL;
6993fad09c73SVivien Didelot 
6994fad09c73SVivien Didelot 	chip = mv88e6xxx_alloc_chip(dev);
6995877b7cb0SAndrew Lunn 	if (!chip) {
6996877b7cb0SAndrew Lunn 		err = -ENOMEM;
6997877b7cb0SAndrew Lunn 		goto out;
6998877b7cb0SAndrew Lunn 	}
6999fad09c73SVivien Didelot 
7000fad09c73SVivien Didelot 	chip->info = compat_info;
7001fad09c73SVivien Didelot 
7002b4308f04SAndrew Lunn 	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
7003877b7cb0SAndrew Lunn 	if (IS_ERR(chip->reset)) {
7004877b7cb0SAndrew Lunn 		err = PTR_ERR(chip->reset);
7005877b7cb0SAndrew Lunn 		goto out;
7006877b7cb0SAndrew Lunn 	}
70077b75e49dSBaruch Siach 	if (chip->reset)
70087b75e49dSBaruch Siach 		usleep_range(1000, 2000);
7009b4308f04SAndrew Lunn 
70105da66099SNathan Rossi 	/* Detect if the device is configured in single chip addressing mode,
70115da66099SNathan Rossi 	 * otherwise continue with address specific smi init/detection.
70125da66099SNathan Rossi 	 */
70135da66099SNathan Rossi 	err = mv88e6xxx_single_chip_detect(chip, mdiodev);
70145da66099SNathan Rossi 	if (err) {
70155da66099SNathan Rossi 		err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
70165da66099SNathan Rossi 		if (err)
70175da66099SNathan Rossi 			goto out;
70185da66099SNathan Rossi 
7019fad09c73SVivien Didelot 		err = mv88e6xxx_detect(chip);
7020fad09c73SVivien Didelot 		if (err)
7021877b7cb0SAndrew Lunn 			goto out;
70225da66099SNathan Rossi 	}
7023fad09c73SVivien Didelot 
7024670bb80fSTobias Waldekranz 	if (chip->info->edsa_support == MV88E6XXX_EDSA_SUPPORTED)
7025670bb80fSTobias Waldekranz 		chip->tag_protocol = DSA_TAG_PROTO_EDSA;
7026670bb80fSTobias Waldekranz 	else
7027670bb80fSTobias Waldekranz 		chip->tag_protocol = DSA_TAG_PROTO_DSA;
7028670bb80fSTobias Waldekranz 
7029e57e5e77SVivien Didelot 	mv88e6xxx_phy_init(chip);
7030e57e5e77SVivien Didelot 
703100baabe5SAndrew Lunn 	if (chip->info->ops->get_eeprom) {
703200baabe5SAndrew Lunn 		if (np)
703300baabe5SAndrew Lunn 			of_property_read_u32(np, "eeprom-length",
703400baabe5SAndrew Lunn 					     &chip->eeprom_len);
703500baabe5SAndrew Lunn 		else
703600baabe5SAndrew Lunn 			chip->eeprom_len = pdata->eeprom_len;
703700baabe5SAndrew Lunn 	}
7038fad09c73SVivien Didelot 
7039c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
7040dc30c35bSAndrew Lunn 	err = mv88e6xxx_switch_reset(chip);
7041c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
7042fad09c73SVivien Didelot 	if (err)
7043dc30c35bSAndrew Lunn 		goto out;
7044fad09c73SVivien Didelot 
7045a27415deSAndrew Lunn 	if (np) {
7046dc30c35bSAndrew Lunn 		chip->irq = of_irq_get(np, 0);
7047dc30c35bSAndrew Lunn 		if (chip->irq == -EPROBE_DEFER) {
7048dc30c35bSAndrew Lunn 			err = chip->irq;
7049dc30c35bSAndrew Lunn 			goto out;
7050fad09c73SVivien Didelot 		}
7051a27415deSAndrew Lunn 	}
7052a27415deSAndrew Lunn 
7053a27415deSAndrew Lunn 	if (pdata)
7054a27415deSAndrew Lunn 		chip->irq = pdata->irq;
7055fad09c73SVivien Didelot 
7056294d711eSAndrew Lunn 	/* Has to be performed before the MDIO bus is created, because
7057a708767eSUwe Kleine-König 	 * the PHYs will link their interrupts to these interrupt
7058294d711eSAndrew Lunn 	 * controllers
7059dc30c35bSAndrew Lunn 	 */
7060c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
7061294d711eSAndrew Lunn 	if (chip->irq > 0)
7062dc30c35bSAndrew Lunn 		err = mv88e6xxx_g1_irq_setup(chip);
7063294d711eSAndrew Lunn 	else
7064294d711eSAndrew Lunn 		err = mv88e6xxx_irq_poll_setup(chip);
7065c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
7066dc30c35bSAndrew Lunn 
7067dc30c35bSAndrew Lunn 	if (err)
7068dc30c35bSAndrew Lunn 		goto out;
7069dc30c35bSAndrew Lunn 
7070d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0) {
7071dc30c35bSAndrew Lunn 		err = mv88e6xxx_g2_irq_setup(chip);
7072dc30c35bSAndrew Lunn 		if (err)
7073dc30c35bSAndrew Lunn 			goto out_g1_irq;
7074dc30c35bSAndrew Lunn 	}
70750977644cSAndrew Lunn 
70760977644cSAndrew Lunn 	err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
70770977644cSAndrew Lunn 	if (err)
70780977644cSAndrew Lunn 		goto out_g2_irq;
707962eb1162SAndrew Lunn 
708062eb1162SAndrew Lunn 	err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
708162eb1162SAndrew Lunn 	if (err)
708262eb1162SAndrew Lunn 		goto out_g1_atu_prob_irq;
7083dc30c35bSAndrew Lunn 
7084a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdios_register(chip, np);
7085dc30c35bSAndrew Lunn 	if (err)
708662eb1162SAndrew Lunn 		goto out_g1_vtu_prob_irq;
7087dc30c35bSAndrew Lunn 
708855ed0ce0SFlorian Fainelli 	err = mv88e6xxx_register_switch(chip);
7089dc30c35bSAndrew Lunn 	if (err)
7090dc30c35bSAndrew Lunn 		goto out_mdio;
7091dc30c35bSAndrew Lunn 
7092fad09c73SVivien Didelot 	return 0;
7093dc30c35bSAndrew Lunn 
7094dc30c35bSAndrew Lunn out_mdio:
7095a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
709662eb1162SAndrew Lunn out_g1_vtu_prob_irq:
709762eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
70980977644cSAndrew Lunn out_g1_atu_prob_irq:
70990977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
7100dc30c35bSAndrew Lunn out_g2_irq:
7101294d711eSAndrew Lunn 	if (chip->info->g2_irqs > 0)
7102dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
7103dc30c35bSAndrew Lunn out_g1_irq:
7104294d711eSAndrew Lunn 	if (chip->irq > 0)
7105dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
7106294d711eSAndrew Lunn 	else
7107294d711eSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
7108dc30c35bSAndrew Lunn out:
7109877b7cb0SAndrew Lunn 	if (pdata)
7110877b7cb0SAndrew Lunn 		dev_put(pdata->netdev);
7111877b7cb0SAndrew Lunn 
7112dc30c35bSAndrew Lunn 	return err;
7113fad09c73SVivien Didelot }
7114fad09c73SVivien Didelot 
7115fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev)
7116fad09c73SVivien Didelot {
7117fad09c73SVivien Didelot 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
71180650bf52SVladimir Oltean 	struct mv88e6xxx_chip *chip;
71190650bf52SVladimir Oltean 
71200650bf52SVladimir Oltean 	if (!ds)
71210650bf52SVladimir Oltean 		return;
71220650bf52SVladimir Oltean 
71230650bf52SVladimir Oltean 	chip = ds->priv;
7124fad09c73SVivien Didelot 
7125c6fe0ad2SBrandon Streiff 	if (chip->info->ptp_support) {
7126c6fe0ad2SBrandon Streiff 		mv88e6xxx_hwtstamp_free(chip);
71272fa8d3afSBrandon Streiff 		mv88e6xxx_ptp_free(chip);
7128c6fe0ad2SBrandon Streiff 	}
71292fa8d3afSBrandon Streiff 
7130930188ceSAndrew Lunn 	mv88e6xxx_phy_destroy(chip);
7131fad09c73SVivien Didelot 	mv88e6xxx_unregister_switch(chip);
7132a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
7133dc30c35bSAndrew Lunn 
713462eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
71350977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
713676f38f1fSAndrew Lunn 
7137d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0)
7138dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
713976f38f1fSAndrew Lunn 
714076f38f1fSAndrew Lunn 	if (chip->irq > 0)
7141dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
714276f38f1fSAndrew Lunn 	else
714376f38f1fSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
71440650bf52SVladimir Oltean 
71450650bf52SVladimir Oltean 	dev_set_drvdata(&mdiodev->dev, NULL);
71460650bf52SVladimir Oltean }
71470650bf52SVladimir Oltean 
71480650bf52SVladimir Oltean static void mv88e6xxx_shutdown(struct mdio_device *mdiodev)
71490650bf52SVladimir Oltean {
71500650bf52SVladimir Oltean 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
71510650bf52SVladimir Oltean 
71520650bf52SVladimir Oltean 	if (!ds)
71530650bf52SVladimir Oltean 		return;
71540650bf52SVladimir Oltean 
71550650bf52SVladimir Oltean 	dsa_switch_shutdown(ds);
71560650bf52SVladimir Oltean 
71570650bf52SVladimir Oltean 	dev_set_drvdata(&mdiodev->dev, NULL);
7158fad09c73SVivien Didelot }
7159fad09c73SVivien Didelot 
7160fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = {
7161fad09c73SVivien Didelot 	{
7162fad09c73SVivien Didelot 		.compatible = "marvell,mv88e6085",
7163fad09c73SVivien Didelot 		.data = &mv88e6xxx_table[MV88E6085],
7164fad09c73SVivien Didelot 	},
71651a3b39ecSAndrew Lunn 	{
71661a3b39ecSAndrew Lunn 		.compatible = "marvell,mv88e6190",
71671a3b39ecSAndrew Lunn 		.data = &mv88e6xxx_table[MV88E6190],
71681a3b39ecSAndrew Lunn 	},
71691f71836fSRasmus Villemoes 	{
71701f71836fSRasmus Villemoes 		.compatible = "marvell,mv88e6250",
71711f71836fSRasmus Villemoes 		.data = &mv88e6xxx_table[MV88E6250],
71721f71836fSRasmus Villemoes 	},
7173fad09c73SVivien Didelot 	{ /* sentinel */ },
7174fad09c73SVivien Didelot };
7175fad09c73SVivien Didelot 
7176fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);
7177fad09c73SVivien Didelot 
7178fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = {
7179fad09c73SVivien Didelot 	.probe	= mv88e6xxx_probe,
7180fad09c73SVivien Didelot 	.remove = mv88e6xxx_remove,
71810650bf52SVladimir Oltean 	.shutdown = mv88e6xxx_shutdown,
7182fad09c73SVivien Didelot 	.mdiodrv.driver = {
7183fad09c73SVivien Didelot 		.name = "mv88e6085",
7184fad09c73SVivien Didelot 		.of_match_table = mv88e6xxx_of_match,
7185bcd3d9d9SMiquel Raynal 		.pm = &mv88e6xxx_pm_ops,
7186fad09c73SVivien Didelot 	},
7187fad09c73SVivien Didelot };
7188fad09c73SVivien Didelot 
71897324d50eSAndrew Lunn mdio_module_driver(mv88e6xxx_driver);
7190fad09c73SVivien Didelot 
7191fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
7192fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
7193fad09c73SVivien Didelot MODULE_LICENSE("GPL");
7194