xref: /openbmc/linux/drivers/net/dsa/mv88e6xxx/chip.c (revision 64d47d50)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2fad09c73SVivien Didelot /*
3fad09c73SVivien Didelot  * Marvell 88e6xxx Ethernet switch single-chip support
4fad09c73SVivien Didelot  *
5fad09c73SVivien Didelot  * Copyright (c) 2008 Marvell Semiconductor
6fad09c73SVivien Didelot  *
7fad09c73SVivien Didelot  * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
8fad09c73SVivien Didelot  *
94333d619SVivien Didelot  * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
104333d619SVivien Didelot  *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
11fad09c73SVivien Didelot  */
12fad09c73SVivien Didelot 
1319fb7f69SVivien Didelot #include <linux/bitfield.h>
14fad09c73SVivien Didelot #include <linux/delay.h>
15fad09c73SVivien Didelot #include <linux/etherdevice.h>
16fad09c73SVivien Didelot #include <linux/ethtool.h>
17fad09c73SVivien Didelot #include <linux/if_bridge.h>
18dc30c35bSAndrew Lunn #include <linux/interrupt.h>
19dc30c35bSAndrew Lunn #include <linux/irq.h>
20dc30c35bSAndrew Lunn #include <linux/irqdomain.h>
21fad09c73SVivien Didelot #include <linux/jiffies.h>
22fad09c73SVivien Didelot #include <linux/list.h>
23fad09c73SVivien Didelot #include <linux/mdio.h>
24fad09c73SVivien Didelot #include <linux/module.h>
25fad09c73SVivien Didelot #include <linux/of_device.h>
26dc30c35bSAndrew Lunn #include <linux/of_irq.h>
27fad09c73SVivien Didelot #include <linux/of_mdio.h>
28877b7cb0SAndrew Lunn #include <linux/platform_data/mv88e6xxx.h>
29fad09c73SVivien Didelot #include <linux/netdevice.h>
30fad09c73SVivien Didelot #include <linux/gpio/consumer.h>
31c9a2356fSRussell King #include <linux/phylink.h>
32fad09c73SVivien Didelot #include <net/dsa.h>
33ec561276SVivien Didelot 
344d5f2ba7SVivien Didelot #include "chip.h"
35a935c052SVivien Didelot #include "global1.h"
36ec561276SVivien Didelot #include "global2.h"
37c6fe0ad2SBrandon Streiff #include "hwtstamp.h"
3810fa5bfcSAndrew Lunn #include "phy.h"
3918abed21SVivien Didelot #include "port.h"
402fa8d3afSBrandon Streiff #include "ptp.h"
416d91782fSAndrew Lunn #include "serdes.h"
42e7ba0fadSVivien Didelot #include "smi.h"
43fad09c73SVivien Didelot 
44fad09c73SVivien Didelot static void assert_reg_lock(struct mv88e6xxx_chip *chip)
45fad09c73SVivien Didelot {
46fad09c73SVivien Didelot 	if (unlikely(!mutex_is_locked(&chip->reg_lock))) {
47fad09c73SVivien Didelot 		dev_err(chip->dev, "Switch registers lock not held!\n");
48fad09c73SVivien Didelot 		dump_stack();
49fad09c73SVivien Didelot 	}
50fad09c73SVivien Didelot }
51fad09c73SVivien Didelot 
52ec561276SVivien Didelot int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
53fad09c73SVivien Didelot {
54fad09c73SVivien Didelot 	int err;
55fad09c73SVivien Didelot 
56fad09c73SVivien Didelot 	assert_reg_lock(chip);
57fad09c73SVivien Didelot 
58fad09c73SVivien Didelot 	err = mv88e6xxx_smi_read(chip, addr, reg, val);
59fad09c73SVivien Didelot 	if (err)
60fad09c73SVivien Didelot 		return err;
61fad09c73SVivien Didelot 
62fad09c73SVivien Didelot 	dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
63fad09c73SVivien Didelot 		addr, reg, *val);
64fad09c73SVivien Didelot 
65fad09c73SVivien Didelot 	return 0;
66fad09c73SVivien Didelot }
67fad09c73SVivien Didelot 
68ec561276SVivien Didelot int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
69fad09c73SVivien Didelot {
70fad09c73SVivien Didelot 	int err;
71fad09c73SVivien Didelot 
72fad09c73SVivien Didelot 	assert_reg_lock(chip);
73fad09c73SVivien Didelot 
74fad09c73SVivien Didelot 	err = mv88e6xxx_smi_write(chip, addr, reg, val);
75fad09c73SVivien Didelot 	if (err)
76fad09c73SVivien Didelot 		return err;
77fad09c73SVivien Didelot 
78fad09c73SVivien Didelot 	dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
79fad09c73SVivien Didelot 		addr, reg, val);
80fad09c73SVivien Didelot 
81fad09c73SVivien Didelot 	return 0;
82fad09c73SVivien Didelot }
83fad09c73SVivien Didelot 
84683f2244SVivien Didelot int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg,
85683f2244SVivien Didelot 			u16 mask, u16 val)
86683f2244SVivien Didelot {
87683f2244SVivien Didelot 	u16 data;
88683f2244SVivien Didelot 	int err;
89683f2244SVivien Didelot 	int i;
90683f2244SVivien Didelot 
91683f2244SVivien Didelot 	/* There's no bus specific operation to wait for a mask */
92683f2244SVivien Didelot 	for (i = 0; i < 16; i++) {
93683f2244SVivien Didelot 		err = mv88e6xxx_read(chip, addr, reg, &data);
94683f2244SVivien Didelot 		if (err)
95683f2244SVivien Didelot 			return err;
96683f2244SVivien Didelot 
97683f2244SVivien Didelot 		if ((data & mask) == val)
98683f2244SVivien Didelot 			return 0;
99683f2244SVivien Didelot 
100683f2244SVivien Didelot 		usleep_range(1000, 2000);
101683f2244SVivien Didelot 	}
102683f2244SVivien Didelot 
103683f2244SVivien Didelot 	dev_err(chip->dev, "Timeout while waiting for switch\n");
104683f2244SVivien Didelot 	return -ETIMEDOUT;
105683f2244SVivien Didelot }
106683f2244SVivien Didelot 
10719fb7f69SVivien Didelot int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg,
10819fb7f69SVivien Didelot 		       int bit, int val)
10919fb7f69SVivien Didelot {
11019fb7f69SVivien Didelot 	return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit),
11119fb7f69SVivien Didelot 				   val ? BIT(bit) : 0x0000);
11219fb7f69SVivien Didelot }
11319fb7f69SVivien Didelot 
11410fa5bfcSAndrew Lunn struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
115a3c53be5SAndrew Lunn {
116a3c53be5SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
117a3c53be5SAndrew Lunn 
118a3c53be5SAndrew Lunn 	mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus,
119a3c53be5SAndrew Lunn 				    list);
120a3c53be5SAndrew Lunn 	if (!mdio_bus)
121a3c53be5SAndrew Lunn 		return NULL;
122a3c53be5SAndrew Lunn 
123a3c53be5SAndrew Lunn 	return mdio_bus->bus;
124a3c53be5SAndrew Lunn }
125a3c53be5SAndrew Lunn 
126dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_mask(struct irq_data *d)
127dc30c35bSAndrew Lunn {
128dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
129dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
130dc30c35bSAndrew Lunn 
131dc30c35bSAndrew Lunn 	chip->g1_irq.masked |= (1 << n);
132dc30c35bSAndrew Lunn }
133dc30c35bSAndrew Lunn 
134dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_unmask(struct irq_data *d)
135dc30c35bSAndrew Lunn {
136dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
137dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
138dc30c35bSAndrew Lunn 
139dc30c35bSAndrew Lunn 	chip->g1_irq.masked &= ~(1 << n);
140dc30c35bSAndrew Lunn }
141dc30c35bSAndrew Lunn 
142294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip)
143dc30c35bSAndrew Lunn {
144dc30c35bSAndrew Lunn 	unsigned int nhandled = 0;
145dc30c35bSAndrew Lunn 	unsigned int sub_irq;
146dc30c35bSAndrew Lunn 	unsigned int n;
147dc30c35bSAndrew Lunn 	u16 reg;
1487c0db24cSJohn David Anglin 	u16 ctl1;
149dc30c35bSAndrew Lunn 	int err;
150dc30c35bSAndrew Lunn 
151c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
15282466921SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
153c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
154dc30c35bSAndrew Lunn 
155dc30c35bSAndrew Lunn 	if (err)
156dc30c35bSAndrew Lunn 		goto out;
157dc30c35bSAndrew Lunn 
1587c0db24cSJohn David Anglin 	do {
159dc30c35bSAndrew Lunn 		for (n = 0; n < chip->g1_irq.nirqs; ++n) {
160dc30c35bSAndrew Lunn 			if (reg & (1 << n)) {
1617c0db24cSJohn David Anglin 				sub_irq = irq_find_mapping(chip->g1_irq.domain,
1627c0db24cSJohn David Anglin 							   n);
163dc30c35bSAndrew Lunn 				handle_nested_irq(sub_irq);
164dc30c35bSAndrew Lunn 				++nhandled;
165dc30c35bSAndrew Lunn 			}
166dc30c35bSAndrew Lunn 		}
1677c0db24cSJohn David Anglin 
168c9acece0SRasmus Villemoes 		mv88e6xxx_reg_lock(chip);
1697c0db24cSJohn David Anglin 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1);
1707c0db24cSJohn David Anglin 		if (err)
1717c0db24cSJohn David Anglin 			goto unlock;
1727c0db24cSJohn David Anglin 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
1737c0db24cSJohn David Anglin unlock:
174c9acece0SRasmus Villemoes 		mv88e6xxx_reg_unlock(chip);
1757c0db24cSJohn David Anglin 		if (err)
1767c0db24cSJohn David Anglin 			goto out;
1777c0db24cSJohn David Anglin 		ctl1 &= GENMASK(chip->g1_irq.nirqs, 0);
1787c0db24cSJohn David Anglin 	} while (reg & ctl1);
1797c0db24cSJohn David Anglin 
180dc30c35bSAndrew Lunn out:
181dc30c35bSAndrew Lunn 	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
182dc30c35bSAndrew Lunn }
183dc30c35bSAndrew Lunn 
184294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
185294d711eSAndrew Lunn {
186294d711eSAndrew Lunn 	struct mv88e6xxx_chip *chip = dev_id;
187294d711eSAndrew Lunn 
188294d711eSAndrew Lunn 	return mv88e6xxx_g1_irq_thread_work(chip);
189294d711eSAndrew Lunn }
190294d711eSAndrew Lunn 
191dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
192dc30c35bSAndrew Lunn {
193dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
194dc30c35bSAndrew Lunn 
195c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
196dc30c35bSAndrew Lunn }
197dc30c35bSAndrew Lunn 
198dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
199dc30c35bSAndrew Lunn {
200dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
201dc30c35bSAndrew Lunn 	u16 mask = GENMASK(chip->g1_irq.nirqs, 0);
202dc30c35bSAndrew Lunn 	u16 reg;
203dc30c35bSAndrew Lunn 	int err;
204dc30c35bSAndrew Lunn 
205d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &reg);
206dc30c35bSAndrew Lunn 	if (err)
207dc30c35bSAndrew Lunn 		goto out;
208dc30c35bSAndrew Lunn 
209dc30c35bSAndrew Lunn 	reg &= ~mask;
210dc30c35bSAndrew Lunn 	reg |= (~chip->g1_irq.masked & mask);
211dc30c35bSAndrew Lunn 
212d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg);
213dc30c35bSAndrew Lunn 	if (err)
214dc30c35bSAndrew Lunn 		goto out;
215dc30c35bSAndrew Lunn 
216dc30c35bSAndrew Lunn out:
217c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
218dc30c35bSAndrew Lunn }
219dc30c35bSAndrew Lunn 
2206eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g1_irq_chip = {
221dc30c35bSAndrew Lunn 	.name			= "mv88e6xxx-g1",
222dc30c35bSAndrew Lunn 	.irq_mask		= mv88e6xxx_g1_irq_mask,
223dc30c35bSAndrew Lunn 	.irq_unmask		= mv88e6xxx_g1_irq_unmask,
224dc30c35bSAndrew Lunn 	.irq_bus_lock		= mv88e6xxx_g1_irq_bus_lock,
225dc30c35bSAndrew Lunn 	.irq_bus_sync_unlock	= mv88e6xxx_g1_irq_bus_sync_unlock,
226dc30c35bSAndrew Lunn };
227dc30c35bSAndrew Lunn 
228dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d,
229dc30c35bSAndrew Lunn 				       unsigned int irq,
230dc30c35bSAndrew Lunn 				       irq_hw_number_t hwirq)
231dc30c35bSAndrew Lunn {
232dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = d->host_data;
233dc30c35bSAndrew Lunn 
234dc30c35bSAndrew Lunn 	irq_set_chip_data(irq, d->host_data);
235dc30c35bSAndrew Lunn 	irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq);
236dc30c35bSAndrew Lunn 	irq_set_noprobe(irq);
237dc30c35bSAndrew Lunn 
238dc30c35bSAndrew Lunn 	return 0;
239dc30c35bSAndrew Lunn }
240dc30c35bSAndrew Lunn 
241dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = {
242dc30c35bSAndrew Lunn 	.map	= mv88e6xxx_g1_irq_domain_map,
243dc30c35bSAndrew Lunn 	.xlate	= irq_domain_xlate_twocell,
244dc30c35bSAndrew Lunn };
245dc30c35bSAndrew Lunn 
2463d82475aSUwe Kleine-König /* To be called with reg_lock held */
247294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip)
248dc30c35bSAndrew Lunn {
249dc30c35bSAndrew Lunn 	int irq, virq;
2503460a577SAndrew Lunn 	u16 mask;
2513460a577SAndrew Lunn 
252d77f4321SVivien Didelot 	mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
2533d5fdba1SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
254d77f4321SVivien Didelot 	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
2553460a577SAndrew Lunn 
2565edef2f2SAndreas Färber 	for (irq = 0; irq < chip->g1_irq.nirqs; irq++) {
257a3db3d3aSAndrew Lunn 		virq = irq_find_mapping(chip->g1_irq.domain, irq);
258dc30c35bSAndrew Lunn 		irq_dispose_mapping(virq);
259dc30c35bSAndrew Lunn 	}
260dc30c35bSAndrew Lunn 
261a3db3d3aSAndrew Lunn 	irq_domain_remove(chip->g1_irq.domain);
262dc30c35bSAndrew Lunn }
263dc30c35bSAndrew Lunn 
264294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
265294d711eSAndrew Lunn {
2663d82475aSUwe Kleine-König 	/*
2673d82475aSUwe Kleine-König 	 * free_irq must be called without reg_lock taken because the irq
2683d82475aSUwe Kleine-König 	 * handler takes this lock, too.
2693d82475aSUwe Kleine-König 	 */
270294d711eSAndrew Lunn 	free_irq(chip->irq, chip);
2713d82475aSUwe Kleine-König 
272c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2733d82475aSUwe Kleine-König 	mv88e6xxx_g1_irq_free_common(chip);
274c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
275294d711eSAndrew Lunn }
276294d711eSAndrew Lunn 
277294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip)
278dc30c35bSAndrew Lunn {
2793dd0ef05SAndrew Lunn 	int err, irq, virq;
2803dd0ef05SAndrew Lunn 	u16 reg, mask;
281dc30c35bSAndrew Lunn 
282dc30c35bSAndrew Lunn 	chip->g1_irq.nirqs = chip->info->g1_irqs;
283dc30c35bSAndrew Lunn 	chip->g1_irq.domain = irq_domain_add_simple(
284dc30c35bSAndrew Lunn 		NULL, chip->g1_irq.nirqs, 0,
285dc30c35bSAndrew Lunn 		&mv88e6xxx_g1_irq_domain_ops, chip);
286dc30c35bSAndrew Lunn 	if (!chip->g1_irq.domain)
287dc30c35bSAndrew Lunn 		return -ENOMEM;
288dc30c35bSAndrew Lunn 
289dc30c35bSAndrew Lunn 	for (irq = 0; irq < chip->g1_irq.nirqs; irq++)
290dc30c35bSAndrew Lunn 		irq_create_mapping(chip->g1_irq.domain, irq);
291dc30c35bSAndrew Lunn 
292dc30c35bSAndrew Lunn 	chip->g1_irq.chip = mv88e6xxx_g1_irq_chip;
293dc30c35bSAndrew Lunn 	chip->g1_irq.masked = ~0;
294dc30c35bSAndrew Lunn 
295d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
296dc30c35bSAndrew Lunn 	if (err)
2973dd0ef05SAndrew Lunn 		goto out_mapping;
298dc30c35bSAndrew Lunn 
2993dd0ef05SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
300dc30c35bSAndrew Lunn 
301d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
302dc30c35bSAndrew Lunn 	if (err)
3033dd0ef05SAndrew Lunn 		goto out_disable;
304dc30c35bSAndrew Lunn 
305dc30c35bSAndrew Lunn 	/* Reading the interrupt status clears (most of) them */
30682466921SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
307dc30c35bSAndrew Lunn 	if (err)
3083dd0ef05SAndrew Lunn 		goto out_disable;
309dc30c35bSAndrew Lunn 
310dc30c35bSAndrew Lunn 	return 0;
311dc30c35bSAndrew Lunn 
3123dd0ef05SAndrew Lunn out_disable:
3133d5fdba1SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
314d77f4321SVivien Didelot 	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
3153dd0ef05SAndrew Lunn 
3163dd0ef05SAndrew Lunn out_mapping:
3173dd0ef05SAndrew Lunn 	for (irq = 0; irq < 16; irq++) {
3183dd0ef05SAndrew Lunn 		virq = irq_find_mapping(chip->g1_irq.domain, irq);
3193dd0ef05SAndrew Lunn 		irq_dispose_mapping(virq);
3203dd0ef05SAndrew Lunn 	}
3213dd0ef05SAndrew Lunn 
3223dd0ef05SAndrew Lunn 	irq_domain_remove(chip->g1_irq.domain);
323dc30c35bSAndrew Lunn 
324dc30c35bSAndrew Lunn 	return err;
325dc30c35bSAndrew Lunn }
326dc30c35bSAndrew Lunn 
327294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
328294d711eSAndrew Lunn {
329f6d9758bSAndrew Lunn 	static struct lock_class_key lock_key;
330f6d9758bSAndrew Lunn 	static struct lock_class_key request_key;
331294d711eSAndrew Lunn 	int err;
332294d711eSAndrew Lunn 
333294d711eSAndrew Lunn 	err = mv88e6xxx_g1_irq_setup_common(chip);
334294d711eSAndrew Lunn 	if (err)
335294d711eSAndrew Lunn 		return err;
336294d711eSAndrew Lunn 
337f6d9758bSAndrew Lunn 	/* These lock classes tells lockdep that global 1 irqs are in
338f6d9758bSAndrew Lunn 	 * a different category than their parent GPIO, so it won't
339f6d9758bSAndrew Lunn 	 * report false recursion.
340f6d9758bSAndrew Lunn 	 */
341f6d9758bSAndrew Lunn 	irq_set_lockdep_class(chip->irq, &lock_key, &request_key);
342f6d9758bSAndrew Lunn 
3433095383aSAndrew Lunn 	snprintf(chip->irq_name, sizeof(chip->irq_name),
3443095383aSAndrew Lunn 		 "mv88e6xxx-%s", dev_name(chip->dev));
3453095383aSAndrew Lunn 
346c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
347294d711eSAndrew Lunn 	err = request_threaded_irq(chip->irq, NULL,
348294d711eSAndrew Lunn 				   mv88e6xxx_g1_irq_thread_fn,
3490340376eSMarek Behún 				   IRQF_ONESHOT | IRQF_SHARED,
3503095383aSAndrew Lunn 				   chip->irq_name, chip);
351c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
352294d711eSAndrew Lunn 	if (err)
353294d711eSAndrew Lunn 		mv88e6xxx_g1_irq_free_common(chip);
354294d711eSAndrew Lunn 
355294d711eSAndrew Lunn 	return err;
356294d711eSAndrew Lunn }
357294d711eSAndrew Lunn 
358294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work)
359294d711eSAndrew Lunn {
360294d711eSAndrew Lunn 	struct mv88e6xxx_chip *chip = container_of(work,
361294d711eSAndrew Lunn 						   struct mv88e6xxx_chip,
362294d711eSAndrew Lunn 						   irq_poll_work.work);
363294d711eSAndrew Lunn 	mv88e6xxx_g1_irq_thread_work(chip);
364294d711eSAndrew Lunn 
365294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
366294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
367294d711eSAndrew Lunn }
368294d711eSAndrew Lunn 
369294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip)
370294d711eSAndrew Lunn {
371294d711eSAndrew Lunn 	int err;
372294d711eSAndrew Lunn 
373294d711eSAndrew Lunn 	err = mv88e6xxx_g1_irq_setup_common(chip);
374294d711eSAndrew Lunn 	if (err)
375294d711eSAndrew Lunn 		return err;
376294d711eSAndrew Lunn 
377294d711eSAndrew Lunn 	kthread_init_delayed_work(&chip->irq_poll_work,
378294d711eSAndrew Lunn 				  mv88e6xxx_irq_poll);
379294d711eSAndrew Lunn 
3803f8b8696SFlorian Fainelli 	chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev));
381294d711eSAndrew Lunn 	if (IS_ERR(chip->kworker))
382294d711eSAndrew Lunn 		return PTR_ERR(chip->kworker);
383294d711eSAndrew Lunn 
384294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
385294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
386294d711eSAndrew Lunn 
387294d711eSAndrew Lunn 	return 0;
388294d711eSAndrew Lunn }
389294d711eSAndrew Lunn 
390294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip)
391294d711eSAndrew Lunn {
392294d711eSAndrew Lunn 	kthread_cancel_delayed_work_sync(&chip->irq_poll_work);
393294d711eSAndrew Lunn 	kthread_destroy_worker(chip->kworker);
3943d82475aSUwe Kleine-König 
395c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3963d82475aSUwe Kleine-König 	mv88e6xxx_g1_irq_free_common(chip);
397c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
398294d711eSAndrew Lunn }
399294d711eSAndrew Lunn 
40064d47d50SRussell King static int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip,
40164d47d50SRussell King 					   int port, phy_interface_t interface)
40264d47d50SRussell King {
40364d47d50SRussell King 	int err;
40464d47d50SRussell King 
40564d47d50SRussell King 	if (chip->info->ops->port_set_rgmii_delay) {
40664d47d50SRussell King 		err = chip->info->ops->port_set_rgmii_delay(chip, port,
40764d47d50SRussell King 							    interface);
40864d47d50SRussell King 		if (err && err != -EOPNOTSUPP)
40964d47d50SRussell King 			return err;
41064d47d50SRussell King 	}
41164d47d50SRussell King 
41264d47d50SRussell King 	if (chip->info->ops->port_set_cmode) {
41364d47d50SRussell King 		err = chip->info->ops->port_set_cmode(chip, port,
41464d47d50SRussell King 						      interface);
41564d47d50SRussell King 		if (err && err != -EOPNOTSUPP)
41664d47d50SRussell King 			return err;
41764d47d50SRussell King 	}
41864d47d50SRussell King 
41964d47d50SRussell King 	return 0;
42064d47d50SRussell King }
42164d47d50SRussell King 
42272d8b4fdSHeiner Kallweit int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
42372d8b4fdSHeiner Kallweit 			     int speed, int duplex, int pause,
424d78343d2SVivien Didelot 			     phy_interface_t mode)
425d78343d2SVivien Didelot {
426a26deec6SAndrew Lunn 	struct phylink_link_state state;
427d78343d2SVivien Didelot 	int err;
428d78343d2SVivien Didelot 
429d78343d2SVivien Didelot 	if (!chip->info->ops->port_set_link)
430d78343d2SVivien Didelot 		return 0;
431d78343d2SVivien Didelot 
432a26deec6SAndrew Lunn 	if (!chip->info->ops->port_link_state)
433a26deec6SAndrew Lunn 		return 0;
434a26deec6SAndrew Lunn 
435a26deec6SAndrew Lunn 	err = chip->info->ops->port_link_state(chip, port, &state);
436a26deec6SAndrew Lunn 	if (err)
437a26deec6SAndrew Lunn 		return err;
438a26deec6SAndrew Lunn 
439a26deec6SAndrew Lunn 	/* Has anything actually changed? We don't expect the
440a26deec6SAndrew Lunn 	 * interface mode to change without one of the other
441a26deec6SAndrew Lunn 	 * parameters also changing
442a26deec6SAndrew Lunn 	 */
443a26deec6SAndrew Lunn 	if (state.link == link &&
444a26deec6SAndrew Lunn 	    state.speed == speed &&
445927441adSMarek Behún 	    state.duplex == duplex &&
446927441adSMarek Behún 	    (state.interface == mode ||
447927441adSMarek Behún 	     state.interface == PHY_INTERFACE_MODE_NA))
448a26deec6SAndrew Lunn 		return 0;
449a26deec6SAndrew Lunn 
450d78343d2SVivien Didelot 	/* Port's MAC control must not be changed unless the link is down */
45143c8e0aeSHubert Feurstein 	err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN);
452d78343d2SVivien Didelot 	if (err)
453d78343d2SVivien Didelot 		return err;
454d78343d2SVivien Didelot 
455d78343d2SVivien Didelot 	if (chip->info->ops->port_set_speed) {
456d78343d2SVivien Didelot 		err = chip->info->ops->port_set_speed(chip, port, speed);
457d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
458d78343d2SVivien Didelot 			goto restore_link;
459d78343d2SVivien Didelot 	}
460d78343d2SVivien Didelot 
4617cbbee05SAndrew Lunn 	if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode)
4627cbbee05SAndrew Lunn 		mode = chip->info->ops->port_max_speed_mode(port);
4637cbbee05SAndrew Lunn 
46454186b91SAndrew Lunn 	if (chip->info->ops->port_set_pause) {
46554186b91SAndrew Lunn 		err = chip->info->ops->port_set_pause(chip, port, pause);
46654186b91SAndrew Lunn 		if (err)
46754186b91SAndrew Lunn 			goto restore_link;
46854186b91SAndrew Lunn 	}
46954186b91SAndrew Lunn 
470d78343d2SVivien Didelot 	if (chip->info->ops->port_set_duplex) {
471d78343d2SVivien Didelot 		err = chip->info->ops->port_set_duplex(chip, port, duplex);
472d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
473d78343d2SVivien Didelot 			goto restore_link;
474d78343d2SVivien Didelot 	}
475d78343d2SVivien Didelot 
47664d47d50SRussell King 	err = mv88e6xxx_port_config_interface(chip, port, mode);
477d78343d2SVivien Didelot restore_link:
478d78343d2SVivien Didelot 	if (chip->info->ops->port_set_link(chip, port, link))
479774439e5SVivien Didelot 		dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
480d78343d2SVivien Didelot 
481d78343d2SVivien Didelot 	return err;
482d78343d2SVivien Didelot }
483d78343d2SVivien Didelot 
484d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
485d700ec41SMarek Vasut {
486d700ec41SMarek Vasut 	struct mv88e6xxx_chip *chip = ds->priv;
487d700ec41SMarek Vasut 
488d700ec41SMarek Vasut 	return port < chip->info->num_internal_phys;
489d700ec41SMarek Vasut }
490d700ec41SMarek Vasut 
4916c422e34SRussell King static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port,
4926c422e34SRussell King 				       unsigned long *mask,
4936c422e34SRussell King 				       struct phylink_link_state *state)
4946c422e34SRussell King {
4956c422e34SRussell King 	if (!phy_interface_mode_is_8023z(state->interface)) {
4966c422e34SRussell King 		/* 10M and 100M are only supported in non-802.3z mode */
4976c422e34SRussell King 		phylink_set(mask, 10baseT_Half);
4986c422e34SRussell King 		phylink_set(mask, 10baseT_Full);
4996c422e34SRussell King 		phylink_set(mask, 100baseT_Half);
5006c422e34SRussell King 		phylink_set(mask, 100baseT_Full);
5016c422e34SRussell King 	}
5026c422e34SRussell King }
5036c422e34SRussell King 
5046c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5056c422e34SRussell King 				       unsigned long *mask,
5066c422e34SRussell King 				       struct phylink_link_state *state)
5076c422e34SRussell King {
5086c422e34SRussell King 	/* FIXME: if the port is in 1000Base-X mode, then it only supports
5096c422e34SRussell King 	 * 1000M FD speeds.  In this case, CMODE will indicate 5.
5106c422e34SRussell King 	 */
5116c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
5126c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
5136c422e34SRussell King 
5146c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
5156c422e34SRussell King }
5166c422e34SRussell King 
517e3af71a3SMarek Behún static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port,
518e3af71a3SMarek Behún 				       unsigned long *mask,
519e3af71a3SMarek Behún 				       struct phylink_link_state *state)
520e3af71a3SMarek Behún {
521e3af71a3SMarek Behún 	if (port >= 5)
522e3af71a3SMarek Behún 		phylink_set(mask, 2500baseX_Full);
523e3af71a3SMarek Behún 
524e3af71a3SMarek Behún 	/* No ethtool bits for 200Mbps */
525e3af71a3SMarek Behún 	phylink_set(mask, 1000baseT_Full);
526e3af71a3SMarek Behún 	phylink_set(mask, 1000baseX_Full);
527e3af71a3SMarek Behún 
528e3af71a3SMarek Behún 	mv88e6065_phylink_validate(chip, port, mask, state);
529e3af71a3SMarek Behún }
530e3af71a3SMarek Behún 
5316c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5326c422e34SRussell King 				       unsigned long *mask,
5336c422e34SRussell King 				       struct phylink_link_state *state)
5346c422e34SRussell King {
5356c422e34SRussell King 	/* No ethtool bits for 200Mbps */
5366c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
5376c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
5386c422e34SRussell King 
5396c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
5406c422e34SRussell King }
5416c422e34SRussell King 
5426c422e34SRussell King static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5436c422e34SRussell King 				       unsigned long *mask,
5446c422e34SRussell King 				       struct phylink_link_state *state)
5456c422e34SRussell King {
546ec26016bSAndrew Lunn 	if (port >= 9) {
5476c422e34SRussell King 		phylink_set(mask, 2500baseX_Full);
548ec26016bSAndrew Lunn 		phylink_set(mask, 2500baseT_Full);
549ec26016bSAndrew Lunn 	}
5506c422e34SRussell King 
5516c422e34SRussell King 	/* No ethtool bits for 200Mbps */
5526c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
5536c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
5546c422e34SRussell King 
5556c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
5566c422e34SRussell King }
5576c422e34SRussell King 
5586c422e34SRussell King static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5596c422e34SRussell King 					unsigned long *mask,
5606c422e34SRussell King 					struct phylink_link_state *state)
5616c422e34SRussell King {
5626c422e34SRussell King 	if (port >= 9) {
5636c422e34SRussell King 		phylink_set(mask, 10000baseT_Full);
5646c422e34SRussell King 		phylink_set(mask, 10000baseKR_Full);
5656c422e34SRussell King 	}
5666c422e34SRussell King 
5676c422e34SRussell King 	mv88e6390_phylink_validate(chip, port, mask, state);
5686c422e34SRussell King }
5696c422e34SRussell King 
570c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
571c9a2356fSRussell King 			       unsigned long *supported,
572c9a2356fSRussell King 			       struct phylink_link_state *state)
573c9a2356fSRussell King {
5746c422e34SRussell King 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
5756c422e34SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
5766c422e34SRussell King 
5776c422e34SRussell King 	/* Allow all the expected bits */
5786c422e34SRussell King 	phylink_set(mask, Autoneg);
5796c422e34SRussell King 	phylink_set(mask, Pause);
5806c422e34SRussell King 	phylink_set_port_modes(mask);
5816c422e34SRussell King 
5826c422e34SRussell King 	if (chip->info->ops->phylink_validate)
5836c422e34SRussell King 		chip->info->ops->phylink_validate(chip, port, mask, state);
5846c422e34SRussell King 
5856c422e34SRussell King 	bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
5866c422e34SRussell King 	bitmap_and(state->advertising, state->advertising, mask,
5876c422e34SRussell King 		   __ETHTOOL_LINK_MODE_MASK_NBITS);
5886c422e34SRussell King 
5896c422e34SRussell King 	/* We can only operate at 2500BaseX or 1000BaseX.  If requested
5906c422e34SRussell King 	 * to advertise both, only report advertising at 2500BaseX.
5916c422e34SRussell King 	 */
5926c422e34SRussell King 	phylink_helper_basex_speed(state);
593c9a2356fSRussell King }
594c9a2356fSRussell King 
595c9a2356fSRussell King static int mv88e6xxx_link_state(struct dsa_switch *ds, int port,
596c9a2356fSRussell King 				struct phylink_link_state *state)
597c9a2356fSRussell King {
598c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
599c9a2356fSRussell King 	int err;
600c9a2356fSRussell King 
601c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
6026c422e34SRussell King 	if (chip->info->ops->port_link_state)
6036c422e34SRussell King 		err = chip->info->ops->port_link_state(chip, port, state);
6046c422e34SRussell King 	else
6056c422e34SRussell King 		err = -EOPNOTSUPP;
606c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
607c9a2356fSRussell King 
608c9a2356fSRussell King 	return err;
609c9a2356fSRussell King }
610c9a2356fSRussell King 
611c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
612c9a2356fSRussell King 				 unsigned int mode,
613c9a2356fSRussell King 				 const struct phylink_link_state *state)
614c9a2356fSRussell King {
615c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
61664d47d50SRussell King 	int err;
617c9a2356fSRussell King 
61864d47d50SRussell King 	/* FIXME: is this the correct test? If we're in fixed mode on an
61964d47d50SRussell King 	 * internal port, why should we process this any different from
62064d47d50SRussell King 	 * PHY mode? On the other hand, the port may be automedia between
62164d47d50SRussell King 	 * an internal PHY and the serdes...
62264d47d50SRussell King 	 */
623d700ec41SMarek Vasut 	if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port))
624c9a2356fSRussell King 		return;
625c9a2356fSRussell King 
626c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
62764d47d50SRussell King 	/* FIXME: should we force the link down here - but if we do, how
62864d47d50SRussell King 	 * do we restore the link force/unforce state? The driver layering
62964d47d50SRussell King 	 * gets in the way.
63064d47d50SRussell King 	 */
63164d47d50SRussell King 	err = mv88e6xxx_port_config_interface(chip, port, state->interface);
632c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
633c9a2356fSRussell King 
634c9a2356fSRussell King 	if (err && err != -EOPNOTSUPP)
63564d47d50SRussell King 		dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port);
636c9a2356fSRussell King }
637c9a2356fSRussell King 
638c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
639c9a2356fSRussell King 				    unsigned int mode,
640c9a2356fSRussell King 				    phy_interface_t interface)
641c9a2356fSRussell King {
64230c4a5b0SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
64330c4a5b0SRussell King 	const struct mv88e6xxx_ops *ops;
64430c4a5b0SRussell King 	int err = 0;
64530c4a5b0SRussell King 
64630c4a5b0SRussell King 	ops = chip->info->ops;
64730c4a5b0SRussell King 
64830c4a5b0SRussell King 	/* Internal PHYs propagate their configuration directly to the MAC.
64930c4a5b0SRussell King 	 * External PHYs depend on whether the PPU is enabled for this port.
65030c4a5b0SRussell King 	 * FIXME: we should be using the PPU enable state here. What about
65130c4a5b0SRussell King 	 * an automedia port?
65230c4a5b0SRussell King 	 */
65330c4a5b0SRussell King 	if (!mv88e6xxx_phy_is_internal(ds, port) && ops->port_set_link) {
65430c4a5b0SRussell King 		mv88e6xxx_reg_lock(chip);
65530c4a5b0SRussell King 		err = ops->port_set_link(chip, port, LINK_FORCED_DOWN);
65630c4a5b0SRussell King 		mv88e6xxx_reg_unlock(chip);
65730c4a5b0SRussell King 
65830c4a5b0SRussell King 		if (err)
65930c4a5b0SRussell King 			dev_err(chip->dev,
66030c4a5b0SRussell King 				"p%d: failed to force MAC link down\n", port);
66130c4a5b0SRussell King 	}
662c9a2356fSRussell King }
663c9a2356fSRussell King 
664c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
665c9a2356fSRussell King 				  unsigned int mode, phy_interface_t interface,
6665b502a7bSRussell King 				  struct phy_device *phydev,
6675b502a7bSRussell King 				  int speed, int duplex,
6685b502a7bSRussell King 				  bool tx_pause, bool rx_pause)
669c9a2356fSRussell King {
67030c4a5b0SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
67130c4a5b0SRussell King 	const struct mv88e6xxx_ops *ops;
67230c4a5b0SRussell King 	int err = 0;
67330c4a5b0SRussell King 
67430c4a5b0SRussell King 	ops = chip->info->ops;
67530c4a5b0SRussell King 
67630c4a5b0SRussell King 	/* Internal PHYs propagate their configuration directly to the MAC.
67730c4a5b0SRussell King 	 * External PHYs depend on whether the PPU is enabled for this port.
67830c4a5b0SRussell King 	 * FIXME: we should be using the PPU enable state here. What about
67930c4a5b0SRussell King 	 * an automedia port?
68030c4a5b0SRussell King 	 */
68130c4a5b0SRussell King 	if (!mv88e6xxx_phy_is_internal(ds, port)) {
68230c4a5b0SRussell King 		mv88e6xxx_reg_lock(chip);
68330c4a5b0SRussell King 		/* FIXME: for an automedia port, should we force the link
68430c4a5b0SRussell King 		 * down here - what if the link comes up due to "other" media
68530c4a5b0SRussell King 		 * while we're bringing the port up, how is the exclusivity
68630c4a5b0SRussell King 		 * handled in the Marvell hardware? E.g. port 4 on 88E6532
68730c4a5b0SRussell King 		 * shared between internal PHY and Serdes.
68830c4a5b0SRussell King 		 */
68930c4a5b0SRussell King 		if (ops->port_set_speed) {
69030c4a5b0SRussell King 			err = ops->port_set_speed(chip, port, speed);
69130c4a5b0SRussell King 			if (err && err != -EOPNOTSUPP)
69230c4a5b0SRussell King 				goto error;
69330c4a5b0SRussell King 		}
69430c4a5b0SRussell King 
69530c4a5b0SRussell King 		if (ops->port_set_duplex) {
69630c4a5b0SRussell King 			err = ops->port_set_duplex(chip, port, duplex);
69730c4a5b0SRussell King 			if (err && err != -EOPNOTSUPP)
69830c4a5b0SRussell King 				goto error;
69930c4a5b0SRussell King 		}
70030c4a5b0SRussell King 
70130c4a5b0SRussell King 		if (ops->port_set_link)
70230c4a5b0SRussell King 			err = ops->port_set_link(chip, port, LINK_FORCED_UP);
70330c4a5b0SRussell King error:
70430c4a5b0SRussell King 		mv88e6xxx_reg_unlock(chip);
70530c4a5b0SRussell King 
70630c4a5b0SRussell King 		if (err && err != -EOPNOTSUPP)
70730c4a5b0SRussell King 			dev_err(ds->dev,
70830c4a5b0SRussell King 				"p%d: failed to configure MAC link up\n", port);
70930c4a5b0SRussell King 	}
710c9a2356fSRussell King }
711c9a2356fSRussell King 
712a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
713fad09c73SVivien Didelot {
714a605a0feSAndrew Lunn 	if (!chip->info->ops->stats_snapshot)
715a605a0feSAndrew Lunn 		return -EOPNOTSUPP;
716fad09c73SVivien Didelot 
717a605a0feSAndrew Lunn 	return chip->info->ops->stats_snapshot(chip, port);
718fad09c73SVivien Didelot }
719fad09c73SVivien Didelot 
720fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
721dfafe449SAndrew Lunn 	{ "in_good_octets",		8, 0x00, STATS_TYPE_BANK0, },
722dfafe449SAndrew Lunn 	{ "in_bad_octets",		4, 0x02, STATS_TYPE_BANK0, },
723dfafe449SAndrew Lunn 	{ "in_unicast",			4, 0x04, STATS_TYPE_BANK0, },
724dfafe449SAndrew Lunn 	{ "in_broadcasts",		4, 0x06, STATS_TYPE_BANK0, },
725dfafe449SAndrew Lunn 	{ "in_multicasts",		4, 0x07, STATS_TYPE_BANK0, },
726dfafe449SAndrew Lunn 	{ "in_pause",			4, 0x16, STATS_TYPE_BANK0, },
727dfafe449SAndrew Lunn 	{ "in_undersize",		4, 0x18, STATS_TYPE_BANK0, },
728dfafe449SAndrew Lunn 	{ "in_fragments",		4, 0x19, STATS_TYPE_BANK0, },
729dfafe449SAndrew Lunn 	{ "in_oversize",		4, 0x1a, STATS_TYPE_BANK0, },
730dfafe449SAndrew Lunn 	{ "in_jabber",			4, 0x1b, STATS_TYPE_BANK0, },
731dfafe449SAndrew Lunn 	{ "in_rx_error",		4, 0x1c, STATS_TYPE_BANK0, },
732dfafe449SAndrew Lunn 	{ "in_fcs_error",		4, 0x1d, STATS_TYPE_BANK0, },
733dfafe449SAndrew Lunn 	{ "out_octets",			8, 0x0e, STATS_TYPE_BANK0, },
734dfafe449SAndrew Lunn 	{ "out_unicast",		4, 0x10, STATS_TYPE_BANK0, },
735dfafe449SAndrew Lunn 	{ "out_broadcasts",		4, 0x13, STATS_TYPE_BANK0, },
736dfafe449SAndrew Lunn 	{ "out_multicasts",		4, 0x12, STATS_TYPE_BANK0, },
737dfafe449SAndrew Lunn 	{ "out_pause",			4, 0x15, STATS_TYPE_BANK0, },
738dfafe449SAndrew Lunn 	{ "excessive",			4, 0x11, STATS_TYPE_BANK0, },
739dfafe449SAndrew Lunn 	{ "collisions",			4, 0x1e, STATS_TYPE_BANK0, },
740dfafe449SAndrew Lunn 	{ "deferred",			4, 0x05, STATS_TYPE_BANK0, },
741dfafe449SAndrew Lunn 	{ "single",			4, 0x14, STATS_TYPE_BANK0, },
742dfafe449SAndrew Lunn 	{ "multiple",			4, 0x17, STATS_TYPE_BANK0, },
743dfafe449SAndrew Lunn 	{ "out_fcs_error",		4, 0x03, STATS_TYPE_BANK0, },
744dfafe449SAndrew Lunn 	{ "late",			4, 0x1f, STATS_TYPE_BANK0, },
745dfafe449SAndrew Lunn 	{ "hist_64bytes",		4, 0x08, STATS_TYPE_BANK0, },
746dfafe449SAndrew Lunn 	{ "hist_65_127bytes",		4, 0x09, STATS_TYPE_BANK0, },
747dfafe449SAndrew Lunn 	{ "hist_128_255bytes",		4, 0x0a, STATS_TYPE_BANK0, },
748dfafe449SAndrew Lunn 	{ "hist_256_511bytes",		4, 0x0b, STATS_TYPE_BANK0, },
749dfafe449SAndrew Lunn 	{ "hist_512_1023bytes",		4, 0x0c, STATS_TYPE_BANK0, },
750dfafe449SAndrew Lunn 	{ "hist_1024_max_bytes",	4, 0x0d, STATS_TYPE_BANK0, },
751dfafe449SAndrew Lunn 	{ "sw_in_discards",		4, 0x10, STATS_TYPE_PORT, },
752dfafe449SAndrew Lunn 	{ "sw_in_filtered",		2, 0x12, STATS_TYPE_PORT, },
753dfafe449SAndrew Lunn 	{ "sw_out_filtered",		2, 0x13, STATS_TYPE_PORT, },
754dfafe449SAndrew Lunn 	{ "in_discards",		4, 0x00, STATS_TYPE_BANK1, },
755dfafe449SAndrew Lunn 	{ "in_filtered",		4, 0x01, STATS_TYPE_BANK1, },
756dfafe449SAndrew Lunn 	{ "in_accepted",		4, 0x02, STATS_TYPE_BANK1, },
757dfafe449SAndrew Lunn 	{ "in_bad_accepted",		4, 0x03, STATS_TYPE_BANK1, },
758dfafe449SAndrew Lunn 	{ "in_good_avb_class_a",	4, 0x04, STATS_TYPE_BANK1, },
759dfafe449SAndrew Lunn 	{ "in_good_avb_class_b",	4, 0x05, STATS_TYPE_BANK1, },
760dfafe449SAndrew Lunn 	{ "in_bad_avb_class_a",		4, 0x06, STATS_TYPE_BANK1, },
761dfafe449SAndrew Lunn 	{ "in_bad_avb_class_b",		4, 0x07, STATS_TYPE_BANK1, },
762dfafe449SAndrew Lunn 	{ "tcam_counter_0",		4, 0x08, STATS_TYPE_BANK1, },
763dfafe449SAndrew Lunn 	{ "tcam_counter_1",		4, 0x09, STATS_TYPE_BANK1, },
764dfafe449SAndrew Lunn 	{ "tcam_counter_2",		4, 0x0a, STATS_TYPE_BANK1, },
765dfafe449SAndrew Lunn 	{ "tcam_counter_3",		4, 0x0b, STATS_TYPE_BANK1, },
766dfafe449SAndrew Lunn 	{ "in_da_unknown",		4, 0x0e, STATS_TYPE_BANK1, },
767dfafe449SAndrew Lunn 	{ "in_management",		4, 0x0f, STATS_TYPE_BANK1, },
768dfafe449SAndrew Lunn 	{ "out_queue_0",		4, 0x10, STATS_TYPE_BANK1, },
769dfafe449SAndrew Lunn 	{ "out_queue_1",		4, 0x11, STATS_TYPE_BANK1, },
770dfafe449SAndrew Lunn 	{ "out_queue_2",		4, 0x12, STATS_TYPE_BANK1, },
771dfafe449SAndrew Lunn 	{ "out_queue_3",		4, 0x13, STATS_TYPE_BANK1, },
772dfafe449SAndrew Lunn 	{ "out_queue_4",		4, 0x14, STATS_TYPE_BANK1, },
773dfafe449SAndrew Lunn 	{ "out_queue_5",		4, 0x15, STATS_TYPE_BANK1, },
774dfafe449SAndrew Lunn 	{ "out_queue_6",		4, 0x16, STATS_TYPE_BANK1, },
775dfafe449SAndrew Lunn 	{ "out_queue_7",		4, 0x17, STATS_TYPE_BANK1, },
776dfafe449SAndrew Lunn 	{ "out_cut_through",		4, 0x18, STATS_TYPE_BANK1, },
777dfafe449SAndrew Lunn 	{ "out_octets_a",		4, 0x1a, STATS_TYPE_BANK1, },
778dfafe449SAndrew Lunn 	{ "out_octets_b",		4, 0x1b, STATS_TYPE_BANK1, },
779dfafe449SAndrew Lunn 	{ "out_management",		4, 0x1f, STATS_TYPE_BANK1, },
780fad09c73SVivien Didelot };
781fad09c73SVivien Didelot 
782fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
783fad09c73SVivien Didelot 					    struct mv88e6xxx_hw_stat *s,
784e0d8b615SAndrew Lunn 					    int port, u16 bank1_select,
785e0d8b615SAndrew Lunn 					    u16 histogram)
786fad09c73SVivien Didelot {
787fad09c73SVivien Didelot 	u32 low;
788fad09c73SVivien Didelot 	u32 high = 0;
789dfafe449SAndrew Lunn 	u16 reg = 0;
7900e7b9925SAndrew Lunn 	int err;
791fad09c73SVivien Didelot 	u64 value;
792fad09c73SVivien Didelot 
793fad09c73SVivien Didelot 	switch (s->type) {
794dfafe449SAndrew Lunn 	case STATS_TYPE_PORT:
7950e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
7960e7b9925SAndrew Lunn 		if (err)
7976c3442f5SJisheng Zhang 			return U64_MAX;
798fad09c73SVivien Didelot 
7990e7b9925SAndrew Lunn 		low = reg;
800cda9f4aaSAndrew Lunn 		if (s->size == 4) {
8010e7b9925SAndrew Lunn 			err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
8020e7b9925SAndrew Lunn 			if (err)
8036c3442f5SJisheng Zhang 				return U64_MAX;
80484b3fd1fSRasmus Villemoes 			low |= ((u32)reg) << 16;
805fad09c73SVivien Didelot 		}
806fad09c73SVivien Didelot 		break;
807dfafe449SAndrew Lunn 	case STATS_TYPE_BANK1:
808e0d8b615SAndrew Lunn 		reg = bank1_select;
809dfafe449SAndrew Lunn 		/* fall through */
810dfafe449SAndrew Lunn 	case STATS_TYPE_BANK0:
811e0d8b615SAndrew Lunn 		reg |= s->reg | histogram;
8127f9ef3afSAndrew Lunn 		mv88e6xxx_g1_stats_read(chip, reg, &low);
813cda9f4aaSAndrew Lunn 		if (s->size == 8)
8147f9ef3afSAndrew Lunn 			mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
8159fc3e4dcSGustavo A. R. Silva 		break;
8169fc3e4dcSGustavo A. R. Silva 	default:
8176c3442f5SJisheng Zhang 		return U64_MAX;
818fad09c73SVivien Didelot 	}
8196e46e2d8SAndrew Lunn 	value = (((u64)high) << 32) | low;
820fad09c73SVivien Didelot 	return value;
821fad09c73SVivien Didelot }
822fad09c73SVivien Didelot 
823436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
824dfafe449SAndrew Lunn 				       uint8_t *data, int types)
825fad09c73SVivien Didelot {
826fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
827fad09c73SVivien Didelot 	int i, j;
828fad09c73SVivien Didelot 
829fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
830fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
831dfafe449SAndrew Lunn 		if (stat->type & types) {
832fad09c73SVivien Didelot 			memcpy(data + j * ETH_GSTRING_LEN, stat->string,
833fad09c73SVivien Didelot 			       ETH_GSTRING_LEN);
834fad09c73SVivien Didelot 			j++;
835fad09c73SVivien Didelot 		}
836fad09c73SVivien Didelot 	}
837436fe17dSAndrew Lunn 
838436fe17dSAndrew Lunn 	return j;
839fad09c73SVivien Didelot }
840fad09c73SVivien Didelot 
841436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
842dfafe449SAndrew Lunn 				       uint8_t *data)
843dfafe449SAndrew Lunn {
844436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
845dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_PORT);
846dfafe449SAndrew Lunn }
847dfafe449SAndrew Lunn 
8481f71836fSRasmus Villemoes static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip,
8491f71836fSRasmus Villemoes 				       uint8_t *data)
8501f71836fSRasmus Villemoes {
8511f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0);
8521f71836fSRasmus Villemoes }
8531f71836fSRasmus Villemoes 
854436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
855dfafe449SAndrew Lunn 				       uint8_t *data)
856dfafe449SAndrew Lunn {
857436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
858dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
859dfafe449SAndrew Lunn }
860dfafe449SAndrew Lunn 
86165f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = {
86265f60e45SAndrew Lunn 	"atu_member_violation",
86365f60e45SAndrew Lunn 	"atu_miss_violation",
86465f60e45SAndrew Lunn 	"atu_full_violation",
86565f60e45SAndrew Lunn 	"vtu_member_violation",
86665f60e45SAndrew Lunn 	"vtu_miss_violation",
86765f60e45SAndrew Lunn };
86865f60e45SAndrew Lunn 
86965f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data)
87065f60e45SAndrew Lunn {
87165f60e45SAndrew Lunn 	unsigned int i;
87265f60e45SAndrew Lunn 
87365f60e45SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++)
87465f60e45SAndrew Lunn 		strlcpy(data + i * ETH_GSTRING_LEN,
87565f60e45SAndrew Lunn 			mv88e6xxx_atu_vtu_stats_strings[i],
87665f60e45SAndrew Lunn 			ETH_GSTRING_LEN);
87765f60e45SAndrew Lunn }
87865f60e45SAndrew Lunn 
879dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
88089f09048SFlorian Fainelli 				  u32 stringset, uint8_t *data)
881fad09c73SVivien Didelot {
88204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
883436fe17dSAndrew Lunn 	int count = 0;
884dfafe449SAndrew Lunn 
88589f09048SFlorian Fainelli 	if (stringset != ETH_SS_STATS)
88689f09048SFlorian Fainelli 		return;
88789f09048SFlorian Fainelli 
888c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
889c6c8cd5eSAndrew Lunn 
890dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_strings)
891436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_strings(chip, data);
892436fe17dSAndrew Lunn 
893436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_strings) {
894436fe17dSAndrew Lunn 		data += count * ETH_GSTRING_LEN;
89565f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_strings(chip, port, data);
896436fe17dSAndrew Lunn 	}
897c6c8cd5eSAndrew Lunn 
89865f60e45SAndrew Lunn 	data += count * ETH_GSTRING_LEN;
89965f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_strings(data);
90065f60e45SAndrew Lunn 
901c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
902dfafe449SAndrew Lunn }
903dfafe449SAndrew Lunn 
904dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
905dfafe449SAndrew Lunn 					  int types)
906dfafe449SAndrew Lunn {
907fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
908fad09c73SVivien Didelot 	int i, j;
909fad09c73SVivien Didelot 
910fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
911fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
912dfafe449SAndrew Lunn 		if (stat->type & types)
913fad09c73SVivien Didelot 			j++;
914fad09c73SVivien Didelot 	}
915fad09c73SVivien Didelot 	return j;
916fad09c73SVivien Didelot }
917fad09c73SVivien Didelot 
918dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
919dfafe449SAndrew Lunn {
920dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
921dfafe449SAndrew Lunn 					      STATS_TYPE_PORT);
922dfafe449SAndrew Lunn }
923dfafe449SAndrew Lunn 
9241f71836fSRasmus Villemoes static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip)
9251f71836fSRasmus Villemoes {
9261f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0);
9271f71836fSRasmus Villemoes }
9281f71836fSRasmus Villemoes 
929dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
930dfafe449SAndrew Lunn {
931dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
932dfafe449SAndrew Lunn 					      STATS_TYPE_BANK1);
933dfafe449SAndrew Lunn }
934dfafe449SAndrew Lunn 
93589f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
936dfafe449SAndrew Lunn {
937dfafe449SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
938436fe17dSAndrew Lunn 	int serdes_count = 0;
939436fe17dSAndrew Lunn 	int count = 0;
940dfafe449SAndrew Lunn 
94189f09048SFlorian Fainelli 	if (sset != ETH_SS_STATS)
94289f09048SFlorian Fainelli 		return 0;
94389f09048SFlorian Fainelli 
944c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
945dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_sset_count)
946436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_sset_count(chip);
947436fe17dSAndrew Lunn 	if (count < 0)
948436fe17dSAndrew Lunn 		goto out;
949436fe17dSAndrew Lunn 
950436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_sset_count)
951436fe17dSAndrew Lunn 		serdes_count = chip->info->ops->serdes_get_sset_count(chip,
952436fe17dSAndrew Lunn 								      port);
95365f60e45SAndrew Lunn 	if (serdes_count < 0) {
954436fe17dSAndrew Lunn 		count = serdes_count;
95565f60e45SAndrew Lunn 		goto out;
95665f60e45SAndrew Lunn 	}
957436fe17dSAndrew Lunn 	count += serdes_count;
95865f60e45SAndrew Lunn 	count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings);
95965f60e45SAndrew Lunn 
960436fe17dSAndrew Lunn out:
961c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
962dfafe449SAndrew Lunn 
963436fe17dSAndrew Lunn 	return count;
964dfafe449SAndrew Lunn }
965dfafe449SAndrew Lunn 
966436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
967e0d8b615SAndrew Lunn 				     uint64_t *data, int types,
968e0d8b615SAndrew Lunn 				     u16 bank1_select, u16 histogram)
969052f947fSAndrew Lunn {
970052f947fSAndrew Lunn 	struct mv88e6xxx_hw_stat *stat;
971052f947fSAndrew Lunn 	int i, j;
972052f947fSAndrew Lunn 
973052f947fSAndrew Lunn 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
974052f947fSAndrew Lunn 		stat = &mv88e6xxx_hw_stats[i];
975052f947fSAndrew Lunn 		if (stat->type & types) {
976c9acece0SRasmus Villemoes 			mv88e6xxx_reg_lock(chip);
977e0d8b615SAndrew Lunn 			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
978e0d8b615SAndrew Lunn 							      bank1_select,
979e0d8b615SAndrew Lunn 							      histogram);
980c9acece0SRasmus Villemoes 			mv88e6xxx_reg_unlock(chip);
981377cda13SAndrew Lunn 
982052f947fSAndrew Lunn 			j++;
983052f947fSAndrew Lunn 		}
984052f947fSAndrew Lunn 	}
985436fe17dSAndrew Lunn 	return j;
986052f947fSAndrew Lunn }
987052f947fSAndrew Lunn 
988436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
989052f947fSAndrew Lunn 				     uint64_t *data)
990052f947fSAndrew Lunn {
991052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
992e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
99357d1ef38SVivien Didelot 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
994052f947fSAndrew Lunn }
995052f947fSAndrew Lunn 
9961f71836fSRasmus Villemoes static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
9971f71836fSRasmus Villemoes 				     uint64_t *data)
9981f71836fSRasmus Villemoes {
9991f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0,
10001f71836fSRasmus Villemoes 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
10011f71836fSRasmus Villemoes }
10021f71836fSRasmus Villemoes 
1003436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1004052f947fSAndrew Lunn 				     uint64_t *data)
1005052f947fSAndrew Lunn {
1006052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1007e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
100857d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
100957d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1010e0d8b615SAndrew Lunn }
1011e0d8b615SAndrew Lunn 
1012436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1013e0d8b615SAndrew Lunn 				     uint64_t *data)
1014e0d8b615SAndrew Lunn {
1015e0d8b615SAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1016e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
101757d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
101857d1ef38SVivien Didelot 					 0);
1019052f947fSAndrew Lunn }
1020052f947fSAndrew Lunn 
102165f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
102265f60e45SAndrew Lunn 					uint64_t *data)
102365f60e45SAndrew Lunn {
102465f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_member_violation;
102565f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_miss_violation;
102665f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_full_violation;
102765f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_member_violation;
102865f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_miss_violation;
102965f60e45SAndrew Lunn }
103065f60e45SAndrew Lunn 
1031052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
1032052f947fSAndrew Lunn 				uint64_t *data)
1033052f947fSAndrew Lunn {
1034436fe17dSAndrew Lunn 	int count = 0;
1035436fe17dSAndrew Lunn 
1036052f947fSAndrew Lunn 	if (chip->info->ops->stats_get_stats)
1037436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_stats(chip, port, data);
1038436fe17dSAndrew Lunn 
1039c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1040436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_stats) {
1041436fe17dSAndrew Lunn 		data += count;
104265f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_stats(chip, port, data);
1043436fe17dSAndrew Lunn 	}
104465f60e45SAndrew Lunn 	data += count;
104565f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_stats(chip, port, data);
1046c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1047052f947fSAndrew Lunn }
1048052f947fSAndrew Lunn 
1049fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
1050fad09c73SVivien Didelot 					uint64_t *data)
1051fad09c73SVivien Didelot {
105204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1053fad09c73SVivien Didelot 	int ret;
1054fad09c73SVivien Didelot 
1055c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1056fad09c73SVivien Didelot 
1057a605a0feSAndrew Lunn 	ret = mv88e6xxx_stats_snapshot(chip, port);
1058c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1059377cda13SAndrew Lunn 
1060377cda13SAndrew Lunn 	if (ret < 0)
1061fad09c73SVivien Didelot 		return;
1062052f947fSAndrew Lunn 
1063052f947fSAndrew Lunn 	mv88e6xxx_get_stats(chip, port, data);
1064fad09c73SVivien Didelot 
1065fad09c73SVivien Didelot }
1066fad09c73SVivien Didelot 
1067fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
1068fad09c73SVivien Didelot {
10690d30bbd0SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
10700d30bbd0SAndrew Lunn 	int len;
10710d30bbd0SAndrew Lunn 
10720d30bbd0SAndrew Lunn 	len = 32 * sizeof(u16);
10730d30bbd0SAndrew Lunn 	if (chip->info->ops->serdes_get_regs_len)
10740d30bbd0SAndrew Lunn 		len += chip->info->ops->serdes_get_regs_len(chip, port);
10750d30bbd0SAndrew Lunn 
10760d30bbd0SAndrew Lunn 	return len;
1077fad09c73SVivien Didelot }
1078fad09c73SVivien Didelot 
1079fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
1080fad09c73SVivien Didelot 			       struct ethtool_regs *regs, void *_p)
1081fad09c73SVivien Didelot {
108204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
10830e7b9925SAndrew Lunn 	int err;
10840e7b9925SAndrew Lunn 	u16 reg;
1085fad09c73SVivien Didelot 	u16 *p = _p;
1086fad09c73SVivien Didelot 	int i;
1087fad09c73SVivien Didelot 
1088a5f39326SVivien Didelot 	regs->version = chip->info->prod_num;
1089fad09c73SVivien Didelot 
1090fad09c73SVivien Didelot 	memset(p, 0xff, 32 * sizeof(u16));
1091fad09c73SVivien Didelot 
1092c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1093fad09c73SVivien Didelot 
1094fad09c73SVivien Didelot 	for (i = 0; i < 32; i++) {
1095fad09c73SVivien Didelot 
10960e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, i, &reg);
10970e7b9925SAndrew Lunn 		if (!err)
10980e7b9925SAndrew Lunn 			p[i] = reg;
1099fad09c73SVivien Didelot 	}
1100fad09c73SVivien Didelot 
11010d30bbd0SAndrew Lunn 	if (chip->info->ops->serdes_get_regs)
11020d30bbd0SAndrew Lunn 		chip->info->ops->serdes_get_regs(chip, port, &p[i]);
11030d30bbd0SAndrew Lunn 
1104c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1105fad09c73SVivien Didelot }
1106fad09c73SVivien Didelot 
110708f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
1108fad09c73SVivien Didelot 				 struct ethtool_eee *e)
1109fad09c73SVivien Didelot {
11105480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
11115480db69SVivien Didelot 	return 0;
1112fad09c73SVivien Didelot }
1113fad09c73SVivien Didelot 
111408f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port,
111546587e4aSVivien Didelot 				 struct ethtool_eee *e)
1116fad09c73SVivien Didelot {
11175480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
11185480db69SVivien Didelot 	return 0;
1119fad09c73SVivien Didelot }
1120fad09c73SVivien Didelot 
11219dc8b13eSVivien Didelot /* Mask of the local ports allowed to receive frames from a given fabric port */
1122e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
1123fad09c73SVivien Didelot {
11249dc8b13eSVivien Didelot 	struct dsa_switch *ds = chip->ds;
11259dc8b13eSVivien Didelot 	struct dsa_switch_tree *dst = ds->dst;
1126e5887a2aSVivien Didelot 	struct net_device *br;
11279dc8b13eSVivien Didelot 	struct dsa_port *dp;
11289dc8b13eSVivien Didelot 	bool found = false;
1129e5887a2aSVivien Didelot 	u16 pvlan;
1130fad09c73SVivien Didelot 
11319dc8b13eSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list) {
11329dc8b13eSVivien Didelot 		if (dp->ds->index == dev && dp->index == port) {
11339dc8b13eSVivien Didelot 			found = true;
11349dc8b13eSVivien Didelot 			break;
11359dc8b13eSVivien Didelot 		}
11369dc8b13eSVivien Didelot 	}
1137fad09c73SVivien Didelot 
1138e5887a2aSVivien Didelot 	/* Prevent frames from unknown switch or port */
11399dc8b13eSVivien Didelot 	if (!found)
1140e5887a2aSVivien Didelot 		return 0;
1141e5887a2aSVivien Didelot 
1142e5887a2aSVivien Didelot 	/* Frames from DSA links and CPU ports can egress any local port */
11439dc8b13eSVivien Didelot 	if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA)
1144e5887a2aSVivien Didelot 		return mv88e6xxx_port_mask(chip);
1145e5887a2aSVivien Didelot 
11469dc8b13eSVivien Didelot 	br = dp->bridge_dev;
1147e5887a2aSVivien Didelot 	pvlan = 0;
1148e5887a2aSVivien Didelot 
1149e5887a2aSVivien Didelot 	/* Frames from user ports can egress any local DSA links and CPU ports,
1150e5887a2aSVivien Didelot 	 * as well as any local member of their bridge group.
1151e5887a2aSVivien Didelot 	 */
11529dc8b13eSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list)
11539dc8b13eSVivien Didelot 		if (dp->ds == ds &&
11549dc8b13eSVivien Didelot 		    (dp->type == DSA_PORT_TYPE_CPU ||
11559dc8b13eSVivien Didelot 		     dp->type == DSA_PORT_TYPE_DSA ||
11569dc8b13eSVivien Didelot 		     (br && dp->bridge_dev == br)))
11579dc8b13eSVivien Didelot 			pvlan |= BIT(dp->index);
1158e5887a2aSVivien Didelot 
1159e5887a2aSVivien Didelot 	return pvlan;
1160fad09c73SVivien Didelot }
1161e5887a2aSVivien Didelot 
1162240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port)
1163e5887a2aSVivien Didelot {
1164e5887a2aSVivien Didelot 	u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port);
1165fad09c73SVivien Didelot 
1166fad09c73SVivien Didelot 	/* prevent frames from going back out of the port they came in on */
1167fad09c73SVivien Didelot 	output_ports &= ~BIT(port);
1168fad09c73SVivien Didelot 
11695a7921f4SVivien Didelot 	return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
1170fad09c73SVivien Didelot }
1171fad09c73SVivien Didelot 
1172fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
1173fad09c73SVivien Didelot 					 u8 state)
1174fad09c73SVivien Didelot {
117504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1176fad09c73SVivien Didelot 	int err;
1177fad09c73SVivien Didelot 
1178c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1179f894c29cSVivien Didelot 	err = mv88e6xxx_port_set_state(chip, port, state);
1180c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1181fad09c73SVivien Didelot 
1182fad09c73SVivien Didelot 	if (err)
1183774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to update state\n", port);
1184fad09c73SVivien Didelot }
1185fad09c73SVivien Didelot 
118693e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip)
118793e18d61SVivien Didelot {
118893e18d61SVivien Didelot 	int err;
118993e18d61SVivien Didelot 
119093e18d61SVivien Didelot 	if (chip->info->ops->ieee_pri_map) {
119193e18d61SVivien Didelot 		err = chip->info->ops->ieee_pri_map(chip);
119293e18d61SVivien Didelot 		if (err)
119393e18d61SVivien Didelot 			return err;
119493e18d61SVivien Didelot 	}
119593e18d61SVivien Didelot 
119693e18d61SVivien Didelot 	if (chip->info->ops->ip_pri_map) {
119793e18d61SVivien Didelot 		err = chip->info->ops->ip_pri_map(chip);
119893e18d61SVivien Didelot 		if (err)
119993e18d61SVivien Didelot 			return err;
120093e18d61SVivien Didelot 	}
120193e18d61SVivien Didelot 
120293e18d61SVivien Didelot 	return 0;
120393e18d61SVivien Didelot }
120493e18d61SVivien Didelot 
1205c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
1206c7f047b6SVivien Didelot {
1207c5f51765SVivien Didelot 	struct dsa_switch *ds = chip->ds;
1208c7f047b6SVivien Didelot 	int target, port;
1209c7f047b6SVivien Didelot 	int err;
1210c7f047b6SVivien Didelot 
1211c7f047b6SVivien Didelot 	if (!chip->info->global2_addr)
1212c7f047b6SVivien Didelot 		return 0;
1213c7f047b6SVivien Didelot 
1214c7f047b6SVivien Didelot 	/* Initialize the routing port to the 32 possible target devices */
1215c7f047b6SVivien Didelot 	for (target = 0; target < 32; target++) {
1216c5f51765SVivien Didelot 		port = dsa_routing_port(ds, target);
1217c5f51765SVivien Didelot 		if (port == ds->num_ports)
1218c7f047b6SVivien Didelot 			port = 0x1f;
1219c7f047b6SVivien Didelot 
1220c7f047b6SVivien Didelot 		err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
1221c7f047b6SVivien Didelot 		if (err)
1222c7f047b6SVivien Didelot 			return err;
1223c7f047b6SVivien Didelot 	}
1224c7f047b6SVivien Didelot 
122502317e68SVivien Didelot 	if (chip->info->ops->set_cascade_port) {
122602317e68SVivien Didelot 		port = MV88E6XXX_CASCADE_PORT_MULTIPLE;
122702317e68SVivien Didelot 		err = chip->info->ops->set_cascade_port(chip, port);
122802317e68SVivien Didelot 		if (err)
122902317e68SVivien Didelot 			return err;
123002317e68SVivien Didelot 	}
123102317e68SVivien Didelot 
123223c98919SVivien Didelot 	err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index);
123323c98919SVivien Didelot 	if (err)
123423c98919SVivien Didelot 		return err;
123523c98919SVivien Didelot 
1236c7f047b6SVivien Didelot 	return 0;
1237c7f047b6SVivien Didelot }
1238c7f047b6SVivien Didelot 
1239b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip)
1240b28f872dSVivien Didelot {
1241b28f872dSVivien Didelot 	/* Clear all trunk masks and mapping */
1242b28f872dSVivien Didelot 	if (chip->info->global2_addr)
1243b28f872dSVivien Didelot 		return mv88e6xxx_g2_trunk_clear(chip);
1244b28f872dSVivien Didelot 
1245b28f872dSVivien Didelot 	return 0;
1246b28f872dSVivien Didelot }
1247b28f872dSVivien Didelot 
12489e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
12499e5baf9bSVivien Didelot {
12509e5baf9bSVivien Didelot 	if (chip->info->ops->rmu_disable)
12519e5baf9bSVivien Didelot 		return chip->info->ops->rmu_disable(chip);
12529e5baf9bSVivien Didelot 
12539e5baf9bSVivien Didelot 	return 0;
12549e5baf9bSVivien Didelot }
12559e5baf9bSVivien Didelot 
12569e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
12579e907d73SVivien Didelot {
12589e907d73SVivien Didelot 	if (chip->info->ops->pot_clear)
12599e907d73SVivien Didelot 		return chip->info->ops->pot_clear(chip);
12609e907d73SVivien Didelot 
12619e907d73SVivien Didelot 	return 0;
12629e907d73SVivien Didelot }
12639e907d73SVivien Didelot 
126451c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip)
126551c901a7SVivien Didelot {
126651c901a7SVivien Didelot 	if (chip->info->ops->mgmt_rsvd2cpu)
126751c901a7SVivien Didelot 		return chip->info->ops->mgmt_rsvd2cpu(chip);
126851c901a7SVivien Didelot 
126951c901a7SVivien Didelot 	return 0;
127051c901a7SVivien Didelot }
127151c901a7SVivien Didelot 
1272a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
1273a2ac29d2SVivien Didelot {
1274c3a7d4adSVivien Didelot 	int err;
1275c3a7d4adSVivien Didelot 
1276daefc943SVivien Didelot 	err = mv88e6xxx_g1_atu_flush(chip, 0, true);
1277daefc943SVivien Didelot 	if (err)
1278daefc943SVivien Didelot 		return err;
1279daefc943SVivien Didelot 
1280c3a7d4adSVivien Didelot 	err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
1281c3a7d4adSVivien Didelot 	if (err)
1282c3a7d4adSVivien Didelot 		return err;
1283c3a7d4adSVivien Didelot 
1284a2ac29d2SVivien Didelot 	return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
1285a2ac29d2SVivien Didelot }
1286a2ac29d2SVivien Didelot 
1287cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip)
1288cd8da8bbSVivien Didelot {
1289cd8da8bbSVivien Didelot 	int port;
1290cd8da8bbSVivien Didelot 	int err;
1291cd8da8bbSVivien Didelot 
1292cd8da8bbSVivien Didelot 	if (!chip->info->ops->irl_init_all)
1293cd8da8bbSVivien Didelot 		return 0;
1294cd8da8bbSVivien Didelot 
1295cd8da8bbSVivien Didelot 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
1296cd8da8bbSVivien Didelot 		/* Disable ingress rate limiting by resetting all per port
1297cd8da8bbSVivien Didelot 		 * ingress rate limit resources to their initial state.
1298cd8da8bbSVivien Didelot 		 */
1299cd8da8bbSVivien Didelot 		err = chip->info->ops->irl_init_all(chip, port);
1300cd8da8bbSVivien Didelot 		if (err)
1301cd8da8bbSVivien Didelot 			return err;
1302cd8da8bbSVivien Didelot 	}
1303cd8da8bbSVivien Didelot 
1304cd8da8bbSVivien Didelot 	return 0;
1305cd8da8bbSVivien Didelot }
1306cd8da8bbSVivien Didelot 
130704a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip)
130804a69a17SVivien Didelot {
130904a69a17SVivien Didelot 	if (chip->info->ops->set_switch_mac) {
131004a69a17SVivien Didelot 		u8 addr[ETH_ALEN];
131104a69a17SVivien Didelot 
131204a69a17SVivien Didelot 		eth_random_addr(addr);
131304a69a17SVivien Didelot 
131404a69a17SVivien Didelot 		return chip->info->ops->set_switch_mac(chip, addr);
131504a69a17SVivien Didelot 	}
131604a69a17SVivien Didelot 
131704a69a17SVivien Didelot 	return 0;
131804a69a17SVivien Didelot }
131904a69a17SVivien Didelot 
132017a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
132117a1594eSVivien Didelot {
132217a1594eSVivien Didelot 	u16 pvlan = 0;
132317a1594eSVivien Didelot 
132417a1594eSVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
1325d14939beSVivien Didelot 		return 0;
132617a1594eSVivien Didelot 
132717a1594eSVivien Didelot 	/* Skip the local source device, which uses in-chip port VLAN */
132817a1594eSVivien Didelot 	if (dev != chip->ds->index)
1329aec5ac88SVivien Didelot 		pvlan = mv88e6xxx_port_vlan(chip, dev, port);
133017a1594eSVivien Didelot 
133117a1594eSVivien Didelot 	return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
133217a1594eSVivien Didelot }
133317a1594eSVivien Didelot 
133481228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
133581228996SVivien Didelot {
133617a1594eSVivien Didelot 	int dev, port;
133717a1594eSVivien Didelot 	int err;
133817a1594eSVivien Didelot 
133981228996SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
134081228996SVivien Didelot 		return 0;
134181228996SVivien Didelot 
134281228996SVivien Didelot 	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
134381228996SVivien Didelot 	 * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
134481228996SVivien Didelot 	 */
134517a1594eSVivien Didelot 	err = mv88e6xxx_g2_misc_4_bit_port(chip);
134617a1594eSVivien Didelot 	if (err)
134717a1594eSVivien Didelot 		return err;
134817a1594eSVivien Didelot 
134917a1594eSVivien Didelot 	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) {
135017a1594eSVivien Didelot 		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) {
135117a1594eSVivien Didelot 			err = mv88e6xxx_pvt_map(chip, dev, port);
135217a1594eSVivien Didelot 			if (err)
135317a1594eSVivien Didelot 				return err;
135417a1594eSVivien Didelot 		}
135517a1594eSVivien Didelot 	}
135617a1594eSVivien Didelot 
135717a1594eSVivien Didelot 	return 0;
135881228996SVivien Didelot }
135981228996SVivien Didelot 
1360749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
1361749efcb8SVivien Didelot {
1362749efcb8SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1363749efcb8SVivien Didelot 	int err;
1364749efcb8SVivien Didelot 
1365c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1366e606ca36SVivien Didelot 	err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
1367c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1368749efcb8SVivien Didelot 
1369749efcb8SVivien Didelot 	if (err)
1370774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to flush ATU\n", port);
1371749efcb8SVivien Didelot }
1372749efcb8SVivien Didelot 
1373b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)
1374b486d7c9SVivien Didelot {
1375b486d7c9SVivien Didelot 	if (!chip->info->max_vid)
1376b486d7c9SVivien Didelot 		return 0;
1377b486d7c9SVivien Didelot 
1378b486d7c9SVivien Didelot 	return mv88e6xxx_g1_vtu_flush(chip);
1379b486d7c9SVivien Didelot }
1380b486d7c9SVivien Didelot 
1381f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,
1382f1394b78SVivien Didelot 				 struct mv88e6xxx_vtu_entry *entry)
1383f1394b78SVivien Didelot {
1384f1394b78SVivien Didelot 	if (!chip->info->ops->vtu_getnext)
1385f1394b78SVivien Didelot 		return -EOPNOTSUPP;
1386f1394b78SVivien Didelot 
1387f1394b78SVivien Didelot 	return chip->info->ops->vtu_getnext(chip, entry);
1388f1394b78SVivien Didelot }
1389f1394b78SVivien Didelot 
13900ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
13910ad5daf6SVivien Didelot 				   struct mv88e6xxx_vtu_entry *entry)
13920ad5daf6SVivien Didelot {
13930ad5daf6SVivien Didelot 	if (!chip->info->ops->vtu_loadpurge)
13940ad5daf6SVivien Didelot 		return -EOPNOTSUPP;
13950ad5daf6SVivien Didelot 
13960ad5daf6SVivien Didelot 	return chip->info->ops->vtu_loadpurge(chip, entry);
13970ad5daf6SVivien Didelot }
13980ad5daf6SVivien Didelot 
1399d7f435f9SVivien Didelot static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
1400fad09c73SVivien Didelot {
1401fad09c73SVivien Didelot 	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
1402425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1403fad09c73SVivien Didelot 	int i, err;
1404fad09c73SVivien Didelot 
1405fad09c73SVivien Didelot 	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
1406fad09c73SVivien Didelot 
1407fad09c73SVivien Didelot 	/* Set every FID bit used by the (un)bridged ports */
1408370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1409b4e48c50SVivien Didelot 		err = mv88e6xxx_port_get_fid(chip, i, fid);
1410fad09c73SVivien Didelot 		if (err)
1411fad09c73SVivien Didelot 			return err;
1412fad09c73SVivien Didelot 
1413fad09c73SVivien Didelot 		set_bit(*fid, fid_bitmap);
1414fad09c73SVivien Didelot 	}
1415fad09c73SVivien Didelot 
1416fad09c73SVivien Didelot 	/* Set every FID bit used by the VLAN entries */
1417425d2d37SVivien Didelot 	vlan.vid = chip->info->max_vid;
1418425d2d37SVivien Didelot 	vlan.valid = false;
1419425d2d37SVivien Didelot 
1420fad09c73SVivien Didelot 	do {
1421f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1422fad09c73SVivien Didelot 		if (err)
1423fad09c73SVivien Didelot 			return err;
1424fad09c73SVivien Didelot 
1425fad09c73SVivien Didelot 		if (!vlan.valid)
1426fad09c73SVivien Didelot 			break;
1427fad09c73SVivien Didelot 
1428fad09c73SVivien Didelot 		set_bit(vlan.fid, fid_bitmap);
14293cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
1430fad09c73SVivien Didelot 
1431fad09c73SVivien Didelot 	/* The reset value 0x000 is used to indicate that multiple address
1432fad09c73SVivien Didelot 	 * databases are not needed. Return the next positive available.
1433fad09c73SVivien Didelot 	 */
1434fad09c73SVivien Didelot 	*fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1);
1435fad09c73SVivien Didelot 	if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
1436fad09c73SVivien Didelot 		return -ENOSPC;
1437fad09c73SVivien Didelot 
1438fad09c73SVivien Didelot 	/* Clear the database */
1439daefc943SVivien Didelot 	return mv88e6xxx_g1_atu_flush(chip, *fid, true);
1440fad09c73SVivien Didelot }
1441fad09c73SVivien Didelot 
144223e8b470SAndrew Lunn static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
144323e8b470SAndrew Lunn {
144423e8b470SAndrew Lunn 	if (chip->info->ops->atu_get_hash)
144523e8b470SAndrew Lunn 		return chip->info->ops->atu_get_hash(chip, hash);
144623e8b470SAndrew Lunn 
144723e8b470SAndrew Lunn 	return -EOPNOTSUPP;
144823e8b470SAndrew Lunn }
144923e8b470SAndrew Lunn 
145023e8b470SAndrew Lunn static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash)
145123e8b470SAndrew Lunn {
145223e8b470SAndrew Lunn 	if (chip->info->ops->atu_set_hash)
145323e8b470SAndrew Lunn 		return chip->info->ops->atu_set_hash(chip, hash);
145423e8b470SAndrew Lunn 
145523e8b470SAndrew Lunn 	return -EOPNOTSUPP;
145623e8b470SAndrew Lunn }
145723e8b470SAndrew Lunn 
1458fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
1459fad09c73SVivien Didelot 					u16 vid_begin, u16 vid_end)
1460fad09c73SVivien Didelot {
146104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1462425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1463fad09c73SVivien Didelot 	int i, err;
1464fad09c73SVivien Didelot 
1465db06ae41SAndrew Lunn 	/* DSA and CPU ports have to be members of multiple vlans */
1466db06ae41SAndrew Lunn 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
1467db06ae41SAndrew Lunn 		return 0;
1468db06ae41SAndrew Lunn 
1469fad09c73SVivien Didelot 	if (!vid_begin)
1470fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1471fad09c73SVivien Didelot 
1472425d2d37SVivien Didelot 	vlan.vid = vid_begin - 1;
1473425d2d37SVivien Didelot 	vlan.valid = false;
1474425d2d37SVivien Didelot 
1475fad09c73SVivien Didelot 	do {
1476f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1477fad09c73SVivien Didelot 		if (err)
14787095a4c4SVivien Didelot 			return err;
1479fad09c73SVivien Didelot 
1480fad09c73SVivien Didelot 		if (!vlan.valid)
1481fad09c73SVivien Didelot 			break;
1482fad09c73SVivien Didelot 
1483fad09c73SVivien Didelot 		if (vlan.vid > vid_end)
1484fad09c73SVivien Didelot 			break;
1485fad09c73SVivien Didelot 
1486370b4ffbSVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1487fad09c73SVivien Didelot 			if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
1488fad09c73SVivien Didelot 				continue;
1489fad09c73SVivien Didelot 
149068bb8ea8SVivien Didelot 			if (!dsa_to_port(ds, i)->slave)
149166e2809dSAndrew Lunn 				continue;
149266e2809dSAndrew Lunn 
1493bd00e053SVivien Didelot 			if (vlan.member[i] ==
14947ec60d6eSVivien Didelot 			    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1495fad09c73SVivien Didelot 				continue;
1496fad09c73SVivien Didelot 
1497c8652c83SVivien Didelot 			if (dsa_to_port(ds, i)->bridge_dev ==
149868bb8ea8SVivien Didelot 			    dsa_to_port(ds, port)->bridge_dev)
1499fad09c73SVivien Didelot 				break; /* same bridge, check next VLAN */
1500fad09c73SVivien Didelot 
1501c8652c83SVivien Didelot 			if (!dsa_to_port(ds, i)->bridge_dev)
150266e2809dSAndrew Lunn 				continue;
150366e2809dSAndrew Lunn 
1504743fcc28SAndrew Lunn 			dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
1505743fcc28SAndrew Lunn 				port, vlan.vid, i,
1506c8652c83SVivien Didelot 				netdev_name(dsa_to_port(ds, i)->bridge_dev));
15077095a4c4SVivien Didelot 			return -EOPNOTSUPP;
1508fad09c73SVivien Didelot 		}
1509fad09c73SVivien Didelot 	} while (vlan.vid < vid_end);
1510fad09c73SVivien Didelot 
15117095a4c4SVivien Didelot 	return 0;
1512fad09c73SVivien Didelot }
1513fad09c73SVivien Didelot 
1514fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
1515fad09c73SVivien Didelot 					 bool vlan_filtering)
1516fad09c73SVivien Didelot {
151704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
151881c6edb2SVivien Didelot 	u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
151981c6edb2SVivien Didelot 		MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
15200e7b9925SAndrew Lunn 	int err;
1521fad09c73SVivien Didelot 
15223cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1523fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1524fad09c73SVivien Didelot 
1525c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1526385a0995SVivien Didelot 	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
1527c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1528fad09c73SVivien Didelot 
15290e7b9925SAndrew Lunn 	return err;
1530fad09c73SVivien Didelot }
1531fad09c73SVivien Didelot 
1532fad09c73SVivien Didelot static int
1533fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
153480e02360SVivien Didelot 			    const struct switchdev_obj_port_vlan *vlan)
1535fad09c73SVivien Didelot {
153604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1537fad09c73SVivien Didelot 	int err;
1538fad09c73SVivien Didelot 
15393cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1540fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1541fad09c73SVivien Didelot 
1542fad09c73SVivien Didelot 	/* If the requested port doesn't belong to the same bridge as the VLAN
1543fad09c73SVivien Didelot 	 * members, do not support it (yet) and fallback to software VLAN.
1544fad09c73SVivien Didelot 	 */
15457095a4c4SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1546fad09c73SVivien Didelot 	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
1547fad09c73SVivien Didelot 					   vlan->vid_end);
15487095a4c4SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1549fad09c73SVivien Didelot 
1550fad09c73SVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
1551fad09c73SVivien Didelot 	 * so skip the prepare phase.
1552fad09c73SVivien Didelot 	 */
15537095a4c4SVivien Didelot 	return err;
1554fad09c73SVivien Didelot }
1555fad09c73SVivien Didelot 
1556a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
1557a4c93ae1SAndrew Lunn 					const unsigned char *addr, u16 vid,
1558a4c93ae1SAndrew Lunn 					u8 state)
1559a4c93ae1SAndrew Lunn {
1560a4c93ae1SAndrew Lunn 	struct mv88e6xxx_atu_entry entry;
15615ef8d249SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
15625ef8d249SVivien Didelot 	u16 fid;
1563a4c93ae1SAndrew Lunn 	int err;
1564a4c93ae1SAndrew Lunn 
1565a4c93ae1SAndrew Lunn 	/* Null VLAN ID corresponds to the port private database */
15665ef8d249SVivien Didelot 	if (vid == 0) {
15675ef8d249SVivien Didelot 		err = mv88e6xxx_port_get_fid(chip, port, &fid);
1568a4c93ae1SAndrew Lunn 		if (err)
1569a4c93ae1SAndrew Lunn 			return err;
15705ef8d249SVivien Didelot 	} else {
15715ef8d249SVivien Didelot 		vlan.vid = vid - 1;
15725ef8d249SVivien Didelot 		vlan.valid = false;
15735ef8d249SVivien Didelot 
15745ef8d249SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
15755ef8d249SVivien Didelot 		if (err)
15765ef8d249SVivien Didelot 			return err;
15775ef8d249SVivien Didelot 
15785ef8d249SVivien Didelot 		/* switchdev expects -EOPNOTSUPP to honor software VLANs */
15795ef8d249SVivien Didelot 		if (vlan.vid != vid || !vlan.valid)
15805ef8d249SVivien Didelot 			return -EOPNOTSUPP;
15815ef8d249SVivien Didelot 
15825ef8d249SVivien Didelot 		fid = vlan.fid;
15835ef8d249SVivien Didelot 	}
1584a4c93ae1SAndrew Lunn 
1585d8291a95SVivien Didelot 	entry.state = 0;
1586a4c93ae1SAndrew Lunn 	ether_addr_copy(entry.mac, addr);
1587a4c93ae1SAndrew Lunn 	eth_addr_dec(entry.mac);
1588a4c93ae1SAndrew Lunn 
15895ef8d249SVivien Didelot 	err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry);
1590a4c93ae1SAndrew Lunn 	if (err)
1591a4c93ae1SAndrew Lunn 		return err;
1592a4c93ae1SAndrew Lunn 
1593a4c93ae1SAndrew Lunn 	/* Initialize a fresh ATU entry if it isn't found */
1594d8291a95SVivien Didelot 	if (!entry.state || !ether_addr_equal(entry.mac, addr)) {
1595a4c93ae1SAndrew Lunn 		memset(&entry, 0, sizeof(entry));
1596a4c93ae1SAndrew Lunn 		ether_addr_copy(entry.mac, addr);
1597a4c93ae1SAndrew Lunn 	}
1598a4c93ae1SAndrew Lunn 
1599a4c93ae1SAndrew Lunn 	/* Purge the ATU entry only if no port is using it anymore */
1600d8291a95SVivien Didelot 	if (!state) {
1601a4c93ae1SAndrew Lunn 		entry.portvec &= ~BIT(port);
1602a4c93ae1SAndrew Lunn 		if (!entry.portvec)
1603d8291a95SVivien Didelot 			entry.state = 0;
1604a4c93ae1SAndrew Lunn 	} else {
1605a4c93ae1SAndrew Lunn 		entry.portvec |= BIT(port);
1606a4c93ae1SAndrew Lunn 		entry.state = state;
1607a4c93ae1SAndrew Lunn 	}
1608a4c93ae1SAndrew Lunn 
16095ef8d249SVivien Didelot 	return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry);
1610a4c93ae1SAndrew Lunn }
1611a4c93ae1SAndrew Lunn 
1612da7dc875SVivien Didelot static int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port,
1613da7dc875SVivien Didelot 				  const struct mv88e6xxx_policy *policy)
1614da7dc875SVivien Didelot {
1615da7dc875SVivien Didelot 	enum mv88e6xxx_policy_mapping mapping = policy->mapping;
1616da7dc875SVivien Didelot 	enum mv88e6xxx_policy_action action = policy->action;
1617da7dc875SVivien Didelot 	const u8 *addr = policy->addr;
1618da7dc875SVivien Didelot 	u16 vid = policy->vid;
1619da7dc875SVivien Didelot 	u8 state;
1620da7dc875SVivien Didelot 	int err;
1621da7dc875SVivien Didelot 	int id;
1622da7dc875SVivien Didelot 
1623da7dc875SVivien Didelot 	if (!chip->info->ops->port_set_policy)
1624da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1625da7dc875SVivien Didelot 
1626da7dc875SVivien Didelot 	switch (mapping) {
1627da7dc875SVivien Didelot 	case MV88E6XXX_POLICY_MAPPING_DA:
1628da7dc875SVivien Didelot 	case MV88E6XXX_POLICY_MAPPING_SA:
1629da7dc875SVivien Didelot 		if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
1630da7dc875SVivien Didelot 			state = 0; /* Dissociate the port and address */
1631da7dc875SVivien Didelot 		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
1632da7dc875SVivien Didelot 			 is_multicast_ether_addr(addr))
1633da7dc875SVivien Didelot 			state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY;
1634da7dc875SVivien Didelot 		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
1635da7dc875SVivien Didelot 			 is_unicast_ether_addr(addr))
1636da7dc875SVivien Didelot 			state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY;
1637da7dc875SVivien Didelot 		else
1638da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1639da7dc875SVivien Didelot 
1640da7dc875SVivien Didelot 		err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
1641da7dc875SVivien Didelot 						   state);
1642da7dc875SVivien Didelot 		if (err)
1643da7dc875SVivien Didelot 			return err;
1644da7dc875SVivien Didelot 		break;
1645da7dc875SVivien Didelot 	default:
1646da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1647da7dc875SVivien Didelot 	}
1648da7dc875SVivien Didelot 
1649da7dc875SVivien Didelot 	/* Skip the port's policy clearing if the mapping is still in use */
1650da7dc875SVivien Didelot 	if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
1651da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1652da7dc875SVivien Didelot 			if (policy->port == port &&
1653da7dc875SVivien Didelot 			    policy->mapping == mapping &&
1654da7dc875SVivien Didelot 			    policy->action != action)
1655da7dc875SVivien Didelot 				return 0;
1656da7dc875SVivien Didelot 
1657da7dc875SVivien Didelot 	return chip->info->ops->port_set_policy(chip, port, mapping, action);
1658da7dc875SVivien Didelot }
1659da7dc875SVivien Didelot 
1660da7dc875SVivien Didelot static int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port,
1661da7dc875SVivien Didelot 				   struct ethtool_rx_flow_spec *fs)
1662da7dc875SVivien Didelot {
1663da7dc875SVivien Didelot 	struct ethhdr *mac_entry = &fs->h_u.ether_spec;
1664da7dc875SVivien Didelot 	struct ethhdr *mac_mask = &fs->m_u.ether_spec;
1665da7dc875SVivien Didelot 	enum mv88e6xxx_policy_mapping mapping;
1666da7dc875SVivien Didelot 	enum mv88e6xxx_policy_action action;
1667da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1668da7dc875SVivien Didelot 	u16 vid = 0;
1669da7dc875SVivien Didelot 	u8 *addr;
1670da7dc875SVivien Didelot 	int err;
1671da7dc875SVivien Didelot 	int id;
1672da7dc875SVivien Didelot 
1673da7dc875SVivien Didelot 	if (fs->location != RX_CLS_LOC_ANY)
1674da7dc875SVivien Didelot 		return -EINVAL;
1675da7dc875SVivien Didelot 
1676da7dc875SVivien Didelot 	if (fs->ring_cookie == RX_CLS_FLOW_DISC)
1677da7dc875SVivien Didelot 		action = MV88E6XXX_POLICY_ACTION_DISCARD;
1678da7dc875SVivien Didelot 	else
1679da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1680da7dc875SVivien Didelot 
1681da7dc875SVivien Didelot 	switch (fs->flow_type & ~FLOW_EXT) {
1682da7dc875SVivien Didelot 	case ETHER_FLOW:
1683da7dc875SVivien Didelot 		if (!is_zero_ether_addr(mac_mask->h_dest) &&
1684da7dc875SVivien Didelot 		    is_zero_ether_addr(mac_mask->h_source)) {
1685da7dc875SVivien Didelot 			mapping = MV88E6XXX_POLICY_MAPPING_DA;
1686da7dc875SVivien Didelot 			addr = mac_entry->h_dest;
1687da7dc875SVivien Didelot 		} else if (is_zero_ether_addr(mac_mask->h_dest) &&
1688da7dc875SVivien Didelot 		    !is_zero_ether_addr(mac_mask->h_source)) {
1689da7dc875SVivien Didelot 			mapping = MV88E6XXX_POLICY_MAPPING_SA;
1690da7dc875SVivien Didelot 			addr = mac_entry->h_source;
1691da7dc875SVivien Didelot 		} else {
1692da7dc875SVivien Didelot 			/* Cannot support DA and SA mapping in the same rule */
1693da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1694da7dc875SVivien Didelot 		}
1695da7dc875SVivien Didelot 		break;
1696da7dc875SVivien Didelot 	default:
1697da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1698da7dc875SVivien Didelot 	}
1699da7dc875SVivien Didelot 
1700da7dc875SVivien Didelot 	if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) {
1701da7dc875SVivien Didelot 		if (fs->m_ext.vlan_tci != 0xffff)
1702da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1703da7dc875SVivien Didelot 		vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK;
1704da7dc875SVivien Didelot 	}
1705da7dc875SVivien Didelot 
1706da7dc875SVivien Didelot 	idr_for_each_entry(&chip->policies, policy, id) {
1707da7dc875SVivien Didelot 		if (policy->port == port && policy->mapping == mapping &&
1708da7dc875SVivien Didelot 		    policy->action == action && policy->vid == vid &&
1709da7dc875SVivien Didelot 		    ether_addr_equal(policy->addr, addr))
1710da7dc875SVivien Didelot 			return -EEXIST;
1711da7dc875SVivien Didelot 	}
1712da7dc875SVivien Didelot 
1713da7dc875SVivien Didelot 	policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL);
1714da7dc875SVivien Didelot 	if (!policy)
1715da7dc875SVivien Didelot 		return -ENOMEM;
1716da7dc875SVivien Didelot 
1717da7dc875SVivien Didelot 	fs->location = 0;
1718da7dc875SVivien Didelot 	err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff,
1719da7dc875SVivien Didelot 			    GFP_KERNEL);
1720da7dc875SVivien Didelot 	if (err) {
1721da7dc875SVivien Didelot 		devm_kfree(chip->dev, policy);
1722da7dc875SVivien Didelot 		return err;
1723da7dc875SVivien Didelot 	}
1724da7dc875SVivien Didelot 
1725da7dc875SVivien Didelot 	memcpy(&policy->fs, fs, sizeof(*fs));
1726da7dc875SVivien Didelot 	ether_addr_copy(policy->addr, addr);
1727da7dc875SVivien Didelot 	policy->mapping = mapping;
1728da7dc875SVivien Didelot 	policy->action = action;
1729da7dc875SVivien Didelot 	policy->port = port;
1730da7dc875SVivien Didelot 	policy->vid = vid;
1731da7dc875SVivien Didelot 
1732da7dc875SVivien Didelot 	err = mv88e6xxx_policy_apply(chip, port, policy);
1733da7dc875SVivien Didelot 	if (err) {
1734da7dc875SVivien Didelot 		idr_remove(&chip->policies, fs->location);
1735da7dc875SVivien Didelot 		devm_kfree(chip->dev, policy);
1736da7dc875SVivien Didelot 		return err;
1737da7dc875SVivien Didelot 	}
1738da7dc875SVivien Didelot 
1739da7dc875SVivien Didelot 	return 0;
1740da7dc875SVivien Didelot }
1741da7dc875SVivien Didelot 
1742da7dc875SVivien Didelot static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,
1743da7dc875SVivien Didelot 			       struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
1744da7dc875SVivien Didelot {
1745da7dc875SVivien Didelot 	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
1746da7dc875SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1747da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1748da7dc875SVivien Didelot 	int err;
1749da7dc875SVivien Didelot 	int id;
1750da7dc875SVivien Didelot 
1751da7dc875SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1752da7dc875SVivien Didelot 
1753da7dc875SVivien Didelot 	switch (rxnfc->cmd) {
1754da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRLCNT:
1755da7dc875SVivien Didelot 		rxnfc->data = 0;
1756da7dc875SVivien Didelot 		rxnfc->data |= RX_CLS_LOC_SPECIAL;
1757da7dc875SVivien Didelot 		rxnfc->rule_cnt = 0;
1758da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1759da7dc875SVivien Didelot 			if (policy->port == port)
1760da7dc875SVivien Didelot 				rxnfc->rule_cnt++;
1761da7dc875SVivien Didelot 		err = 0;
1762da7dc875SVivien Didelot 		break;
1763da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRULE:
1764da7dc875SVivien Didelot 		err = -ENOENT;
1765da7dc875SVivien Didelot 		policy = idr_find(&chip->policies, fs->location);
1766da7dc875SVivien Didelot 		if (policy) {
1767da7dc875SVivien Didelot 			memcpy(fs, &policy->fs, sizeof(*fs));
1768da7dc875SVivien Didelot 			err = 0;
1769da7dc875SVivien Didelot 		}
1770da7dc875SVivien Didelot 		break;
1771da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRLALL:
1772da7dc875SVivien Didelot 		rxnfc->data = 0;
1773da7dc875SVivien Didelot 		rxnfc->rule_cnt = 0;
1774da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1775da7dc875SVivien Didelot 			if (policy->port == port)
1776da7dc875SVivien Didelot 				rule_locs[rxnfc->rule_cnt++] = id;
1777da7dc875SVivien Didelot 		err = 0;
1778da7dc875SVivien Didelot 		break;
1779da7dc875SVivien Didelot 	default:
1780da7dc875SVivien Didelot 		err = -EOPNOTSUPP;
1781da7dc875SVivien Didelot 		break;
1782da7dc875SVivien Didelot 	}
1783da7dc875SVivien Didelot 
1784da7dc875SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1785da7dc875SVivien Didelot 
1786da7dc875SVivien Didelot 	return err;
1787da7dc875SVivien Didelot }
1788da7dc875SVivien Didelot 
1789da7dc875SVivien Didelot static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port,
1790da7dc875SVivien Didelot 			       struct ethtool_rxnfc *rxnfc)
1791da7dc875SVivien Didelot {
1792da7dc875SVivien Didelot 	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
1793da7dc875SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1794da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1795da7dc875SVivien Didelot 	int err;
1796da7dc875SVivien Didelot 
1797da7dc875SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1798da7dc875SVivien Didelot 
1799da7dc875SVivien Didelot 	switch (rxnfc->cmd) {
1800da7dc875SVivien Didelot 	case ETHTOOL_SRXCLSRLINS:
1801da7dc875SVivien Didelot 		err = mv88e6xxx_policy_insert(chip, port, fs);
1802da7dc875SVivien Didelot 		break;
1803da7dc875SVivien Didelot 	case ETHTOOL_SRXCLSRLDEL:
1804da7dc875SVivien Didelot 		err = -ENOENT;
1805da7dc875SVivien Didelot 		policy = idr_remove(&chip->policies, fs->location);
1806da7dc875SVivien Didelot 		if (policy) {
1807da7dc875SVivien Didelot 			policy->action = MV88E6XXX_POLICY_ACTION_NORMAL;
1808da7dc875SVivien Didelot 			err = mv88e6xxx_policy_apply(chip, port, policy);
1809da7dc875SVivien Didelot 			devm_kfree(chip->dev, policy);
1810da7dc875SVivien Didelot 		}
1811da7dc875SVivien Didelot 		break;
1812da7dc875SVivien Didelot 	default:
1813da7dc875SVivien Didelot 		err = -EOPNOTSUPP;
1814da7dc875SVivien Didelot 		break;
1815da7dc875SVivien Didelot 	}
1816da7dc875SVivien Didelot 
1817da7dc875SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1818da7dc875SVivien Didelot 
1819da7dc875SVivien Didelot 	return err;
1820da7dc875SVivien Didelot }
1821da7dc875SVivien Didelot 
182287fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
182387fa886eSAndrew Lunn 					u16 vid)
182487fa886eSAndrew Lunn {
182587fa886eSAndrew Lunn 	const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
182687fa886eSAndrew Lunn 	u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
182787fa886eSAndrew Lunn 
182887fa886eSAndrew Lunn 	return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
182987fa886eSAndrew Lunn }
183087fa886eSAndrew Lunn 
183187fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
183287fa886eSAndrew Lunn {
183387fa886eSAndrew Lunn 	int port;
183487fa886eSAndrew Lunn 	int err;
183587fa886eSAndrew Lunn 
183687fa886eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
183787fa886eSAndrew Lunn 		err = mv88e6xxx_port_add_broadcast(chip, port, vid);
183887fa886eSAndrew Lunn 		if (err)
183987fa886eSAndrew Lunn 			return err;
184087fa886eSAndrew Lunn 	}
184187fa886eSAndrew Lunn 
184287fa886eSAndrew Lunn 	return 0;
184387fa886eSAndrew Lunn }
184487fa886eSAndrew Lunn 
1845b1ac6fb4SVivien Didelot static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port,
1846933b4425SRussell King 				    u16 vid, u8 member, bool warn)
1847fad09c73SVivien Didelot {
1848b1ac6fb4SVivien Didelot 	const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1849b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1850b1ac6fb4SVivien Didelot 	int i, err;
1851fad09c73SVivien Didelot 
1852b1ac6fb4SVivien Didelot 	if (!vid)
1853b1ac6fb4SVivien Didelot 		return -EOPNOTSUPP;
1854b1ac6fb4SVivien Didelot 
1855b1ac6fb4SVivien Didelot 	vlan.vid = vid - 1;
1856b1ac6fb4SVivien Didelot 	vlan.valid = false;
1857b1ac6fb4SVivien Didelot 
1858b1ac6fb4SVivien Didelot 	err = mv88e6xxx_vtu_getnext(chip, &vlan);
1859fad09c73SVivien Didelot 	if (err)
1860fad09c73SVivien Didelot 		return err;
1861fad09c73SVivien Didelot 
1862b1ac6fb4SVivien Didelot 	if (vlan.vid != vid || !vlan.valid) {
1863b1ac6fb4SVivien Didelot 		memset(&vlan, 0, sizeof(vlan));
1864b1ac6fb4SVivien Didelot 
1865b1ac6fb4SVivien Didelot 		err = mv88e6xxx_atu_new(chip, &vlan.fid);
1866b1ac6fb4SVivien Didelot 		if (err)
1867b1ac6fb4SVivien Didelot 			return err;
1868b1ac6fb4SVivien Didelot 
1869b1ac6fb4SVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
1870b1ac6fb4SVivien Didelot 			if (i == port)
1871b1ac6fb4SVivien Didelot 				vlan.member[i] = member;
1872b1ac6fb4SVivien Didelot 			else
1873b1ac6fb4SVivien Didelot 				vlan.member[i] = non_member;
1874b1ac6fb4SVivien Didelot 
1875b1ac6fb4SVivien Didelot 		vlan.vid = vid;
18761cb9dfcaSRasmus Villemoes 		vlan.valid = true;
1877fad09c73SVivien Didelot 
187887fa886eSAndrew Lunn 		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
187987fa886eSAndrew Lunn 		if (err)
188087fa886eSAndrew Lunn 			return err;
188187fa886eSAndrew Lunn 
1882b1ac6fb4SVivien Didelot 		err = mv88e6xxx_broadcast_setup(chip, vlan.vid);
1883b1ac6fb4SVivien Didelot 		if (err)
1884b1ac6fb4SVivien Didelot 			return err;
1885b1ac6fb4SVivien Didelot 	} else if (vlan.member[port] != member) {
1886b1ac6fb4SVivien Didelot 		vlan.member[port] = member;
1887b1ac6fb4SVivien Didelot 
1888b1ac6fb4SVivien Didelot 		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
1889b1ac6fb4SVivien Didelot 		if (err)
1890b1ac6fb4SVivien Didelot 			return err;
1891933b4425SRussell King 	} else if (warn) {
1892b1ac6fb4SVivien Didelot 		dev_info(chip->dev, "p%d: already a member of VLAN %d\n",
1893b1ac6fb4SVivien Didelot 			 port, vid);
1894b1ac6fb4SVivien Didelot 	}
1895b1ac6fb4SVivien Didelot 
1896b1ac6fb4SVivien Didelot 	return 0;
1897fad09c73SVivien Didelot }
1898fad09c73SVivien Didelot 
1899fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
190080e02360SVivien Didelot 				    const struct switchdev_obj_port_vlan *vlan)
1901fad09c73SVivien Didelot {
190204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1903fad09c73SVivien Didelot 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1904fad09c73SVivien Didelot 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1905933b4425SRussell King 	bool warn;
1906c91498e1SVivien Didelot 	u8 member;
1907fad09c73SVivien Didelot 	u16 vid;
1908fad09c73SVivien Didelot 
19093cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1910fad09c73SVivien Didelot 		return;
1911fad09c73SVivien Didelot 
1912c91498e1SVivien Didelot 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
19137ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED;
1914c91498e1SVivien Didelot 	else if (untagged)
19157ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED;
1916c91498e1SVivien Didelot 	else
19177ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
1918c91498e1SVivien Didelot 
1919933b4425SRussell King 	/* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port
1920933b4425SRussell King 	 * and then the CPU port. Do not warn for duplicates for the CPU port.
1921933b4425SRussell King 	 */
1922933b4425SRussell King 	warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port);
1923933b4425SRussell King 
1924c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1925fad09c73SVivien Didelot 
1926fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
1927933b4425SRussell King 		if (mv88e6xxx_port_vlan_join(chip, port, vid, member, warn))
1928774439e5SVivien Didelot 			dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
1929fad09c73SVivien Didelot 				vid, untagged ? 'u' : 't');
1930fad09c73SVivien Didelot 
193177064f37SVivien Didelot 	if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end))
1932774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to set PVID %d\n", port,
1933fad09c73SVivien Didelot 			vlan->vid_end);
1934fad09c73SVivien Didelot 
1935c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1936fad09c73SVivien Didelot }
1937fad09c73SVivien Didelot 
193852109892SVivien Didelot static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip,
1939fad09c73SVivien Didelot 				     int port, u16 vid)
1940fad09c73SVivien Didelot {
1941b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1942fad09c73SVivien Didelot 	int i, err;
1943fad09c73SVivien Didelot 
194452109892SVivien Didelot 	if (!vid)
194552109892SVivien Didelot 		return -EOPNOTSUPP;
194652109892SVivien Didelot 
194752109892SVivien Didelot 	vlan.vid = vid - 1;
194852109892SVivien Didelot 	vlan.valid = false;
194952109892SVivien Didelot 
195052109892SVivien Didelot 	err = mv88e6xxx_vtu_getnext(chip, &vlan);
1951fad09c73SVivien Didelot 	if (err)
1952fad09c73SVivien Didelot 		return err;
1953fad09c73SVivien Didelot 
195452109892SVivien Didelot 	/* If the VLAN doesn't exist in hardware or the port isn't a member,
195552109892SVivien Didelot 	 * tell switchdev that this VLAN is likely handled in software.
195652109892SVivien Didelot 	 */
195752109892SVivien Didelot 	if (vlan.vid != vid || !vlan.valid ||
195852109892SVivien Didelot 	    vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1959fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1960fad09c73SVivien Didelot 
19617ec60d6eSVivien Didelot 	vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1962fad09c73SVivien Didelot 
1963fad09c73SVivien Didelot 	/* keep the VLAN unless all ports are excluded */
1964fad09c73SVivien Didelot 	vlan.valid = false;
1965370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
19667ec60d6eSVivien Didelot 		if (vlan.member[i] !=
19677ec60d6eSVivien Didelot 		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
1968fad09c73SVivien Didelot 			vlan.valid = true;
1969fad09c73SVivien Didelot 			break;
1970fad09c73SVivien Didelot 		}
1971fad09c73SVivien Didelot 	}
1972fad09c73SVivien Didelot 
19730ad5daf6SVivien Didelot 	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
1974fad09c73SVivien Didelot 	if (err)
1975fad09c73SVivien Didelot 		return err;
1976fad09c73SVivien Didelot 
1977e606ca36SVivien Didelot 	return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
1978fad09c73SVivien Didelot }
1979fad09c73SVivien Didelot 
1980fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
1981fad09c73SVivien Didelot 				   const struct switchdev_obj_port_vlan *vlan)
1982fad09c73SVivien Didelot {
198304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1984fad09c73SVivien Didelot 	u16 pvid, vid;
1985fad09c73SVivien Didelot 	int err = 0;
1986fad09c73SVivien Didelot 
19873cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1988fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1989fad09c73SVivien Didelot 
1990c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1991fad09c73SVivien Didelot 
199277064f37SVivien Didelot 	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
1993fad09c73SVivien Didelot 	if (err)
1994fad09c73SVivien Didelot 		goto unlock;
1995fad09c73SVivien Didelot 
1996fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
199752109892SVivien Didelot 		err = mv88e6xxx_port_vlan_leave(chip, port, vid);
1998fad09c73SVivien Didelot 		if (err)
1999fad09c73SVivien Didelot 			goto unlock;
2000fad09c73SVivien Didelot 
2001fad09c73SVivien Didelot 		if (vid == pvid) {
200277064f37SVivien Didelot 			err = mv88e6xxx_port_set_pvid(chip, port, 0);
2003fad09c73SVivien Didelot 			if (err)
2004fad09c73SVivien Didelot 				goto unlock;
2005fad09c73SVivien Didelot 		}
2006fad09c73SVivien Didelot 	}
2007fad09c73SVivien Didelot 
2008fad09c73SVivien Didelot unlock:
2009c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2010fad09c73SVivien Didelot 
2011fad09c73SVivien Didelot 	return err;
2012fad09c73SVivien Didelot }
2013fad09c73SVivien Didelot 
20141b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
20156c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
2016fad09c73SVivien Didelot {
201704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
20181b6dd556SArkadi Sharshevsky 	int err;
2019fad09c73SVivien Didelot 
2020c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
20211b6dd556SArkadi Sharshevsky 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
20221b6dd556SArkadi Sharshevsky 					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
2023c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
20241b6dd556SArkadi Sharshevsky 
20251b6dd556SArkadi Sharshevsky 	return err;
2026fad09c73SVivien Didelot }
2027fad09c73SVivien Didelot 
2028fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
20296c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
2030fad09c73SVivien Didelot {
203104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
203283dabd1fSVivien Didelot 	int err;
2033fad09c73SVivien Didelot 
2034c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2035d8291a95SVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
2036c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2037fad09c73SVivien Didelot 
203883dabd1fSVivien Didelot 	return err;
2039fad09c73SVivien Didelot }
2040fad09c73SVivien Didelot 
204183dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
2042fad09c73SVivien Didelot 				      u16 fid, u16 vid, int port,
20432bedde1aSArkadi Sharshevsky 				      dsa_fdb_dump_cb_t *cb, void *data)
2044fad09c73SVivien Didelot {
2045dabc1a96SVivien Didelot 	struct mv88e6xxx_atu_entry addr;
20462bedde1aSArkadi Sharshevsky 	bool is_static;
2047fad09c73SVivien Didelot 	int err;
2048fad09c73SVivien Didelot 
2049d8291a95SVivien Didelot 	addr.state = 0;
2050dabc1a96SVivien Didelot 	eth_broadcast_addr(addr.mac);
2051fad09c73SVivien Didelot 
2052fad09c73SVivien Didelot 	do {
2053dabc1a96SVivien Didelot 		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
2054fad09c73SVivien Didelot 		if (err)
205583dabd1fSVivien Didelot 			return err;
2056fad09c73SVivien Didelot 
2057d8291a95SVivien Didelot 		if (!addr.state)
2058fad09c73SVivien Didelot 			break;
2059fad09c73SVivien Didelot 
206001bd96c8SVivien Didelot 		if (addr.trunk || (addr.portvec & BIT(port)) == 0)
206183dabd1fSVivien Didelot 			continue;
2062fad09c73SVivien Didelot 
206383dabd1fSVivien Didelot 		if (!is_unicast_ether_addr(addr.mac))
206483dabd1fSVivien Didelot 			continue;
206583dabd1fSVivien Didelot 
20662bedde1aSArkadi Sharshevsky 		is_static = (addr.state ==
20672bedde1aSArkadi Sharshevsky 			     MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
20682bedde1aSArkadi Sharshevsky 		err = cb(addr.mac, vid, is_static, data);
206983dabd1fSVivien Didelot 		if (err)
207083dabd1fSVivien Didelot 			return err;
2071fad09c73SVivien Didelot 	} while (!is_broadcast_ether_addr(addr.mac));
2072fad09c73SVivien Didelot 
2073fad09c73SVivien Didelot 	return err;
2074fad09c73SVivien Didelot }
2075fad09c73SVivien Didelot 
207683dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
20772bedde1aSArkadi Sharshevsky 				  dsa_fdb_dump_cb_t *cb, void *data)
207883dabd1fSVivien Didelot {
2079425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
208083dabd1fSVivien Didelot 	u16 fid;
208183dabd1fSVivien Didelot 	int err;
208283dabd1fSVivien Didelot 
208383dabd1fSVivien Didelot 	/* Dump port's default Filtering Information Database (VLAN ID 0) */
2084b4e48c50SVivien Didelot 	err = mv88e6xxx_port_get_fid(chip, port, &fid);
208583dabd1fSVivien Didelot 	if (err)
208683dabd1fSVivien Didelot 		return err;
208783dabd1fSVivien Didelot 
20882bedde1aSArkadi Sharshevsky 	err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data);
208983dabd1fSVivien Didelot 	if (err)
209083dabd1fSVivien Didelot 		return err;
209183dabd1fSVivien Didelot 
209283dabd1fSVivien Didelot 	/* Dump VLANs' Filtering Information Databases */
2093425d2d37SVivien Didelot 	vlan.vid = chip->info->max_vid;
2094425d2d37SVivien Didelot 	vlan.valid = false;
2095425d2d37SVivien Didelot 
209683dabd1fSVivien Didelot 	do {
2097f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
209883dabd1fSVivien Didelot 		if (err)
209983dabd1fSVivien Didelot 			return err;
210083dabd1fSVivien Didelot 
210183dabd1fSVivien Didelot 		if (!vlan.valid)
210283dabd1fSVivien Didelot 			break;
210383dabd1fSVivien Didelot 
210483dabd1fSVivien Didelot 		err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port,
21052bedde1aSArkadi Sharshevsky 						 cb, data);
210683dabd1fSVivien Didelot 		if (err)
210783dabd1fSVivien Didelot 			return err;
21083cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
210983dabd1fSVivien Didelot 
211083dabd1fSVivien Didelot 	return err;
211183dabd1fSVivien Didelot }
211283dabd1fSVivien Didelot 
2113fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
21142bedde1aSArkadi Sharshevsky 				   dsa_fdb_dump_cb_t *cb, void *data)
2115fad09c73SVivien Didelot {
211604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2117fcf15367SVivien Didelot 	int err;
2118fad09c73SVivien Didelot 
2119c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2120fcf15367SVivien Didelot 	err = mv88e6xxx_port_db_dump(chip, port, cb, data);
2121c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2122fcf15367SVivien Didelot 
2123fcf15367SVivien Didelot 	return err;
2124fad09c73SVivien Didelot }
2125fad09c73SVivien Didelot 
2126240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
2127240ea3efSVivien Didelot 				struct net_device *br)
2128240ea3efSVivien Didelot {
2129ef2025ecSVivien Didelot 	struct dsa_switch *ds = chip->ds;
2130ef2025ecSVivien Didelot 	struct dsa_switch_tree *dst = ds->dst;
2131ef2025ecSVivien Didelot 	struct dsa_port *dp;
2132240ea3efSVivien Didelot 	int err;
2133240ea3efSVivien Didelot 
2134ef2025ecSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list) {
2135ef2025ecSVivien Didelot 		if (dp->bridge_dev == br) {
2136ef2025ecSVivien Didelot 			if (dp->ds == ds) {
2137ef2025ecSVivien Didelot 				/* This is a local bridge group member,
2138ef2025ecSVivien Didelot 				 * remap its Port VLAN Map.
2139ef2025ecSVivien Didelot 				 */
2140ef2025ecSVivien Didelot 				err = mv88e6xxx_port_vlan_map(chip, dp->index);
2141240ea3efSVivien Didelot 				if (err)
2142240ea3efSVivien Didelot 					return err;
2143ef2025ecSVivien Didelot 			} else {
2144ef2025ecSVivien Didelot 				/* This is an external bridge group member,
2145ef2025ecSVivien Didelot 				 * remap its cross-chip Port VLAN Table entry.
2146ef2025ecSVivien Didelot 				 */
2147ef2025ecSVivien Didelot 				err = mv88e6xxx_pvt_map(chip, dp->ds->index,
2148ef2025ecSVivien Didelot 							dp->index);
2149e96a6e02SVivien Didelot 				if (err)
2150e96a6e02SVivien Didelot 					return err;
2151e96a6e02SVivien Didelot 			}
2152e96a6e02SVivien Didelot 		}
2153e96a6e02SVivien Didelot 	}
2154e96a6e02SVivien Didelot 
2155240ea3efSVivien Didelot 	return 0;
2156240ea3efSVivien Didelot }
2157240ea3efSVivien Didelot 
2158fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
2159fae8a25eSVivien Didelot 				      struct net_device *br)
2160fad09c73SVivien Didelot {
216104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2162240ea3efSVivien Didelot 	int err;
2163fad09c73SVivien Didelot 
2164c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2165240ea3efSVivien Didelot 	err = mv88e6xxx_bridge_map(chip, br);
2166c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2167fad09c73SVivien Didelot 
2168fad09c73SVivien Didelot 	return err;
2169fad09c73SVivien Didelot }
2170fad09c73SVivien Didelot 
2171f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
2172f123f2fbSVivien Didelot 					struct net_device *br)
2173fad09c73SVivien Didelot {
217404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2175fad09c73SVivien Didelot 
2176c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2177240ea3efSVivien Didelot 	if (mv88e6xxx_bridge_map(chip, br) ||
2178240ea3efSVivien Didelot 	    mv88e6xxx_port_vlan_map(chip, port))
2179240ea3efSVivien Didelot 		dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
2180c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2181fad09c73SVivien Didelot }
2182fad09c73SVivien Didelot 
2183aec5ac88SVivien Didelot static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev,
2184aec5ac88SVivien Didelot 					   int port, struct net_device *br)
2185aec5ac88SVivien Didelot {
2186aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2187aec5ac88SVivien Didelot 	int err;
2188aec5ac88SVivien Didelot 
2189c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2190aec5ac88SVivien Didelot 	err = mv88e6xxx_pvt_map(chip, dev, port);
2191c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2192aec5ac88SVivien Didelot 
2193aec5ac88SVivien Didelot 	return err;
2194aec5ac88SVivien Didelot }
2195aec5ac88SVivien Didelot 
2196aec5ac88SVivien Didelot static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev,
2197aec5ac88SVivien Didelot 					     int port, struct net_device *br)
2198aec5ac88SVivien Didelot {
2199aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2200aec5ac88SVivien Didelot 
2201c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2202aec5ac88SVivien Didelot 	if (mv88e6xxx_pvt_map(chip, dev, port))
2203aec5ac88SVivien Didelot 		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
2204c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2205aec5ac88SVivien Didelot }
2206aec5ac88SVivien Didelot 
220717e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
220817e708baSVivien Didelot {
220917e708baSVivien Didelot 	if (chip->info->ops->reset)
221017e708baSVivien Didelot 		return chip->info->ops->reset(chip);
221117e708baSVivien Didelot 
221217e708baSVivien Didelot 	return 0;
221317e708baSVivien Didelot }
221417e708baSVivien Didelot 
2215309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
2216309eca6dSVivien Didelot {
2217309eca6dSVivien Didelot 	struct gpio_desc *gpiod = chip->reset;
2218309eca6dSVivien Didelot 
2219309eca6dSVivien Didelot 	/* If there is a GPIO connected to the reset pin, toggle it */
2220309eca6dSVivien Didelot 	if (gpiod) {
2221309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 1);
2222309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2223309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 0);
2224309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2225309eca6dSVivien Didelot 	}
2226309eca6dSVivien Didelot }
2227309eca6dSVivien Didelot 
22284ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
22294ac4b5a6SVivien Didelot {
22304ac4b5a6SVivien Didelot 	int i, err;
22314ac4b5a6SVivien Didelot 
22324ac4b5a6SVivien Didelot 	/* Set all ports to the Disabled state */
22334ac4b5a6SVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2234f894c29cSVivien Didelot 		err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED);
22354ac4b5a6SVivien Didelot 		if (err)
22364ac4b5a6SVivien Didelot 			return err;
22374ac4b5a6SVivien Didelot 	}
22384ac4b5a6SVivien Didelot 
22394ac4b5a6SVivien Didelot 	/* Wait for transmit queues to drain,
22404ac4b5a6SVivien Didelot 	 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
22414ac4b5a6SVivien Didelot 	 */
22424ac4b5a6SVivien Didelot 	usleep_range(2000, 4000);
22434ac4b5a6SVivien Didelot 
22444ac4b5a6SVivien Didelot 	return 0;
22454ac4b5a6SVivien Didelot }
22464ac4b5a6SVivien Didelot 
2247fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
2248fad09c73SVivien Didelot {
2249a935c052SVivien Didelot 	int err;
2250fad09c73SVivien Didelot 
22514ac4b5a6SVivien Didelot 	err = mv88e6xxx_disable_ports(chip);
22520e7b9925SAndrew Lunn 	if (err)
22530e7b9925SAndrew Lunn 		return err;
2254fad09c73SVivien Didelot 
2255309eca6dSVivien Didelot 	mv88e6xxx_hardware_reset(chip);
2256fad09c73SVivien Didelot 
225717e708baSVivien Didelot 	return mv88e6xxx_software_reset(chip);
2258fad09c73SVivien Didelot }
2259fad09c73SVivien Didelot 
22604314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
226131bef4e9SVivien Didelot 				   enum mv88e6xxx_frame_mode frame,
226231bef4e9SVivien Didelot 				   enum mv88e6xxx_egress_mode egress, u16 etype)
226356995cbcSAndrew Lunn {
226456995cbcSAndrew Lunn 	int err;
226556995cbcSAndrew Lunn 
22664314557cSVivien Didelot 	if (!chip->info->ops->port_set_frame_mode)
22674314557cSVivien Didelot 		return -EOPNOTSUPP;
22684314557cSVivien Didelot 
22694314557cSVivien Didelot 	err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
227056995cbcSAndrew Lunn 	if (err)
227156995cbcSAndrew Lunn 		return err;
227256995cbcSAndrew Lunn 
22734314557cSVivien Didelot 	err = chip->info->ops->port_set_frame_mode(chip, port, frame);
22744314557cSVivien Didelot 	if (err)
22754314557cSVivien Didelot 		return err;
22764314557cSVivien Didelot 
22774314557cSVivien Didelot 	if (chip->info->ops->port_set_ether_type)
22784314557cSVivien Didelot 		return chip->info->ops->port_set_ether_type(chip, port, etype);
22794314557cSVivien Didelot 
22804314557cSVivien Didelot 	return 0;
22814314557cSVivien Didelot }
22824314557cSVivien Didelot 
22834314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
22844314557cSVivien Didelot {
22854314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
228631bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2287b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
22884314557cSVivien Didelot }
22894314557cSVivien Didelot 
22904314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
22914314557cSVivien Didelot {
22924314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
229331bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2294b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
22954314557cSVivien Didelot }
22964314557cSVivien Didelot 
22974314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
22984314557cSVivien Didelot {
22994314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port,
23004314557cSVivien Didelot 				       MV88E6XXX_FRAME_MODE_ETHERTYPE,
230131bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_ETHERTYPE,
230231bef4e9SVivien Didelot 				       ETH_P_EDSA);
23034314557cSVivien Didelot }
23044314557cSVivien Didelot 
23054314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port)
23064314557cSVivien Didelot {
23074314557cSVivien Didelot 	if (dsa_is_dsa_port(chip->ds, port))
23084314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
23094314557cSVivien Didelot 
23102b3e9891SVivien Didelot 	if (dsa_is_user_port(chip->ds, port))
23114314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_normal(chip, port);
23124314557cSVivien Didelot 
23134314557cSVivien Didelot 	/* Setup CPU port mode depending on its supported tag format */
23144314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA)
23154314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
23164314557cSVivien Didelot 
23174314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA)
23184314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_edsa(chip, port);
23194314557cSVivien Didelot 
23204314557cSVivien Didelot 	return -EINVAL;
23214314557cSVivien Didelot }
23224314557cSVivien Didelot 
2323ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
2324ea698f4fSVivien Didelot {
2325ea698f4fSVivien Didelot 	bool message = dsa_is_dsa_port(chip->ds, port);
2326ea698f4fSVivien Didelot 
2327ea698f4fSVivien Didelot 	return mv88e6xxx_port_set_message_port(chip, port, message);
2328ea698f4fSVivien Didelot }
2329ea698f4fSVivien Didelot 
2330601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
2331601aeed3SVivien Didelot {
23323ee50cbfSVivien Didelot 	struct dsa_switch *ds = chip->ds;
2333407308f6SDavid S. Miller 	bool flood;
2334601aeed3SVivien Didelot 
2335407308f6SDavid S. Miller 	/* Upstream ports flood frames with unknown unicast or multicast DA */
2336407308f6SDavid S. Miller 	flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port);
2337407308f6SDavid S. Miller 	if (chip->info->ops->port_set_egress_floods)
2338407308f6SDavid S. Miller 		return chip->info->ops->port_set_egress_floods(chip, port,
2339407308f6SDavid S. Miller 							       flood, flood);
2340407308f6SDavid S. Miller 
2341601aeed3SVivien Didelot 	return 0;
2342601aeed3SVivien Didelot }
2343601aeed3SVivien Didelot 
234445de77ffSVivien Didelot static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
234545de77ffSVivien Didelot {
234645de77ffSVivien Didelot 	struct mv88e6xxx_port *mvp = dev_id;
234745de77ffSVivien Didelot 	struct mv88e6xxx_chip *chip = mvp->chip;
234845de77ffSVivien Didelot 	irqreturn_t ret = IRQ_NONE;
234945de77ffSVivien Didelot 	int port = mvp->port;
235045de77ffSVivien Didelot 	u8 lane;
235145de77ffSVivien Didelot 
235245de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
235345de77ffSVivien Didelot 	lane = mv88e6xxx_serdes_get_lane(chip, port);
235445de77ffSVivien Didelot 	if (lane)
235545de77ffSVivien Didelot 		ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
235645de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
235745de77ffSVivien Didelot 
235845de77ffSVivien Didelot 	return ret;
235945de77ffSVivien Didelot }
236045de77ffSVivien Didelot 
236145de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
236245de77ffSVivien Didelot 					u8 lane)
236345de77ffSVivien Didelot {
236445de77ffSVivien Didelot 	struct mv88e6xxx_port *dev_id = &chip->ports[port];
236545de77ffSVivien Didelot 	unsigned int irq;
236645de77ffSVivien Didelot 	int err;
236745de77ffSVivien Didelot 
236845de77ffSVivien Didelot 	/* Nothing to request if this SERDES port has no IRQ */
236945de77ffSVivien Didelot 	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
237045de77ffSVivien Didelot 	if (!irq)
237145de77ffSVivien Didelot 		return 0;
237245de77ffSVivien Didelot 
2373e6f2f6b8SAndrew Lunn 	snprintf(dev_id->serdes_irq_name, sizeof(dev_id->serdes_irq_name),
2374e6f2f6b8SAndrew Lunn 		 "mv88e6xxx-%s-serdes-%d", dev_name(chip->dev), port);
2375e6f2f6b8SAndrew Lunn 
237645de77ffSVivien Didelot 	/* Requesting the IRQ will trigger IRQ callbacks, so release the lock */
237745de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
237845de77ffSVivien Didelot 	err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn,
2379e6f2f6b8SAndrew Lunn 				   IRQF_ONESHOT, dev_id->serdes_irq_name,
2380e6f2f6b8SAndrew Lunn 				   dev_id);
238145de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
238245de77ffSVivien Didelot 	if (err)
238345de77ffSVivien Didelot 		return err;
238445de77ffSVivien Didelot 
238545de77ffSVivien Didelot 	dev_id->serdes_irq = irq;
238645de77ffSVivien Didelot 
238745de77ffSVivien Didelot 	return mv88e6xxx_serdes_irq_enable(chip, port, lane);
238845de77ffSVivien Didelot }
238945de77ffSVivien Didelot 
239045de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
239145de77ffSVivien Didelot 				     u8 lane)
239245de77ffSVivien Didelot {
239345de77ffSVivien Didelot 	struct mv88e6xxx_port *dev_id = &chip->ports[port];
239445de77ffSVivien Didelot 	unsigned int irq = dev_id->serdes_irq;
239545de77ffSVivien Didelot 	int err;
239645de77ffSVivien Didelot 
239745de77ffSVivien Didelot 	/* Nothing to free if no IRQ has been requested */
239845de77ffSVivien Didelot 	if (!irq)
239945de77ffSVivien Didelot 		return 0;
240045de77ffSVivien Didelot 
240145de77ffSVivien Didelot 	err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
240245de77ffSVivien Didelot 
240345de77ffSVivien Didelot 	/* Freeing the IRQ will trigger IRQ callbacks, so release the lock */
240445de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
240545de77ffSVivien Didelot 	free_irq(irq, dev_id);
240645de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
240745de77ffSVivien Didelot 
240845de77ffSVivien Didelot 	dev_id->serdes_irq = 0;
240945de77ffSVivien Didelot 
241045de77ffSVivien Didelot 	return err;
241145de77ffSVivien Didelot }
241245de77ffSVivien Didelot 
24136d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
24146d91782fSAndrew Lunn 				  bool on)
24156d91782fSAndrew Lunn {
2416dc272f60SVivien Didelot 	u8 lane;
2417fc0bc019SVivien Didelot 	int err;
24186d91782fSAndrew Lunn 
2419dc272f60SVivien Didelot 	lane = mv88e6xxx_serdes_get_lane(chip, port);
2420dc272f60SVivien Didelot 	if (!lane)
2421523a8904SVivien Didelot 		return 0;
2422fc0bc019SVivien Didelot 
2423fc0bc019SVivien Didelot 	if (on) {
2424dc272f60SVivien Didelot 		err = mv88e6xxx_serdes_power_up(chip, port, lane);
2425fc0bc019SVivien Didelot 		if (err)
2426fc0bc019SVivien Didelot 			return err;
2427fc0bc019SVivien Didelot 
242845de77ffSVivien Didelot 		err = mv88e6xxx_serdes_irq_request(chip, port, lane);
2429fc0bc019SVivien Didelot 	} else {
243045de77ffSVivien Didelot 		err = mv88e6xxx_serdes_irq_free(chip, port, lane);
243145de77ffSVivien Didelot 		if (err)
243245de77ffSVivien Didelot 			return err;
2433fc0bc019SVivien Didelot 
2434dc272f60SVivien Didelot 		err = mv88e6xxx_serdes_power_down(chip, port, lane);
2435fc0bc019SVivien Didelot 	}
2436fc0bc019SVivien Didelot 
2437fc0bc019SVivien Didelot 	return err;
24386d91782fSAndrew Lunn }
24396d91782fSAndrew Lunn 
2440fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
2441fa371c80SVivien Didelot {
2442fa371c80SVivien Didelot 	struct dsa_switch *ds = chip->ds;
2443fa371c80SVivien Didelot 	int upstream_port;
2444fa371c80SVivien Didelot 	int err;
2445fa371c80SVivien Didelot 
244607073c79SVivien Didelot 	upstream_port = dsa_upstream_port(ds, port);
2447fa371c80SVivien Didelot 	if (chip->info->ops->port_set_upstream_port) {
2448fa371c80SVivien Didelot 		err = chip->info->ops->port_set_upstream_port(chip, port,
2449fa371c80SVivien Didelot 							      upstream_port);
2450fa371c80SVivien Didelot 		if (err)
2451fa371c80SVivien Didelot 			return err;
2452fa371c80SVivien Didelot 	}
2453fa371c80SVivien Didelot 
24540ea54ddaSVivien Didelot 	if (port == upstream_port) {
24550ea54ddaSVivien Didelot 		if (chip->info->ops->set_cpu_port) {
24560ea54ddaSVivien Didelot 			err = chip->info->ops->set_cpu_port(chip,
24570ea54ddaSVivien Didelot 							    upstream_port);
24580ea54ddaSVivien Didelot 			if (err)
24590ea54ddaSVivien Didelot 				return err;
24600ea54ddaSVivien Didelot 		}
24610ea54ddaSVivien Didelot 
24620ea54ddaSVivien Didelot 		if (chip->info->ops->set_egress_port) {
24630ea54ddaSVivien Didelot 			err = chip->info->ops->set_egress_port(chip,
24645c74c54cSIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS,
24655c74c54cSIwan R Timmer 						upstream_port);
24665c74c54cSIwan R Timmer 			if (err)
24675c74c54cSIwan R Timmer 				return err;
24685c74c54cSIwan R Timmer 
24695c74c54cSIwan R Timmer 			err = chip->info->ops->set_egress_port(chip,
24705c74c54cSIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS,
24710ea54ddaSVivien Didelot 						upstream_port);
24720ea54ddaSVivien Didelot 			if (err)
24730ea54ddaSVivien Didelot 				return err;
24740ea54ddaSVivien Didelot 		}
24750ea54ddaSVivien Didelot 	}
24760ea54ddaSVivien Didelot 
2477fa371c80SVivien Didelot 	return 0;
2478fa371c80SVivien Didelot }
2479fa371c80SVivien Didelot 
2480fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
2481fad09c73SVivien Didelot {
2482fad09c73SVivien Didelot 	struct dsa_switch *ds = chip->ds;
24830e7b9925SAndrew Lunn 	int err;
2484fad09c73SVivien Didelot 	u16 reg;
2485fad09c73SVivien Didelot 
24867b898469SAndrew Lunn 	chip->ports[port].chip = chip;
24877b898469SAndrew Lunn 	chip->ports[port].port = port;
24887b898469SAndrew Lunn 
2489d78343d2SVivien Didelot 	/* MAC Forcing register: don't force link, speed, duplex or flow control
2490d78343d2SVivien Didelot 	 * state to any particular values on physical ports, but force the CPU
2491d78343d2SVivien Didelot 	 * port and all DSA ports to their maximum bandwidth and full duplex.
2492fad09c73SVivien Didelot 	 */
2493d78343d2SVivien Didelot 	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
2494d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
2495d78343d2SVivien Didelot 					       SPEED_MAX, DUPLEX_FULL,
249654186b91SAndrew Lunn 					       PAUSE_OFF,
2497d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
2498fad09c73SVivien Didelot 	else
2499d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
2500d78343d2SVivien Didelot 					       SPEED_UNFORCED, DUPLEX_UNFORCED,
250154186b91SAndrew Lunn 					       PAUSE_ON,
2502d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
25030e7b9925SAndrew Lunn 	if (err)
25040e7b9925SAndrew Lunn 		return err;
2505fad09c73SVivien Didelot 
2506fad09c73SVivien Didelot 	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
2507fad09c73SVivien Didelot 	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
2508fad09c73SVivien Didelot 	 * tunneling, determine priority by looking at 802.1p and IP
2509fad09c73SVivien Didelot 	 * priority fields (IP prio has precedence), and set STP state
2510fad09c73SVivien Didelot 	 * to Forwarding.
2511fad09c73SVivien Didelot 	 *
2512fad09c73SVivien Didelot 	 * If this is the CPU link, use DSA or EDSA tagging depending
2513fad09c73SVivien Didelot 	 * on which tagging mode was configured.
2514fad09c73SVivien Didelot 	 *
2515fad09c73SVivien Didelot 	 * If this is a link to another switch, use DSA tagging mode.
2516fad09c73SVivien Didelot 	 *
2517fad09c73SVivien Didelot 	 * If this is the upstream port for this switch, enable
2518fad09c73SVivien Didelot 	 * forwarding of unknown unicasts and multicasts.
2519fad09c73SVivien Didelot 	 */
2520a89b433bSVivien Didelot 	reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP |
2521a89b433bSVivien Didelot 		MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
2522a89b433bSVivien Didelot 		MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
2523a89b433bSVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
25240e7b9925SAndrew Lunn 	if (err)
25250e7b9925SAndrew Lunn 		return err;
252656995cbcSAndrew Lunn 
2527601aeed3SVivien Didelot 	err = mv88e6xxx_setup_port_mode(chip, port);
252856995cbcSAndrew Lunn 	if (err)
252956995cbcSAndrew Lunn 		return err;
2530fad09c73SVivien Didelot 
2531601aeed3SVivien Didelot 	err = mv88e6xxx_setup_egress_floods(chip, port);
25324314557cSVivien Didelot 	if (err)
25334314557cSVivien Didelot 		return err;
25344314557cSVivien Didelot 
2535fad09c73SVivien Didelot 	/* Port Control 2: don't force a good FCS, set the maximum frame size to
2536fad09c73SVivien Didelot 	 * 10240 bytes, disable 802.1q tags checking, don't discard tagged or
2537fad09c73SVivien Didelot 	 * untagged frames on this port, do a destination address lookup on all
2538fad09c73SVivien Didelot 	 * received packets as usual, disable ARP mirroring and don't send a
2539fad09c73SVivien Didelot 	 * copy of all transmitted/received frames on this port to the CPU.
2540fad09c73SVivien Didelot 	 */
2541a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_map_da(chip, port);
2542a23b2961SAndrew Lunn 	if (err)
2543a23b2961SAndrew Lunn 		return err;
2544a23b2961SAndrew Lunn 
2545fa371c80SVivien Didelot 	err = mv88e6xxx_setup_upstream_port(chip, port);
25460e7b9925SAndrew Lunn 	if (err)
25470e7b9925SAndrew Lunn 		return err;
2548fad09c73SVivien Didelot 
2549a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_8021q_mode(chip, port,
255081c6edb2SVivien Didelot 				MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED);
2551a23b2961SAndrew Lunn 	if (err)
2552a23b2961SAndrew Lunn 		return err;
2553a23b2961SAndrew Lunn 
2554cd782656SVivien Didelot 	if (chip->info->ops->port_set_jumbo_size) {
2555cd782656SVivien Didelot 		err = chip->info->ops->port_set_jumbo_size(chip, port, 10240);
25565f436666SAndrew Lunn 		if (err)
25575f436666SAndrew Lunn 			return err;
25585f436666SAndrew Lunn 	}
25595f436666SAndrew Lunn 
2560fad09c73SVivien Didelot 	/* Port Association Vector: when learning source addresses
2561fad09c73SVivien Didelot 	 * of packets, add the address to the address database using
2562fad09c73SVivien Didelot 	 * a port bitmap that has only the bit for this port set and
2563fad09c73SVivien Didelot 	 * the other bits clear.
2564fad09c73SVivien Didelot 	 */
2565fad09c73SVivien Didelot 	reg = 1 << port;
2566fad09c73SVivien Didelot 	/* Disable learning for CPU port */
2567fad09c73SVivien Didelot 	if (dsa_is_cpu_port(ds, port))
2568fad09c73SVivien Didelot 		reg = 0;
2569fad09c73SVivien Didelot 
25702a4614e4SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
25712a4614e4SVivien Didelot 				   reg);
25720e7b9925SAndrew Lunn 	if (err)
25730e7b9925SAndrew Lunn 		return err;
2574fad09c73SVivien Didelot 
2575fad09c73SVivien Didelot 	/* Egress rate control 2: disable egress rate control. */
25762cb8cb14SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2,
25772cb8cb14SVivien Didelot 				   0x0000);
25780e7b9925SAndrew Lunn 	if (err)
25790e7b9925SAndrew Lunn 		return err;
2580fad09c73SVivien Didelot 
25810898432cSVivien Didelot 	if (chip->info->ops->port_pause_limit) {
25820898432cSVivien Didelot 		err = chip->info->ops->port_pause_limit(chip, port, 0, 0);
2583b35d322aSAndrew Lunn 		if (err)
2584b35d322aSAndrew Lunn 			return err;
2585b35d322aSAndrew Lunn 	}
2586b35d322aSAndrew Lunn 
2587c8c94891SVivien Didelot 	if (chip->info->ops->port_disable_learn_limit) {
2588c8c94891SVivien Didelot 		err = chip->info->ops->port_disable_learn_limit(chip, port);
2589c8c94891SVivien Didelot 		if (err)
2590c8c94891SVivien Didelot 			return err;
2591c8c94891SVivien Didelot 	}
2592c8c94891SVivien Didelot 
25939dbfb4e1SVivien Didelot 	if (chip->info->ops->port_disable_pri_override) {
25949dbfb4e1SVivien Didelot 		err = chip->info->ops->port_disable_pri_override(chip, port);
25950e7b9925SAndrew Lunn 		if (err)
25960e7b9925SAndrew Lunn 			return err;
2597ef0a7318SAndrew Lunn 	}
25982bbb33beSAndrew Lunn 
2599ef0a7318SAndrew Lunn 	if (chip->info->ops->port_tag_remap) {
2600ef0a7318SAndrew Lunn 		err = chip->info->ops->port_tag_remap(chip, port);
26010e7b9925SAndrew Lunn 		if (err)
26020e7b9925SAndrew Lunn 			return err;
2603fad09c73SVivien Didelot 	}
2604fad09c73SVivien Didelot 
2605ef70b111SAndrew Lunn 	if (chip->info->ops->port_egress_rate_limiting) {
2606ef70b111SAndrew Lunn 		err = chip->info->ops->port_egress_rate_limiting(chip, port);
26070e7b9925SAndrew Lunn 		if (err)
26080e7b9925SAndrew Lunn 			return err;
2609fad09c73SVivien Didelot 	}
2610fad09c73SVivien Didelot 
2611121b8fe2SHubert Feurstein 	if (chip->info->ops->port_setup_message_port) {
2612121b8fe2SHubert Feurstein 		err = chip->info->ops->port_setup_message_port(chip, port);
26130e7b9925SAndrew Lunn 		if (err)
26140e7b9925SAndrew Lunn 			return err;
2615121b8fe2SHubert Feurstein 	}
2616fad09c73SVivien Didelot 
2617fad09c73SVivien Didelot 	/* Port based VLAN map: give each port the same default address
2618fad09c73SVivien Didelot 	 * database, and allow bidirectional communication between the
2619fad09c73SVivien Didelot 	 * CPU and DSA port(s), and the other ports.
2620fad09c73SVivien Didelot 	 */
2621b4e48c50SVivien Didelot 	err = mv88e6xxx_port_set_fid(chip, port, 0);
26220e7b9925SAndrew Lunn 	if (err)
26230e7b9925SAndrew Lunn 		return err;
2624fad09c73SVivien Didelot 
2625240ea3efSVivien Didelot 	err = mv88e6xxx_port_vlan_map(chip, port);
26260e7b9925SAndrew Lunn 	if (err)
26270e7b9925SAndrew Lunn 		return err;
2628fad09c73SVivien Didelot 
2629fad09c73SVivien Didelot 	/* Default VLAN ID and priority: don't set a default VLAN
2630fad09c73SVivien Didelot 	 * ID, and set the default packet priority to zero.
2631fad09c73SVivien Didelot 	 */
2632b7929fb3SVivien Didelot 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0);
2633fad09c73SVivien Didelot }
2634fad09c73SVivien Didelot 
263504aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
263604aca993SAndrew Lunn 				 struct phy_device *phydev)
263704aca993SAndrew Lunn {
263804aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
2639523a8904SVivien Didelot 	int err;
264004aca993SAndrew Lunn 
2641c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2642523a8904SVivien Didelot 	err = mv88e6xxx_serdes_power(chip, port, true);
2643c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
264404aca993SAndrew Lunn 
264504aca993SAndrew Lunn 	return err;
264604aca993SAndrew Lunn }
264704aca993SAndrew Lunn 
264875104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
264904aca993SAndrew Lunn {
265004aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
265104aca993SAndrew Lunn 
2652c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2653523a8904SVivien Didelot 	if (mv88e6xxx_serdes_power(chip, port, false))
2654523a8904SVivien Didelot 		dev_err(chip->dev, "failed to power off SERDES\n");
2655c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
265604aca993SAndrew Lunn }
265704aca993SAndrew Lunn 
26582cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
26592cfcd964SVivien Didelot 				     unsigned int ageing_time)
26602cfcd964SVivien Didelot {
266104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
26622cfcd964SVivien Didelot 	int err;
26632cfcd964SVivien Didelot 
2664c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2665720c6343SVivien Didelot 	err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
2666c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
26672cfcd964SVivien Didelot 
26682cfcd964SVivien Didelot 	return err;
26692cfcd964SVivien Didelot }
26702cfcd964SVivien Didelot 
2671447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
2672fad09c73SVivien Didelot {
2673fad09c73SVivien Didelot 	int err;
2674fad09c73SVivien Didelot 
2675de227387SAndrew Lunn 	/* Initialize the statistics unit */
2676447b1bb8SVivien Didelot 	if (chip->info->ops->stats_set_histogram) {
2677447b1bb8SVivien Didelot 		err = chip->info->ops->stats_set_histogram(chip);
2678de227387SAndrew Lunn 		if (err)
2679de227387SAndrew Lunn 			return err;
2680447b1bb8SVivien Didelot 	}
2681de227387SAndrew Lunn 
268240cff8fcSAndrew Lunn 	return mv88e6xxx_g1_stats_clear(chip);
26839729934cSVivien Didelot }
26849729934cSVivien Didelot 
2685ea89098eSAndrew Lunn /* Check if the errata has already been applied. */
2686ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
2687ea89098eSAndrew Lunn {
2688ea89098eSAndrew Lunn 	int port;
2689ea89098eSAndrew Lunn 	int err;
2690ea89098eSAndrew Lunn 	u16 val;
2691ea89098eSAndrew Lunn 
2692ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
269360907013SMarek Behún 		err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val);
2694ea89098eSAndrew Lunn 		if (err) {
2695ea89098eSAndrew Lunn 			dev_err(chip->dev,
2696ea89098eSAndrew Lunn 				"Error reading hidden register: %d\n", err);
2697ea89098eSAndrew Lunn 			return false;
2698ea89098eSAndrew Lunn 		}
2699ea89098eSAndrew Lunn 		if (val != 0x01c0)
2700ea89098eSAndrew Lunn 			return false;
2701ea89098eSAndrew Lunn 	}
2702ea89098eSAndrew Lunn 
2703ea89098eSAndrew Lunn 	return true;
2704ea89098eSAndrew Lunn }
2705ea89098eSAndrew Lunn 
2706ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic
2707ea89098eSAndrew Lunn  * values into undocumented hidden registers and then performing a
2708ea89098eSAndrew Lunn  * software reset.
2709ea89098eSAndrew Lunn  */
2710ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
2711ea89098eSAndrew Lunn {
2712ea89098eSAndrew Lunn 	int port;
2713ea89098eSAndrew Lunn 	int err;
2714ea89098eSAndrew Lunn 
2715ea89098eSAndrew Lunn 	if (mv88e6390_setup_errata_applied(chip))
2716ea89098eSAndrew Lunn 		return 0;
2717ea89098eSAndrew Lunn 
2718ea89098eSAndrew Lunn 	/* Set the ports into blocking mode */
2719ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
2720ea89098eSAndrew Lunn 		err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED);
2721ea89098eSAndrew Lunn 		if (err)
2722ea89098eSAndrew Lunn 			return err;
2723ea89098eSAndrew Lunn 	}
2724ea89098eSAndrew Lunn 
2725ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
272660907013SMarek Behún 		err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0);
2727ea89098eSAndrew Lunn 		if (err)
2728ea89098eSAndrew Lunn 			return err;
2729ea89098eSAndrew Lunn 	}
2730ea89098eSAndrew Lunn 
2731ea89098eSAndrew Lunn 	return mv88e6xxx_software_reset(chip);
2732ea89098eSAndrew Lunn }
2733ea89098eSAndrew Lunn 
273423e8b470SAndrew Lunn enum mv88e6xxx_devlink_param_id {
273523e8b470SAndrew Lunn 	MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
273623e8b470SAndrew Lunn 	MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
273723e8b470SAndrew Lunn };
273823e8b470SAndrew Lunn 
273923e8b470SAndrew Lunn static int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id,
274023e8b470SAndrew Lunn 				       struct devlink_param_gset_ctx *ctx)
274123e8b470SAndrew Lunn {
274223e8b470SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
274323e8b470SAndrew Lunn 	int err;
274423e8b470SAndrew Lunn 
274523e8b470SAndrew Lunn 	mv88e6xxx_reg_lock(chip);
274623e8b470SAndrew Lunn 
274723e8b470SAndrew Lunn 	switch (id) {
274823e8b470SAndrew Lunn 	case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
274923e8b470SAndrew Lunn 		err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8);
275023e8b470SAndrew Lunn 		break;
275123e8b470SAndrew Lunn 	default:
275223e8b470SAndrew Lunn 		err = -EOPNOTSUPP;
275323e8b470SAndrew Lunn 		break;
275423e8b470SAndrew Lunn 	}
275523e8b470SAndrew Lunn 
275623e8b470SAndrew Lunn 	mv88e6xxx_reg_unlock(chip);
275723e8b470SAndrew Lunn 
275823e8b470SAndrew Lunn 	return err;
275923e8b470SAndrew Lunn }
276023e8b470SAndrew Lunn 
276123e8b470SAndrew Lunn static int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id,
276223e8b470SAndrew Lunn 				       struct devlink_param_gset_ctx *ctx)
276323e8b470SAndrew Lunn {
276423e8b470SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
276523e8b470SAndrew Lunn 	int err;
276623e8b470SAndrew Lunn 
276723e8b470SAndrew Lunn 	mv88e6xxx_reg_lock(chip);
276823e8b470SAndrew Lunn 
276923e8b470SAndrew Lunn 	switch (id) {
277023e8b470SAndrew Lunn 	case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
277123e8b470SAndrew Lunn 		err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8);
277223e8b470SAndrew Lunn 		break;
277323e8b470SAndrew Lunn 	default:
277423e8b470SAndrew Lunn 		err = -EOPNOTSUPP;
277523e8b470SAndrew Lunn 		break;
277623e8b470SAndrew Lunn 	}
277723e8b470SAndrew Lunn 
277823e8b470SAndrew Lunn 	mv88e6xxx_reg_unlock(chip);
277923e8b470SAndrew Lunn 
278023e8b470SAndrew Lunn 	return err;
278123e8b470SAndrew Lunn }
278223e8b470SAndrew Lunn 
278323e8b470SAndrew Lunn static const struct devlink_param mv88e6xxx_devlink_params[] = {
278423e8b470SAndrew Lunn 	DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
278523e8b470SAndrew Lunn 				 "ATU_hash", DEVLINK_PARAM_TYPE_U8,
278623e8b470SAndrew Lunn 				 BIT(DEVLINK_PARAM_CMODE_RUNTIME)),
278723e8b470SAndrew Lunn };
278823e8b470SAndrew Lunn 
278923e8b470SAndrew Lunn static int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds)
279023e8b470SAndrew Lunn {
279123e8b470SAndrew Lunn 	return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params,
279223e8b470SAndrew Lunn 					   ARRAY_SIZE(mv88e6xxx_devlink_params));
279323e8b470SAndrew Lunn }
279423e8b470SAndrew Lunn 
279523e8b470SAndrew Lunn static void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds)
279623e8b470SAndrew Lunn {
279723e8b470SAndrew Lunn 	dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params,
279823e8b470SAndrew Lunn 				      ARRAY_SIZE(mv88e6xxx_devlink_params));
279923e8b470SAndrew Lunn }
280023e8b470SAndrew Lunn 
2801e0c69ca7SAndrew Lunn enum mv88e6xxx_devlink_resource_id {
2802e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU,
2803e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
2804e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
2805e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
2806e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
2807e0c69ca7SAndrew Lunn };
2808e0c69ca7SAndrew Lunn 
2809e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip,
2810e0c69ca7SAndrew Lunn 					 u16 bin)
2811e0c69ca7SAndrew Lunn {
2812e0c69ca7SAndrew Lunn 	u16 occupancy = 0;
2813e0c69ca7SAndrew Lunn 	int err;
2814e0c69ca7SAndrew Lunn 
2815e0c69ca7SAndrew Lunn 	mv88e6xxx_reg_lock(chip);
2816e0c69ca7SAndrew Lunn 
2817e0c69ca7SAndrew Lunn 	err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL,
2818e0c69ca7SAndrew Lunn 					 bin);
2819e0c69ca7SAndrew Lunn 	if (err) {
2820e0c69ca7SAndrew Lunn 		dev_err(chip->dev, "failed to set ATU stats kind/bin\n");
2821e0c69ca7SAndrew Lunn 		goto unlock;
2822e0c69ca7SAndrew Lunn 	}
2823e0c69ca7SAndrew Lunn 
2824e0c69ca7SAndrew Lunn 	err = mv88e6xxx_g1_atu_get_next(chip, 0);
2825e0c69ca7SAndrew Lunn 	if (err) {
2826e0c69ca7SAndrew Lunn 		dev_err(chip->dev, "failed to perform ATU get next\n");
2827e0c69ca7SAndrew Lunn 		goto unlock;
2828e0c69ca7SAndrew Lunn 	}
2829e0c69ca7SAndrew Lunn 
2830e0c69ca7SAndrew Lunn 	err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy);
2831e0c69ca7SAndrew Lunn 	if (err) {
2832e0c69ca7SAndrew Lunn 		dev_err(chip->dev, "failed to get ATU stats\n");
2833e0c69ca7SAndrew Lunn 		goto unlock;
2834e0c69ca7SAndrew Lunn 	}
2835e0c69ca7SAndrew Lunn 
2836012fc745SAndrew Lunn 	occupancy &= MV88E6XXX_G2_ATU_STATS_MASK;
2837012fc745SAndrew Lunn 
2838e0c69ca7SAndrew Lunn unlock:
2839e0c69ca7SAndrew Lunn 	mv88e6xxx_reg_unlock(chip);
2840e0c69ca7SAndrew Lunn 
2841e0c69ca7SAndrew Lunn 	return occupancy;
2842e0c69ca7SAndrew Lunn }
2843e0c69ca7SAndrew Lunn 
2844e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv)
2845e0c69ca7SAndrew Lunn {
2846e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = priv;
2847e0c69ca7SAndrew Lunn 
2848e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_get(chip,
2849e0c69ca7SAndrew Lunn 					     MV88E6XXX_G2_ATU_STATS_BIN_0);
2850e0c69ca7SAndrew Lunn }
2851e0c69ca7SAndrew Lunn 
2852e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv)
2853e0c69ca7SAndrew Lunn {
2854e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = priv;
2855e0c69ca7SAndrew Lunn 
2856e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_get(chip,
2857e0c69ca7SAndrew Lunn 					     MV88E6XXX_G2_ATU_STATS_BIN_1);
2858e0c69ca7SAndrew Lunn }
2859e0c69ca7SAndrew Lunn 
2860e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv)
2861e0c69ca7SAndrew Lunn {
2862e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = priv;
2863e0c69ca7SAndrew Lunn 
2864e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_get(chip,
2865e0c69ca7SAndrew Lunn 					     MV88E6XXX_G2_ATU_STATS_BIN_2);
2866e0c69ca7SAndrew Lunn }
2867e0c69ca7SAndrew Lunn 
2868e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv)
2869e0c69ca7SAndrew Lunn {
2870e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = priv;
2871e0c69ca7SAndrew Lunn 
2872e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_get(chip,
2873e0c69ca7SAndrew Lunn 					     MV88E6XXX_G2_ATU_STATS_BIN_3);
2874e0c69ca7SAndrew Lunn }
2875e0c69ca7SAndrew Lunn 
2876e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_get(void *priv)
2877e0c69ca7SAndrew Lunn {
2878e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_0_get(priv) +
2879e0c69ca7SAndrew Lunn 		mv88e6xxx_devlink_atu_bin_1_get(priv) +
2880e0c69ca7SAndrew Lunn 		mv88e6xxx_devlink_atu_bin_2_get(priv) +
2881e0c69ca7SAndrew Lunn 		mv88e6xxx_devlink_atu_bin_3_get(priv);
2882e0c69ca7SAndrew Lunn }
2883e0c69ca7SAndrew Lunn 
2884e0c69ca7SAndrew Lunn static int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds)
2885e0c69ca7SAndrew Lunn {
2886e0c69ca7SAndrew Lunn 	struct devlink_resource_size_params size_params;
2887e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
2888e0c69ca7SAndrew Lunn 	int err;
2889e0c69ca7SAndrew Lunn 
2890e0c69ca7SAndrew Lunn 	devlink_resource_size_params_init(&size_params,
2891e0c69ca7SAndrew Lunn 					  mv88e6xxx_num_macs(chip),
2892e0c69ca7SAndrew Lunn 					  mv88e6xxx_num_macs(chip),
2893e0c69ca7SAndrew Lunn 					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
2894e0c69ca7SAndrew Lunn 
2895e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU",
2896e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip),
2897e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2898e0c69ca7SAndrew Lunn 					    DEVLINK_RESOURCE_ID_PARENT_TOP,
2899e0c69ca7SAndrew Lunn 					    &size_params);
2900e0c69ca7SAndrew Lunn 	if (err)
2901e0c69ca7SAndrew Lunn 		goto out;
2902e0c69ca7SAndrew Lunn 
2903e0c69ca7SAndrew Lunn 	devlink_resource_size_params_init(&size_params,
2904e0c69ca7SAndrew Lunn 					  mv88e6xxx_num_macs(chip) / 4,
2905e0c69ca7SAndrew Lunn 					  mv88e6xxx_num_macs(chip) / 4,
2906e0c69ca7SAndrew Lunn 					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
2907e0c69ca7SAndrew Lunn 
2908e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU_bin_0",
2909e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip) / 4,
2910e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
2911e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2912e0c69ca7SAndrew Lunn 					    &size_params);
2913e0c69ca7SAndrew Lunn 	if (err)
2914e0c69ca7SAndrew Lunn 		goto out;
2915e0c69ca7SAndrew Lunn 
2916e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU_bin_1",
2917e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip) / 4,
2918e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
2919e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2920e0c69ca7SAndrew Lunn 					    &size_params);
2921e0c69ca7SAndrew Lunn 	if (err)
2922e0c69ca7SAndrew Lunn 		goto out;
2923e0c69ca7SAndrew Lunn 
2924e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU_bin_2",
2925e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip) / 4,
2926e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
2927e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2928e0c69ca7SAndrew Lunn 					    &size_params);
2929e0c69ca7SAndrew Lunn 	if (err)
2930e0c69ca7SAndrew Lunn 		goto out;
2931e0c69ca7SAndrew Lunn 
2932e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU_bin_3",
2933e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip) / 4,
2934e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
2935e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2936e0c69ca7SAndrew Lunn 					    &size_params);
2937e0c69ca7SAndrew Lunn 	if (err)
2938e0c69ca7SAndrew Lunn 		goto out;
2939e0c69ca7SAndrew Lunn 
2940e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
2941e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU,
2942e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_get,
2943e0c69ca7SAndrew Lunn 					      chip);
2944e0c69ca7SAndrew Lunn 
2945e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
2946e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
2947e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_bin_0_get,
2948e0c69ca7SAndrew Lunn 					      chip);
2949e0c69ca7SAndrew Lunn 
2950e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
2951e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
2952e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_bin_1_get,
2953e0c69ca7SAndrew Lunn 					      chip);
2954e0c69ca7SAndrew Lunn 
2955e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
2956e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
2957e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_bin_2_get,
2958e0c69ca7SAndrew Lunn 					      chip);
2959e0c69ca7SAndrew Lunn 
2960e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
2961e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
2962e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_bin_3_get,
2963e0c69ca7SAndrew Lunn 					      chip);
2964e0c69ca7SAndrew Lunn 
2965e0c69ca7SAndrew Lunn 	return 0;
2966e0c69ca7SAndrew Lunn 
2967e0c69ca7SAndrew Lunn out:
2968e0c69ca7SAndrew Lunn 	dsa_devlink_resources_unregister(ds);
2969e0c69ca7SAndrew Lunn 	return err;
2970e0c69ca7SAndrew Lunn }
2971e0c69ca7SAndrew Lunn 
297223e8b470SAndrew Lunn static void mv88e6xxx_teardown(struct dsa_switch *ds)
297323e8b470SAndrew Lunn {
297423e8b470SAndrew Lunn 	mv88e6xxx_teardown_devlink_params(ds);
2975e0c69ca7SAndrew Lunn 	dsa_devlink_resources_unregister(ds);
297623e8b470SAndrew Lunn }
297723e8b470SAndrew Lunn 
2978fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds)
2979fad09c73SVivien Didelot {
298004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
29812d2e1dd2SAndrew Lunn 	u8 cmode;
2982fad09c73SVivien Didelot 	int err;
2983fad09c73SVivien Didelot 	int i;
2984fad09c73SVivien Didelot 
2985fad09c73SVivien Didelot 	chip->ds = ds;
2986a3c53be5SAndrew Lunn 	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
2987fad09c73SVivien Didelot 
2988c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2989fad09c73SVivien Didelot 
2990ea89098eSAndrew Lunn 	if (chip->info->ops->setup_errata) {
2991ea89098eSAndrew Lunn 		err = chip->info->ops->setup_errata(chip);
2992ea89098eSAndrew Lunn 		if (err)
2993ea89098eSAndrew Lunn 			goto unlock;
2994ea89098eSAndrew Lunn 	}
2995ea89098eSAndrew Lunn 
29962d2e1dd2SAndrew Lunn 	/* Cache the cmode of each port. */
29972d2e1dd2SAndrew Lunn 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
29982d2e1dd2SAndrew Lunn 		if (chip->info->ops->port_get_cmode) {
29992d2e1dd2SAndrew Lunn 			err = chip->info->ops->port_get_cmode(chip, i, &cmode);
30002d2e1dd2SAndrew Lunn 			if (err)
3001e29129fcSDan Carpenter 				goto unlock;
30022d2e1dd2SAndrew Lunn 
30032d2e1dd2SAndrew Lunn 			chip->ports[i].cmode = cmode;
30042d2e1dd2SAndrew Lunn 		}
30052d2e1dd2SAndrew Lunn 	}
30062d2e1dd2SAndrew Lunn 
30079729934cSVivien Didelot 	/* Setup Switch Port Registers */
3008370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
3009b759f528SVivien Didelot 		if (dsa_is_unused_port(ds, i))
3010b759f528SVivien Didelot 			continue;
3011b759f528SVivien Didelot 
3012c857486aSHubert Feurstein 		/* Prevent the use of an invalid port. */
3013b759f528SVivien Didelot 		if (mv88e6xxx_is_invalid_port(chip, i)) {
3014c857486aSHubert Feurstein 			dev_err(chip->dev, "port %d is invalid\n", i);
3015c857486aSHubert Feurstein 			err = -EINVAL;
3016c857486aSHubert Feurstein 			goto unlock;
3017c857486aSHubert Feurstein 		}
3018c857486aSHubert Feurstein 
30199729934cSVivien Didelot 		err = mv88e6xxx_setup_port(chip, i);
30209729934cSVivien Didelot 		if (err)
30219729934cSVivien Didelot 			goto unlock;
30229729934cSVivien Didelot 	}
30239729934cSVivien Didelot 
3024cd8da8bbSVivien Didelot 	err = mv88e6xxx_irl_setup(chip);
3025cd8da8bbSVivien Didelot 	if (err)
3026cd8da8bbSVivien Didelot 		goto unlock;
3027cd8da8bbSVivien Didelot 
302804a69a17SVivien Didelot 	err = mv88e6xxx_mac_setup(chip);
302904a69a17SVivien Didelot 	if (err)
303004a69a17SVivien Didelot 		goto unlock;
303104a69a17SVivien Didelot 
30321b17aedfSVivien Didelot 	err = mv88e6xxx_phy_setup(chip);
30331b17aedfSVivien Didelot 	if (err)
30341b17aedfSVivien Didelot 		goto unlock;
30351b17aedfSVivien Didelot 
3036b486d7c9SVivien Didelot 	err = mv88e6xxx_vtu_setup(chip);
3037b486d7c9SVivien Didelot 	if (err)
3038b486d7c9SVivien Didelot 		goto unlock;
3039b486d7c9SVivien Didelot 
304081228996SVivien Didelot 	err = mv88e6xxx_pvt_setup(chip);
304181228996SVivien Didelot 	if (err)
304281228996SVivien Didelot 		goto unlock;
304381228996SVivien Didelot 
3044a2ac29d2SVivien Didelot 	err = mv88e6xxx_atu_setup(chip);
3045a2ac29d2SVivien Didelot 	if (err)
3046a2ac29d2SVivien Didelot 		goto unlock;
3047a2ac29d2SVivien Didelot 
304887fa886eSAndrew Lunn 	err = mv88e6xxx_broadcast_setup(chip, 0);
304987fa886eSAndrew Lunn 	if (err)
305087fa886eSAndrew Lunn 		goto unlock;
305187fa886eSAndrew Lunn 
30529e907d73SVivien Didelot 	err = mv88e6xxx_pot_setup(chip);
30539e907d73SVivien Didelot 	if (err)
30549e907d73SVivien Didelot 		goto unlock;
30559e907d73SVivien Didelot 
30569e5baf9bSVivien Didelot 	err = mv88e6xxx_rmu_setup(chip);
30579e5baf9bSVivien Didelot 	if (err)
30589e5baf9bSVivien Didelot 		goto unlock;
30599e5baf9bSVivien Didelot 
306051c901a7SVivien Didelot 	err = mv88e6xxx_rsvd2cpu_setup(chip);
30616e55f698SAndrew Lunn 	if (err)
30626e55f698SAndrew Lunn 		goto unlock;
30636e55f698SAndrew Lunn 
3064b28f872dSVivien Didelot 	err = mv88e6xxx_trunk_setup(chip);
3065b28f872dSVivien Didelot 	if (err)
3066b28f872dSVivien Didelot 		goto unlock;
3067b28f872dSVivien Didelot 
3068c7f047b6SVivien Didelot 	err = mv88e6xxx_devmap_setup(chip);
3069c7f047b6SVivien Didelot 	if (err)
3070c7f047b6SVivien Didelot 		goto unlock;
3071c7f047b6SVivien Didelot 
307293e18d61SVivien Didelot 	err = mv88e6xxx_pri_setup(chip);
307393e18d61SVivien Didelot 	if (err)
307493e18d61SVivien Didelot 		goto unlock;
307593e18d61SVivien Didelot 
3076c6fe0ad2SBrandon Streiff 	/* Setup PTP Hardware Clock and timestamping */
30772fa8d3afSBrandon Streiff 	if (chip->info->ptp_support) {
30782fa8d3afSBrandon Streiff 		err = mv88e6xxx_ptp_setup(chip);
30792fa8d3afSBrandon Streiff 		if (err)
30802fa8d3afSBrandon Streiff 			goto unlock;
3081c6fe0ad2SBrandon Streiff 
3082c6fe0ad2SBrandon Streiff 		err = mv88e6xxx_hwtstamp_setup(chip);
3083c6fe0ad2SBrandon Streiff 		if (err)
3084c6fe0ad2SBrandon Streiff 			goto unlock;
30852fa8d3afSBrandon Streiff 	}
30862fa8d3afSBrandon Streiff 
3087447b1bb8SVivien Didelot 	err = mv88e6xxx_stats_setup(chip);
3088447b1bb8SVivien Didelot 	if (err)
3089447b1bb8SVivien Didelot 		goto unlock;
3090447b1bb8SVivien Didelot 
3091fad09c73SVivien Didelot unlock:
3092c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3093fad09c73SVivien Didelot 
3094e0c69ca7SAndrew Lunn 	if (err)
3095e0c69ca7SAndrew Lunn 		return err;
3096e0c69ca7SAndrew Lunn 
3097e0c69ca7SAndrew Lunn 	/* Have to be called without holding the register lock, since
3098e0c69ca7SAndrew Lunn 	 * they take the devlink lock, and we later take the locks in
3099e0c69ca7SAndrew Lunn 	 * the reverse order when getting/setting parameters or
3100e0c69ca7SAndrew Lunn 	 * resource occupancy.
310123e8b470SAndrew Lunn 	 */
3102e0c69ca7SAndrew Lunn 	err = mv88e6xxx_setup_devlink_resources(ds);
3103e0c69ca7SAndrew Lunn 	if (err)
3104e0c69ca7SAndrew Lunn 		return err;
3105e0c69ca7SAndrew Lunn 
3106e0c69ca7SAndrew Lunn 	err = mv88e6xxx_setup_devlink_params(ds);
3107e0c69ca7SAndrew Lunn 	if (err)
3108e0c69ca7SAndrew Lunn 		dsa_devlink_resources_unregister(ds);
3109e0c69ca7SAndrew Lunn 
3110e0c69ca7SAndrew Lunn 	return err;
3111fad09c73SVivien Didelot }
3112fad09c73SVivien Didelot 
3113e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
3114fad09c73SVivien Didelot {
31150dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
31160dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
3117e57e5e77SVivien Didelot 	u16 val;
3118e57e5e77SVivien Didelot 	int err;
3119fad09c73SVivien Didelot 
3120ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_read)
3121ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
3122ee26a228SAndrew Lunn 
3123c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3124ee26a228SAndrew Lunn 	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
3125c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3126e57e5e77SVivien Didelot 
3127da9f3301SAndrew Lunn 	if (reg == MII_PHYSID2) {
3128ddc49acbSAndrew Lunn 		/* Some internal PHYs don't have a model number. */
3129ddc49acbSAndrew Lunn 		if (chip->info->family != MV88E6XXX_FAMILY_6165)
3130ddc49acbSAndrew Lunn 			/* Then there is the 6165 family. It gets is
3131ddc49acbSAndrew Lunn 			 * PHYs correct. But it can also have two
3132ddc49acbSAndrew Lunn 			 * SERDES interfaces in the PHY address
3133ddc49acbSAndrew Lunn 			 * space. And these don't have a model
3134ddc49acbSAndrew Lunn 			 * number. But they are not PHYs, so we don't
3135ddc49acbSAndrew Lunn 			 * want to give them something a PHY driver
3136ddc49acbSAndrew Lunn 			 * will recognise.
3137ddc49acbSAndrew Lunn 			 *
3138ddc49acbSAndrew Lunn 			 * Use the mv88e6390 family model number
3139ddc49acbSAndrew Lunn 			 * instead, for anything which really could be
3140ddc49acbSAndrew Lunn 			 * a PHY,
3141da9f3301SAndrew Lunn 			 */
3142da9f3301SAndrew Lunn 			if (!(val & 0x3f0))
3143107fcc10SVivien Didelot 				val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4;
3144da9f3301SAndrew Lunn 	}
3145da9f3301SAndrew Lunn 
3146e57e5e77SVivien Didelot 	return err ? err : val;
3147fad09c73SVivien Didelot }
3148fad09c73SVivien Didelot 
3149e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
3150fad09c73SVivien Didelot {
31510dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
31520dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
3153e57e5e77SVivien Didelot 	int err;
3154fad09c73SVivien Didelot 
3155ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_write)
3156ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
3157ee26a228SAndrew Lunn 
3158c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3159ee26a228SAndrew Lunn 	err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
3160c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3161e57e5e77SVivien Didelot 
3162e57e5e77SVivien Didelot 	return err;
3163fad09c73SVivien Didelot }
3164fad09c73SVivien Didelot 
3165fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
3166a3c53be5SAndrew Lunn 				   struct device_node *np,
3167a3c53be5SAndrew Lunn 				   bool external)
3168fad09c73SVivien Didelot {
3169fad09c73SVivien Didelot 	static int index;
31700dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
3171fad09c73SVivien Didelot 	struct mii_bus *bus;
3172fad09c73SVivien Didelot 	int err;
3173fad09c73SVivien Didelot 
31742510babcSAndrew Lunn 	if (external) {
3175c9acece0SRasmus Villemoes 		mv88e6xxx_reg_lock(chip);
31762510babcSAndrew Lunn 		err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
3177c9acece0SRasmus Villemoes 		mv88e6xxx_reg_unlock(chip);
31782510babcSAndrew Lunn 
31792510babcSAndrew Lunn 		if (err)
31802510babcSAndrew Lunn 			return err;
31812510babcSAndrew Lunn 	}
31822510babcSAndrew Lunn 
31830dd12d54SAndrew Lunn 	bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
3184fad09c73SVivien Didelot 	if (!bus)
3185fad09c73SVivien Didelot 		return -ENOMEM;
3186fad09c73SVivien Didelot 
31870dd12d54SAndrew Lunn 	mdio_bus = bus->priv;
3188a3c53be5SAndrew Lunn 	mdio_bus->bus = bus;
31890dd12d54SAndrew Lunn 	mdio_bus->chip = chip;
3190a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&mdio_bus->list);
3191a3c53be5SAndrew Lunn 	mdio_bus->external = external;
31920dd12d54SAndrew Lunn 
3193fad09c73SVivien Didelot 	if (np) {
3194fad09c73SVivien Didelot 		bus->name = np->full_name;
3195f7ce9103SRob Herring 		snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np);
3196fad09c73SVivien Didelot 	} else {
3197fad09c73SVivien Didelot 		bus->name = "mv88e6xxx SMI";
3198fad09c73SVivien Didelot 		snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
3199fad09c73SVivien Didelot 	}
3200fad09c73SVivien Didelot 
3201fad09c73SVivien Didelot 	bus->read = mv88e6xxx_mdio_read;
3202fad09c73SVivien Didelot 	bus->write = mv88e6xxx_mdio_write;
3203fad09c73SVivien Didelot 	bus->parent = chip->dev;
3204fad09c73SVivien Didelot 
32056f88284fSAndrew Lunn 	if (!external) {
32066f88284fSAndrew Lunn 		err = mv88e6xxx_g2_irq_mdio_setup(chip, bus);
32076f88284fSAndrew Lunn 		if (err)
32086f88284fSAndrew Lunn 			return err;
32096f88284fSAndrew Lunn 	}
32106f88284fSAndrew Lunn 
3211a3c53be5SAndrew Lunn 	err = of_mdiobus_register(bus, np);
3212fad09c73SVivien Didelot 	if (err) {
3213fad09c73SVivien Didelot 		dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
32146f88284fSAndrew Lunn 		mv88e6xxx_g2_irq_mdio_free(chip, bus);
3215fad09c73SVivien Didelot 		return err;
3216fad09c73SVivien Didelot 	}
3217fad09c73SVivien Didelot 
3218a3c53be5SAndrew Lunn 	if (external)
3219a3c53be5SAndrew Lunn 		list_add_tail(&mdio_bus->list, &chip->mdios);
3220a3c53be5SAndrew Lunn 	else
3221a3c53be5SAndrew Lunn 		list_add(&mdio_bus->list, &chip->mdios);
3222a3c53be5SAndrew Lunn 
3223a3c53be5SAndrew Lunn 	return 0;
3224a3c53be5SAndrew Lunn }
3225a3c53be5SAndrew Lunn 
3226a3c53be5SAndrew Lunn static const struct of_device_id mv88e6xxx_mdio_external_match[] = {
3227a3c53be5SAndrew Lunn 	{ .compatible = "marvell,mv88e6xxx-mdio-external",
3228a3c53be5SAndrew Lunn 	  .data = (void *)true },
3229a3c53be5SAndrew Lunn 	{ },
3230a3c53be5SAndrew Lunn };
3231a3c53be5SAndrew Lunn 
32323126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
32333126aeecSAndrew Lunn 
32343126aeecSAndrew Lunn {
32353126aeecSAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
32363126aeecSAndrew Lunn 	struct mii_bus *bus;
32373126aeecSAndrew Lunn 
32383126aeecSAndrew Lunn 	list_for_each_entry(mdio_bus, &chip->mdios, list) {
32393126aeecSAndrew Lunn 		bus = mdio_bus->bus;
32403126aeecSAndrew Lunn 
32416f88284fSAndrew Lunn 		if (!mdio_bus->external)
32426f88284fSAndrew Lunn 			mv88e6xxx_g2_irq_mdio_free(chip, bus);
32436f88284fSAndrew Lunn 
32443126aeecSAndrew Lunn 		mdiobus_unregister(bus);
32453126aeecSAndrew Lunn 	}
32463126aeecSAndrew Lunn }
32473126aeecSAndrew Lunn 
3248a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
3249a3c53be5SAndrew Lunn 				    struct device_node *np)
3250a3c53be5SAndrew Lunn {
3251a3c53be5SAndrew Lunn 	const struct of_device_id *match;
3252a3c53be5SAndrew Lunn 	struct device_node *child;
3253a3c53be5SAndrew Lunn 	int err;
3254a3c53be5SAndrew Lunn 
3255a3c53be5SAndrew Lunn 	/* Always register one mdio bus for the internal/default mdio
3256a3c53be5SAndrew Lunn 	 * bus. This maybe represented in the device tree, but is
3257a3c53be5SAndrew Lunn 	 * optional.
3258a3c53be5SAndrew Lunn 	 */
3259a3c53be5SAndrew Lunn 	child = of_get_child_by_name(np, "mdio");
3260a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdio_register(chip, child, false);
3261a3c53be5SAndrew Lunn 	if (err)
3262a3c53be5SAndrew Lunn 		return err;
3263a3c53be5SAndrew Lunn 
3264a3c53be5SAndrew Lunn 	/* Walk the device tree, and see if there are any other nodes
3265a3c53be5SAndrew Lunn 	 * which say they are compatible with the external mdio
3266a3c53be5SAndrew Lunn 	 * bus.
3267a3c53be5SAndrew Lunn 	 */
3268a3c53be5SAndrew Lunn 	for_each_available_child_of_node(np, child) {
3269a3c53be5SAndrew Lunn 		match = of_match_node(mv88e6xxx_mdio_external_match, child);
3270a3c53be5SAndrew Lunn 		if (match) {
3271a3c53be5SAndrew Lunn 			err = mv88e6xxx_mdio_register(chip, child, true);
32723126aeecSAndrew Lunn 			if (err) {
32733126aeecSAndrew Lunn 				mv88e6xxx_mdios_unregister(chip);
327478e42040SNishka Dasgupta 				of_node_put(child);
3275a3c53be5SAndrew Lunn 				return err;
3276a3c53be5SAndrew Lunn 			}
3277a3c53be5SAndrew Lunn 		}
32783126aeecSAndrew Lunn 	}
3279a3c53be5SAndrew Lunn 
3280a3c53be5SAndrew Lunn 	return 0;
3281a3c53be5SAndrew Lunn }
3282a3c53be5SAndrew Lunn 
3283855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
3284855b1932SVivien Didelot {
328504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3286855b1932SVivien Didelot 
3287855b1932SVivien Didelot 	return chip->eeprom_len;
3288855b1932SVivien Didelot }
3289855b1932SVivien Didelot 
3290855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
3291855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
3292855b1932SVivien Didelot {
329304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3294855b1932SVivien Didelot 	int err;
3295855b1932SVivien Didelot 
3296ee4dc2e7SVivien Didelot 	if (!chip->info->ops->get_eeprom)
3297ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
3298ee4dc2e7SVivien Didelot 
3299c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3300ee4dc2e7SVivien Didelot 	err = chip->info->ops->get_eeprom(chip, eeprom, data);
3301c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3302855b1932SVivien Didelot 
3303855b1932SVivien Didelot 	if (err)
3304855b1932SVivien Didelot 		return err;
3305855b1932SVivien Didelot 
3306855b1932SVivien Didelot 	eeprom->magic = 0xc3ec4951;
3307855b1932SVivien Didelot 
3308855b1932SVivien Didelot 	return 0;
3309855b1932SVivien Didelot }
3310855b1932SVivien Didelot 
3311855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
3312855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
3313855b1932SVivien Didelot {
331404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3315855b1932SVivien Didelot 	int err;
3316855b1932SVivien Didelot 
3317ee4dc2e7SVivien Didelot 	if (!chip->info->ops->set_eeprom)
3318ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
3319ee4dc2e7SVivien Didelot 
3320855b1932SVivien Didelot 	if (eeprom->magic != 0xc3ec4951)
3321855b1932SVivien Didelot 		return -EINVAL;
3322855b1932SVivien Didelot 
3323c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3324ee4dc2e7SVivien Didelot 	err = chip->info->ops->set_eeprom(chip, eeprom, data);
3325c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3326855b1932SVivien Didelot 
3327855b1932SVivien Didelot 	return err;
3328855b1932SVivien Didelot }
3329855b1932SVivien Didelot 
3330b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = {
33314b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6097 */
333293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
333393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3334cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3335b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
33367e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
33377e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
333808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
33397f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
334096a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3341ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
334256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3343601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
334456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3345ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
33460898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3347c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
33489dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
33496c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
33502d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3351121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3352a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
335340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3354dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3355dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3356052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3357fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3358fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3359fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
336051c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
33619e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
3362a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3363a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
336417e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
33659e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
3366f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
33670ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
33686c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3369b3469dd8SVivien Didelot };
3370b3469dd8SVivien Didelot 
3371b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = {
33724b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6095 */
337393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
337493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3375b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
33767e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
33777e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
337808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
33797f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
338096a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
338156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3382601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
3383a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
33846c422e34SRussell King 	.port_link_state = mv88e6185_port_link_state,
33852d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3386121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3387a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
338840cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3389dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3390dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3391052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
339251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3393a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3394a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
339517e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3396f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
33970ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
33986c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3399b3469dd8SVivien Didelot };
3400b3469dd8SVivien Didelot 
34017d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = {
340215da3cc8SStefan Eichenberger 	/* MV88E6XXX_FAMILY_6097 */
340393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
340493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3405cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
34067d381a02SStefan Eichenberger 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
34077d381a02SStefan Eichenberger 	.phy_read = mv88e6xxx_g2_smi_phy_read,
34087d381a02SStefan Eichenberger 	.phy_write = mv88e6xxx_g2_smi_phy_write,
34097d381a02SStefan Eichenberger 	.port_set_link = mv88e6xxx_port_set_link,
34107d381a02SStefan Eichenberger 	.port_set_duplex = mv88e6xxx_port_set_duplex,
34117d381a02SStefan Eichenberger 	.port_set_speed = mv88e6185_port_set_speed,
3412ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
341356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3414601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
341556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3416cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3417ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
34180898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3419c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
34209dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34216c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
34222d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3423121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
34247d381a02SStefan Eichenberger 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
342540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
34267d381a02SStefan Eichenberger 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
34277d381a02SStefan Eichenberger 	.stats_get_strings = mv88e6095_stats_get_strings,
34287d381a02SStefan Eichenberger 	.stats_get_stats = mv88e6095_stats_get_stats,
3429fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3430fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
343191eaa475SVolodymyr Bendiuga 	.watchdog_ops = &mv88e6097_watchdog_ops,
343251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
34339e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
343417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
34359e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
3436f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
34370ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
34386c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
34397d381a02SStefan Eichenberger };
34407d381a02SStefan Eichenberger 
3441b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = {
34424b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
344393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
344493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3445cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3446b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3447ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3448ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
344908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
34507f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
345196a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
345256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3453601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3454c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
34559dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34566c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
34572d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3458121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
34590ac64c39SAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
346040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3461dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3462dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3463052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3464fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3465fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3466fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
346751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
34689e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
346917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
347023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
347123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3472f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
34730ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
34746c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3475b3469dd8SVivien Didelot };
3476b3469dd8SVivien Didelot 
3477b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = {
34784b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
347993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
348093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3481b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
34827e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
34837e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
348408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
34857f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
348696a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3487ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
348856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3489601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
349056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3491a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
3492cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3493ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
34940898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
349554186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
34966c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
34972d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3498121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3499a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
350040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3501dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3502dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3503052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3504fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3505fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3506fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
350751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3508a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
350902317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3510a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
351117e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3512f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
35130ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
35146c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3515b3469dd8SVivien Didelot };
3516b3469dd8SVivien Didelot 
3517990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = {
3518990e27b0SVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
351993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
352093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3521cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3522990e27b0SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
3523990e27b0SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3524990e27b0SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3525990e27b0SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3526990e27b0SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
3527990e27b0SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3528990e27b0SVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3529990e27b0SVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
353026422340SMarek Behún 	.port_set_speed = mv88e6341_port_set_speed,
35317cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
3532990e27b0SVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
3533990e27b0SVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3534990e27b0SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3535990e27b0SVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3536cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3537990e27b0SVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
35380898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3539990e27b0SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3540990e27b0SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35416c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
35422d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
35437a3007d2SMarek Behún 	.port_set_cmode = mv88e6341_port_set_cmode,
3544121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3545990e27b0SVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
354640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3547990e27b0SVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3548990e27b0SVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
3549990e27b0SVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
3550fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3551fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
3552990e27b0SVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
3553990e27b0SVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
35549e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
3555990e27b0SVivien Didelot 	.reset = mv88e6352_g1_reset,
3556f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
35570ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3558d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
3559d3cf7d8fSMarek Behún 	.serdes_get_lane = mv88e6341_serdes_get_lane,
35604241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
356161a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3562907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
3563a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
3564e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
3565990e27b0SVivien Didelot };
3566990e27b0SVivien Didelot 
3567b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = {
35684b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
356993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
357093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3571cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3572b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3573ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3574ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
357508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
35767f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
357796a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3578ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
357956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3580601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
358156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3582cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3583ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
35840898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3585c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
35869dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35876c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
35882d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3589121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3590a6da21bbSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
359140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3592dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3593dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3594052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3595fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3596fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3597fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
359851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
35999e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
360017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
360123e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
360223e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3603f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
36040ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3605a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3606dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
36076c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3608b3469dd8SVivien Didelot };
3609b3469dd8SVivien Didelot 
3610b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = {
36114b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
361293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
361393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3614cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3615b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3616efb3e74dSAndrew Lunn 	.phy_read = mv88e6165_phy_read,
3617efb3e74dSAndrew Lunn 	.phy_write = mv88e6165_phy_write,
361808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
36197f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
362096a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3621c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36229dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36236c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
36242d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3625121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3626a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
362740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3628dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3629dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3630052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3631fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3632fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3633fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
363451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
36359e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
363617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
363723e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
363823e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3639f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
36400ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3641a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3642dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
36436c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3644b3469dd8SVivien Didelot };
3645b3469dd8SVivien Didelot 
3646b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = {
36474b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
364893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
364993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3650cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3651b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3652b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3653b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
365408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
36557f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
365694d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
365796a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3658ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
365956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3660601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
366156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3662cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3663ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36640898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3665c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36669dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36676c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
36682d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3669121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3670a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
367140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3672dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3673dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3674052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3675fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3676fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3677fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
367851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
36799e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
368017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
368123e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
368223e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3683f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
36840ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
36856c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3686b3469dd8SVivien Didelot };
3687b3469dd8SVivien Didelot 
3688b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = {
36894b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
369093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
369193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3692cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3693ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3694ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3695b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3696b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3697b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
369808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
36997f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3700a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
370196a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3702ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
3703f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
370456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3705601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
370656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3707cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3708ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37090898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3710c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
37119dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37126c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
37132d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3714121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3715a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
371640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3717dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3718dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3719052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3720fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3721fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3722fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
372351c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
37249e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
372517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
37269e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
372723e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
372823e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3729f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37300ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37319db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
37326d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
3733d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
3734d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
3735a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
37366c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3737b3469dd8SVivien Didelot };
3738b3469dd8SVivien Didelot 
3739b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = {
37404b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
374193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
374293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3743cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3744b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3745b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3746b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
374708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
37487f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
374994d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
375096a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3751ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
375256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3753601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
375456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3755cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3756ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37570898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3758c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
37599dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37606c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
37612d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3762121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3763a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
376440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3765dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3766dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3767052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3768fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3769fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3770fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
377151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
37729e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
377317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
377423e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
377523e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3776f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37770ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37786c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3779b3469dd8SVivien Didelot };
3780b3469dd8SVivien Didelot 
3781b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = {
37824b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
378393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
378493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3785cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3786ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3787ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3788b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3789b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3790b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
379108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
37927f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3793a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
379496a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3795ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
3796f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
379756995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3798601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
379956995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3800cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3801ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
38020898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3803c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38049dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38056c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
38062d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3807121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3808a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
380940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3810dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3811dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3812052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3813fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3814fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3815fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
381651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
38179e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
381817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
38199e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
382023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
382123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3822f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
38230ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
38249db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
38256d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
38264241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
382761a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
3828907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
3829d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
3830d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
3831a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
38326c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3833b3469dd8SVivien Didelot };
3834b3469dd8SVivien Didelot 
3835b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = {
38364b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
383793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
383893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3839b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
38407e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
38417e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
384208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
38437f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
384496a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
384556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3846601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
3847ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
3848a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
384954186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
38506c422e34SRussell King 	.port_link_state = mv88e6185_port_link_state,
38512d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3852121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3853a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
385440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3855dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3856dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3857052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3858fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3859fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3860fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
386151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
386202317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3863a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3864a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
386517e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3866f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
38670ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
38686c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3869b3469dd8SVivien Didelot };
3870b3469dd8SVivien Didelot 
38711a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = {
38724b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3873ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3874cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
387598fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
387698fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
38771a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
38781a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
38791a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
38801a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
38811a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
38821a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
38831a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
38847cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
3885ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
3886f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
388756995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3888601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
388956995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
38900898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3891c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38929dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38936c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
38942d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3895fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
3896121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
389779523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3898de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3899dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3900dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3901e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3902fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3903fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
390461303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
39056e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
39069e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
390717e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
39089e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
390923e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
391023e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3911931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3912931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
39136335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
391417deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
39154241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
391661a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3917907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
39184262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
39194262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
3920bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
3921bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
39224262c38dSAndrew Lunn 	.phylink_validate = mv88e6390_phylink_validate,
3923a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
39246c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
39251a3b39ecSAndrew Lunn };
39261a3b39ecSAndrew Lunn 
39271a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = {
39284b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3929ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3930cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
393198fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
393298fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
39331a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
39341a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
39351a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
39361a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
39371a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
39381a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
39391a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390x_port_set_speed,
39407cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
3941ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
3942f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
394356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3944601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
394556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
39460898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3947c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
39489dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
39496c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
39502d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3951fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
3952121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
395379523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3954de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3955dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3956dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3957e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3958fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3959fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
396061303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
39616e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
39629e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
396317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
39649e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
396523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
396623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3967931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3968931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
3969d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
397017deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390x_serdes_get_lane,
39714241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
397261a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3973907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
39744262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
39754262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
3976bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
3977bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
39784262c38dSAndrew Lunn 	.phylink_validate = mv88e6390_phylink_validate,
3979a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
39806c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
39811a3b39ecSAndrew Lunn };
39821a3b39ecSAndrew Lunn 
39831a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = {
39844b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3985ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3986cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
398798fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
398898fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
39891a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
39901a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
39911a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
39921a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
39931a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
39941a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
39951a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
39967cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
3997ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
399856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3999601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
400056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
40010898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4002c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
40039dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
40046c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
40052d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4006fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4007121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
400879523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4009de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4010dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4011dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4012e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4013fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4014fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
401561303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
40166e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
40179e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
401817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
40199e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
402023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
402123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4022931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4023931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
40246335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
402517deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
40264241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
402761a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4028907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
40294262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
40304262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4031bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4032bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
40334262c38dSAndrew Lunn 	.phylink_validate = mv88e6390_phylink_validate,
40346d2ac8eeSAndrew Lunn 	.avb_ops = &mv88e6390_avb_ops,
40356d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
40366c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
40371a3b39ecSAndrew Lunn };
40381a3b39ecSAndrew Lunn 
4039b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = {
40404b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
404193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
404293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4043cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4044ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4045ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4046b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4047b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4048b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
404908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
40507f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
4051a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
405296a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
4053ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
4054f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
405556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4056601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
405756995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4058cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4059ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
40600898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4061c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
40629dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
40636c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
40642d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4065121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4066a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
406740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4068dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4069dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4070052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4071fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4072fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4073fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
407451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
40759e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
407617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
40779e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
407823e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
407923e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4080f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
40810ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
40829db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
40836d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
40844241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
408561a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4086907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
4087d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
4088d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
4089a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
40900d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
40916d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
40926c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
4093b3469dd8SVivien Didelot };
4094b3469dd8SVivien Didelot 
40951f71836fSRasmus Villemoes static const struct mv88e6xxx_ops mv88e6250_ops = {
40961f71836fSRasmus Villemoes 	/* MV88E6XXX_FAMILY_6250 */
40971f71836fSRasmus Villemoes 	.ieee_pri_map = mv88e6250_g1_ieee_pri_map,
40981f71836fSRasmus Villemoes 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
40991f71836fSRasmus Villemoes 	.irl_init_all = mv88e6352_g2_irl_init_all,
41001f71836fSRasmus Villemoes 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
41011f71836fSRasmus Villemoes 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
41021f71836fSRasmus Villemoes 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
41031f71836fSRasmus Villemoes 	.phy_read = mv88e6xxx_g2_smi_phy_read,
41041f71836fSRasmus Villemoes 	.phy_write = mv88e6xxx_g2_smi_phy_write,
41051f71836fSRasmus Villemoes 	.port_set_link = mv88e6xxx_port_set_link,
41061f71836fSRasmus Villemoes 	.port_set_duplex = mv88e6xxx_port_set_duplex,
41071f71836fSRasmus Villemoes 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
41081f71836fSRasmus Villemoes 	.port_set_speed = mv88e6250_port_set_speed,
41091f71836fSRasmus Villemoes 	.port_tag_remap = mv88e6095_port_tag_remap,
41101f71836fSRasmus Villemoes 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
41111f71836fSRasmus Villemoes 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
41121f71836fSRasmus Villemoes 	.port_set_ether_type = mv88e6351_port_set_ether_type,
41131f71836fSRasmus Villemoes 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
41141f71836fSRasmus Villemoes 	.port_pause_limit = mv88e6097_port_pause_limit,
41151f71836fSRasmus Villemoes 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
41161f71836fSRasmus Villemoes 	.port_link_state = mv88e6250_port_link_state,
41171f71836fSRasmus Villemoes 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
41181f71836fSRasmus Villemoes 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
41191f71836fSRasmus Villemoes 	.stats_get_sset_count = mv88e6250_stats_get_sset_count,
41201f71836fSRasmus Villemoes 	.stats_get_strings = mv88e6250_stats_get_strings,
41211f71836fSRasmus Villemoes 	.stats_get_stats = mv88e6250_stats_get_stats,
41221f71836fSRasmus Villemoes 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
41231f71836fSRasmus Villemoes 	.set_egress_port = mv88e6095_g1_set_egress_port,
41241f71836fSRasmus Villemoes 	.watchdog_ops = &mv88e6250_watchdog_ops,
41251f71836fSRasmus Villemoes 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
41261f71836fSRasmus Villemoes 	.pot_clear = mv88e6xxx_g2_pot_clear,
41271f71836fSRasmus Villemoes 	.reset = mv88e6250_g1_reset,
41281f71836fSRasmus Villemoes 	.vtu_getnext = mv88e6250_g1_vtu_getnext,
41291f71836fSRasmus Villemoes 	.vtu_loadpurge = mv88e6250_g1_vtu_loadpurge,
413071509614SHubert Feurstein 	.avb_ops = &mv88e6352_avb_ops,
413171509614SHubert Feurstein 	.ptp_ops = &mv88e6250_ptp_ops,
41321f71836fSRasmus Villemoes 	.phylink_validate = mv88e6065_phylink_validate,
41331f71836fSRasmus Villemoes };
41341f71836fSRasmus Villemoes 
41351a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = {
41364b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4137ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4138cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
413998fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
414098fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
41411a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
41421a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
41431a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
41441a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
41451a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
41461a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
41471a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
41487cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4149ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4150f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
415156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4152601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
415356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
41540898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4155c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
41569dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
41576c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
41582d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4159fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4160121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
416179523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4162de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4163dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4164dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4165e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4166fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4167fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
416861303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
41696e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
41709e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
417117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
41729e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
417323e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
417423e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4175931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4176931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
41776335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
417817deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
41794241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
418061a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4181907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
41824262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
41834262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4184bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4185bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
41864262c38dSAndrew Lunn 	.phylink_validate = mv88e6390_phylink_validate,
4187a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
41880d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
41896d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
41906c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
41911a3b39ecSAndrew Lunn };
41921a3b39ecSAndrew Lunn 
4193b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = {
41944b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6320 */
419593e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
419693e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4197cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4198ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4199ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4200b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4201b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4202b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
420308ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
42047f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
420596a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
4206ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
420756995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4208601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
420956995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4210cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4211ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
42120898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4213c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
42149dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
42156c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
42162d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4217121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4218a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
421940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4220dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4221dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4222052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
4223fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4224fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
42259c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
422651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
42279e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
422817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
4229f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
42300ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4231a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
42320d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
42336d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
42346c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4235b3469dd8SVivien Didelot };
4236b3469dd8SVivien Didelot 
4237b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = {
4238bd807204SVivien Didelot 	/* MV88E6XXX_FAMILY_6320 */
423993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
424093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4241cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4242ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4243ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4244b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4245b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4246b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
424708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
42487f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
424996a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
4250ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
425156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4252601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
425356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4254cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4255ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
42560898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4257c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
42589dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
42596c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
42602d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4261121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4262a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
426340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4264dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4265dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4266052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
4267fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4268fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
42699c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
427017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
4271f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
42720ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4273a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
42740d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
42756d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
42766c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4277b3469dd8SVivien Didelot };
4278b3469dd8SVivien Didelot 
427916e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = {
428016e329aeSVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
428193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
428293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4283cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
428416e329aeSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
428516e329aeSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
428616e329aeSVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
428716e329aeSVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
428816e329aeSVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
428916e329aeSVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
429016e329aeSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
429116e329aeSVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
429226422340SMarek Behún 	.port_set_speed = mv88e6341_port_set_speed,
42937cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
429416e329aeSVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
429516e329aeSVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
429616e329aeSVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
429716e329aeSVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4298cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
429916e329aeSVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
43000898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
430116e329aeSVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
430216e329aeSVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
43036c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
43042d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
43057a3007d2SMarek Behún 	.port_set_cmode = mv88e6341_port_set_cmode,
4306121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
430716e329aeSVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
430840cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
430916e329aeSVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
431016e329aeSVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
431116e329aeSVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
4312fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4313fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
431416e329aeSVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
431516e329aeSVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
43169e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
431716e329aeSVivien Didelot 	.reset = mv88e6352_g1_reset,
4318f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
43190ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4320d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
4321d3cf7d8fSMarek Behún 	.serdes_get_lane = mv88e6341_serdes_get_lane,
43224241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
432361a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4324907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
4325a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
43260d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
43276d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
4328e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
432916e329aeSVivien Didelot };
433016e329aeSVivien Didelot 
4331b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = {
43324b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
433393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
433493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4335cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4336b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4337b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4338b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
433908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
43407f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
434194d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
434296a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
4343ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
434456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4345601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
434656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4347cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4348ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
43490898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4350c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
43519dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
43526c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
43532d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4354121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4355a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
435640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4357dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4358dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4359052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4360fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4361fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4362fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
436351c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
43649e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
436517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
436623e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
436723e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4368f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
43690ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
43706c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4371b3469dd8SVivien Didelot };
4372b3469dd8SVivien Didelot 
4373b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = {
43744b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
437593e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
437693e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4377cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4378b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4379b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4380b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
438108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
43827f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
438394d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
438496a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
4385ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
438656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4387601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
438856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4389cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4390ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
43910898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4392c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
43939dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
43946c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
43952d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4396121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4397a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
439840cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4399dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4400dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4401052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4402fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4403fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4404fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
440551c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
44069e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
440717e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
440823e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
440923e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4410f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
44110ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
44120d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
44136d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
44146c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4415b3469dd8SVivien Didelot };
4416b3469dd8SVivien Didelot 
4417b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = {
44184b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
441993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
442093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4421cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4422ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4423ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4424b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4425b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4426b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
442708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
44287f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
4429a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
443096a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
4431ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
4432f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
443356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4434601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
443556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4436cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4437ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
44380898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4439c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
44409dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
44416c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
44422d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4443121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4444a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
444540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4446dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4447dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4448052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4449fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4450fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4451fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
445251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
44539e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
445417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
44559e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
445623e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
445723e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4458f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
44590ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
44609db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
44616d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
44624241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
446361a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4464907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
4465a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
44660d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
44676d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
4468cda9f4aaSAndrew Lunn 	.serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
4469cda9f4aaSAndrew Lunn 	.serdes_get_strings = mv88e6352_serdes_get_strings,
4470cda9f4aaSAndrew Lunn 	.serdes_get_stats = mv88e6352_serdes_get_stats,
4471d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
4472d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
44736c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
4474b3469dd8SVivien Didelot };
4475b3469dd8SVivien Didelot 
44761a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = {
44774b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4478ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4479cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
448098fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
448198fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
44821a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
44831a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
44841a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
44851a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
44861a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
44871a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
44881a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
44897cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4490ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4491f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
449256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4493601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
449456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4495cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4496ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
44970898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4498c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
44999dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
45006c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
45012d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4502fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4503121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
450479523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4505de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4506dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4507dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4508e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4509fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4510fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
451161303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
45126e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
45139e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
451417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
45159e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
451623e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
451723e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4518931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4519931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
45206335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
452117deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
45224241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
452361a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4524907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
4525a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
45260d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
45276d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
45280df95287SNikita Yushchenko 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
45290df95287SNikita Yushchenko 	.serdes_get_strings = mv88e6390_serdes_get_strings,
45300df95287SNikita Yushchenko 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4531bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4532bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
45336c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
45341a3b39ecSAndrew Lunn };
45351a3b39ecSAndrew Lunn 
45361a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = {
45374b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4538ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4539cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
454098fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
454198fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
45421a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
45431a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
45441a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
45451a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
45461a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
45471a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
45481a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390x_port_set_speed,
45497cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
4550ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4551f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
455256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4553601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
455456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4555cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4556ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
45570898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4558c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
45599dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
45606c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
45612d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4562b3dce4daSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
4563121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
456479523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4565de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4566dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4567dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4568e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4569fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4570fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
457161303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
45726e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
45739e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
457417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
45759e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
457623e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
457723e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4578931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4579931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4580d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
458117deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390x_serdes_get_lane,
45824241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
458361a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4584907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
45854262c38dSAndrew Lunn 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
45864262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
45874262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4588bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4589bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
4590a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
45910d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
45926d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
45936c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
45941a3b39ecSAndrew Lunn };
45951a3b39ecSAndrew Lunn 
4596fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = {
4597fad09c73SVivien Didelot 	[MV88E6085] = {
4598107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
4599fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6097,
4600fad09c73SVivien Didelot 		.name = "Marvell 88E6085",
4601fad09c73SVivien Didelot 		.num_databases = 4096,
4602d9ea5620SAndrew Lunn 		.num_macs = 8192,
4603fad09c73SVivien Didelot 		.num_ports = 10,
4604bc393155SAndrew Lunn 		.num_internal_phys = 5,
46053cf3c846SVivien Didelot 		.max_vid = 4095,
4606fad09c73SVivien Didelot 		.port_base_addr = 0x10,
46079255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4608a935c052SVivien Didelot 		.global1_addr = 0x1b,
46099069c13aSVivien Didelot 		.global2_addr = 0x1c,
4610acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4611dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4612d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4613e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4614f3645652SVivien Didelot 		.pvt = true,
4615b3e05aa1SVivien Didelot 		.multi_chip = true,
4616443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4617b3469dd8SVivien Didelot 		.ops = &mv88e6085_ops,
4618fad09c73SVivien Didelot 	},
4619fad09c73SVivien Didelot 
4620fad09c73SVivien Didelot 	[MV88E6095] = {
4621107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095,
4622fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6095,
4623fad09c73SVivien Didelot 		.name = "Marvell 88E6095/88E6095F",
4624fad09c73SVivien Didelot 		.num_databases = 256,
4625d9ea5620SAndrew Lunn 		.num_macs = 8192,
4626fad09c73SVivien Didelot 		.num_ports = 11,
4627bc393155SAndrew Lunn 		.num_internal_phys = 0,
46283cf3c846SVivien Didelot 		.max_vid = 4095,
4629fad09c73SVivien Didelot 		.port_base_addr = 0x10,
46309255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4631a935c052SVivien Didelot 		.global1_addr = 0x1b,
46329069c13aSVivien Didelot 		.global2_addr = 0x1c,
4633acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4634dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4635e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4636b3e05aa1SVivien Didelot 		.multi_chip = true,
4637443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4638b3469dd8SVivien Didelot 		.ops = &mv88e6095_ops,
4639fad09c73SVivien Didelot 	},
4640fad09c73SVivien Didelot 
46417d381a02SStefan Eichenberger 	[MV88E6097] = {
4642107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097,
46437d381a02SStefan Eichenberger 		.family = MV88E6XXX_FAMILY_6097,
46447d381a02SStefan Eichenberger 		.name = "Marvell 88E6097/88E6097F",
46457d381a02SStefan Eichenberger 		.num_databases = 4096,
4646d9ea5620SAndrew Lunn 		.num_macs = 8192,
46477d381a02SStefan Eichenberger 		.num_ports = 11,
4648bc393155SAndrew Lunn 		.num_internal_phys = 8,
46493cf3c846SVivien Didelot 		.max_vid = 4095,
46507d381a02SStefan Eichenberger 		.port_base_addr = 0x10,
46519255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
46527d381a02SStefan Eichenberger 		.global1_addr = 0x1b,
46539069c13aSVivien Didelot 		.global2_addr = 0x1c,
46547d381a02SStefan Eichenberger 		.age_time_coeff = 15000,
4655c534178bSStefan Eichenberger 		.g1_irqs = 8,
4656d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4657e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4658f3645652SVivien Didelot 		.pvt = true,
4659b3e05aa1SVivien Didelot 		.multi_chip = true,
46602bfcfcd3SStefan Eichenberger 		.tag_protocol = DSA_TAG_PROTO_EDSA,
46617d381a02SStefan Eichenberger 		.ops = &mv88e6097_ops,
46627d381a02SStefan Eichenberger 	},
46637d381a02SStefan Eichenberger 
4664fad09c73SVivien Didelot 	[MV88E6123] = {
4665107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123,
4666fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4667fad09c73SVivien Didelot 		.name = "Marvell 88E6123",
4668fad09c73SVivien Didelot 		.num_databases = 4096,
4669d9ea5620SAndrew Lunn 		.num_macs = 1024,
4670fad09c73SVivien Didelot 		.num_ports = 3,
4671bc393155SAndrew Lunn 		.num_internal_phys = 5,
46723cf3c846SVivien Didelot 		.max_vid = 4095,
4673fad09c73SVivien Didelot 		.port_base_addr = 0x10,
46749255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4675a935c052SVivien Didelot 		.global1_addr = 0x1b,
46769069c13aSVivien Didelot 		.global2_addr = 0x1c,
4677acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4678dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4679d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4680e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4681f3645652SVivien Didelot 		.pvt = true,
4682b3e05aa1SVivien Didelot 		.multi_chip = true,
46835ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4684b3469dd8SVivien Didelot 		.ops = &mv88e6123_ops,
4685fad09c73SVivien Didelot 	},
4686fad09c73SVivien Didelot 
4687fad09c73SVivien Didelot 	[MV88E6131] = {
4688107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131,
4689fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
4690fad09c73SVivien Didelot 		.name = "Marvell 88E6131",
4691fad09c73SVivien Didelot 		.num_databases = 256,
4692d9ea5620SAndrew Lunn 		.num_macs = 8192,
4693fad09c73SVivien Didelot 		.num_ports = 8,
4694bc393155SAndrew Lunn 		.num_internal_phys = 0,
46953cf3c846SVivien Didelot 		.max_vid = 4095,
4696fad09c73SVivien Didelot 		.port_base_addr = 0x10,
46979255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4698a935c052SVivien Didelot 		.global1_addr = 0x1b,
46999069c13aSVivien Didelot 		.global2_addr = 0x1c,
4700acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4701dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4702e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4703b3e05aa1SVivien Didelot 		.multi_chip = true,
4704443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4705b3469dd8SVivien Didelot 		.ops = &mv88e6131_ops,
4706fad09c73SVivien Didelot 	},
4707fad09c73SVivien Didelot 
4708990e27b0SVivien Didelot 	[MV88E6141] = {
4709107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141,
4710990e27b0SVivien Didelot 		.family = MV88E6XXX_FAMILY_6341,
471179a68b26SUwe Kleine-König 		.name = "Marvell 88E6141",
4712990e27b0SVivien Didelot 		.num_databases = 4096,
4713d9ea5620SAndrew Lunn 		.num_macs = 2048,
4714990e27b0SVivien Didelot 		.num_ports = 6,
4715bc393155SAndrew Lunn 		.num_internal_phys = 5,
4716a73ccd61SBrandon Streiff 		.num_gpio = 11,
47173cf3c846SVivien Didelot 		.max_vid = 4095,
4718990e27b0SVivien Didelot 		.port_base_addr = 0x10,
47199255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
4720990e27b0SVivien Didelot 		.global1_addr = 0x1b,
47219069c13aSVivien Didelot 		.global2_addr = 0x1c,
4722990e27b0SVivien Didelot 		.age_time_coeff = 3750,
4723990e27b0SVivien Didelot 		.atu_move_port_mask = 0x1f,
4724adfccf11SAndrew Lunn 		.g1_irqs = 9,
4725d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4726f3645652SVivien Didelot 		.pvt = true,
4727b3e05aa1SVivien Didelot 		.multi_chip = true,
4728990e27b0SVivien Didelot 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4729990e27b0SVivien Didelot 		.ops = &mv88e6141_ops,
4730990e27b0SVivien Didelot 	},
4731990e27b0SVivien Didelot 
4732fad09c73SVivien Didelot 	[MV88E6161] = {
4733107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161,
4734fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4735fad09c73SVivien Didelot 		.name = "Marvell 88E6161",
4736fad09c73SVivien Didelot 		.num_databases = 4096,
4737d9ea5620SAndrew Lunn 		.num_macs = 1024,
4738fad09c73SVivien Didelot 		.num_ports = 6,
4739bc393155SAndrew Lunn 		.num_internal_phys = 5,
47403cf3c846SVivien Didelot 		.max_vid = 4095,
4741fad09c73SVivien Didelot 		.port_base_addr = 0x10,
47429255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4743a935c052SVivien Didelot 		.global1_addr = 0x1b,
47449069c13aSVivien Didelot 		.global2_addr = 0x1c,
4745acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4746dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4747d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4748e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4749f3645652SVivien Didelot 		.pvt = true,
4750b3e05aa1SVivien Didelot 		.multi_chip = true,
47515ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4752dfa54348SAndrew Lunn 		.ptp_support = true,
4753b3469dd8SVivien Didelot 		.ops = &mv88e6161_ops,
4754fad09c73SVivien Didelot 	},
4755fad09c73SVivien Didelot 
4756fad09c73SVivien Didelot 	[MV88E6165] = {
4757107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165,
4758fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4759fad09c73SVivien Didelot 		.name = "Marvell 88E6165",
4760fad09c73SVivien Didelot 		.num_databases = 4096,
4761d9ea5620SAndrew Lunn 		.num_macs = 8192,
4762fad09c73SVivien Didelot 		.num_ports = 6,
4763bc393155SAndrew Lunn 		.num_internal_phys = 0,
47643cf3c846SVivien Didelot 		.max_vid = 4095,
4765fad09c73SVivien Didelot 		.port_base_addr = 0x10,
47669255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4767a935c052SVivien Didelot 		.global1_addr = 0x1b,
47689069c13aSVivien Didelot 		.global2_addr = 0x1c,
4769acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4770dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4771d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4772e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4773f3645652SVivien Didelot 		.pvt = true,
4774b3e05aa1SVivien Didelot 		.multi_chip = true,
4775443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4776dfa54348SAndrew Lunn 		.ptp_support = true,
4777b3469dd8SVivien Didelot 		.ops = &mv88e6165_ops,
4778fad09c73SVivien Didelot 	},
4779fad09c73SVivien Didelot 
4780fad09c73SVivien Didelot 	[MV88E6171] = {
4781107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171,
4782fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4783fad09c73SVivien Didelot 		.name = "Marvell 88E6171",
4784fad09c73SVivien Didelot 		.num_databases = 4096,
4785d9ea5620SAndrew Lunn 		.num_macs = 8192,
4786fad09c73SVivien Didelot 		.num_ports = 7,
4787bc393155SAndrew Lunn 		.num_internal_phys = 5,
47883cf3c846SVivien Didelot 		.max_vid = 4095,
4789fad09c73SVivien Didelot 		.port_base_addr = 0x10,
47909255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4791a935c052SVivien Didelot 		.global1_addr = 0x1b,
47929069c13aSVivien Didelot 		.global2_addr = 0x1c,
4793acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4794dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4795d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4796e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4797f3645652SVivien Didelot 		.pvt = true,
4798b3e05aa1SVivien Didelot 		.multi_chip = true,
4799443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4800b3469dd8SVivien Didelot 		.ops = &mv88e6171_ops,
4801fad09c73SVivien Didelot 	},
4802fad09c73SVivien Didelot 
4803fad09c73SVivien Didelot 	[MV88E6172] = {
4804107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172,
4805fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4806fad09c73SVivien Didelot 		.name = "Marvell 88E6172",
4807fad09c73SVivien Didelot 		.num_databases = 4096,
4808d9ea5620SAndrew Lunn 		.num_macs = 8192,
4809fad09c73SVivien Didelot 		.num_ports = 7,
4810bc393155SAndrew Lunn 		.num_internal_phys = 5,
4811a73ccd61SBrandon Streiff 		.num_gpio = 15,
48123cf3c846SVivien Didelot 		.max_vid = 4095,
4813fad09c73SVivien Didelot 		.port_base_addr = 0x10,
48149255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4815a935c052SVivien Didelot 		.global1_addr = 0x1b,
48169069c13aSVivien Didelot 		.global2_addr = 0x1c,
4817acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4818dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4819d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4820e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4821f3645652SVivien Didelot 		.pvt = true,
4822b3e05aa1SVivien Didelot 		.multi_chip = true,
4823443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4824b3469dd8SVivien Didelot 		.ops = &mv88e6172_ops,
4825fad09c73SVivien Didelot 	},
4826fad09c73SVivien Didelot 
4827fad09c73SVivien Didelot 	[MV88E6175] = {
4828107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175,
4829fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4830fad09c73SVivien Didelot 		.name = "Marvell 88E6175",
4831fad09c73SVivien Didelot 		.num_databases = 4096,
4832d9ea5620SAndrew Lunn 		.num_macs = 8192,
4833fad09c73SVivien Didelot 		.num_ports = 7,
4834bc393155SAndrew Lunn 		.num_internal_phys = 5,
48353cf3c846SVivien Didelot 		.max_vid = 4095,
4836fad09c73SVivien Didelot 		.port_base_addr = 0x10,
48379255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4838a935c052SVivien Didelot 		.global1_addr = 0x1b,
48399069c13aSVivien Didelot 		.global2_addr = 0x1c,
4840acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4841dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4842d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4843e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4844f3645652SVivien Didelot 		.pvt = true,
4845b3e05aa1SVivien Didelot 		.multi_chip = true,
4846443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4847b3469dd8SVivien Didelot 		.ops = &mv88e6175_ops,
4848fad09c73SVivien Didelot 	},
4849fad09c73SVivien Didelot 
4850fad09c73SVivien Didelot 	[MV88E6176] = {
4851107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176,
4852fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4853fad09c73SVivien Didelot 		.name = "Marvell 88E6176",
4854fad09c73SVivien Didelot 		.num_databases = 4096,
4855d9ea5620SAndrew Lunn 		.num_macs = 8192,
4856fad09c73SVivien Didelot 		.num_ports = 7,
4857bc393155SAndrew Lunn 		.num_internal_phys = 5,
4858a73ccd61SBrandon Streiff 		.num_gpio = 15,
48593cf3c846SVivien Didelot 		.max_vid = 4095,
4860fad09c73SVivien Didelot 		.port_base_addr = 0x10,
48619255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4862a935c052SVivien Didelot 		.global1_addr = 0x1b,
48639069c13aSVivien Didelot 		.global2_addr = 0x1c,
4864acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4865dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4866d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4867e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4868f3645652SVivien Didelot 		.pvt = true,
4869b3e05aa1SVivien Didelot 		.multi_chip = true,
4870443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4871b3469dd8SVivien Didelot 		.ops = &mv88e6176_ops,
4872fad09c73SVivien Didelot 	},
4873fad09c73SVivien Didelot 
4874fad09c73SVivien Didelot 	[MV88E6185] = {
4875107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185,
4876fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
4877fad09c73SVivien Didelot 		.name = "Marvell 88E6185",
4878fad09c73SVivien Didelot 		.num_databases = 256,
4879d9ea5620SAndrew Lunn 		.num_macs = 8192,
4880fad09c73SVivien Didelot 		.num_ports = 10,
4881bc393155SAndrew Lunn 		.num_internal_phys = 0,
48823cf3c846SVivien Didelot 		.max_vid = 4095,
4883fad09c73SVivien Didelot 		.port_base_addr = 0x10,
48849255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4885a935c052SVivien Didelot 		.global1_addr = 0x1b,
48869069c13aSVivien Didelot 		.global2_addr = 0x1c,
4887acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4888dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4889e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4890b3e05aa1SVivien Didelot 		.multi_chip = true,
4891443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4892b3469dd8SVivien Didelot 		.ops = &mv88e6185_ops,
4893fad09c73SVivien Didelot 	},
4894fad09c73SVivien Didelot 
48951a3b39ecSAndrew Lunn 	[MV88E6190] = {
4896107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190,
48971a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
48981a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190",
48991a3b39ecSAndrew Lunn 		.num_databases = 4096,
4900d9ea5620SAndrew Lunn 		.num_macs = 16384,
49011a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
490295150f29SHeiner Kallweit 		.num_internal_phys = 9,
4903a73ccd61SBrandon Streiff 		.num_gpio = 16,
4904931d1822SVivien Didelot 		.max_vid = 8191,
49051a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
49069255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
49071a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
49089069c13aSVivien Didelot 		.global2_addr = 0x1c,
4909443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4910b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
49111a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4912d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4913f3645652SVivien Didelot 		.pvt = true,
4914b3e05aa1SVivien Didelot 		.multi_chip = true,
4915e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
49161a3b39ecSAndrew Lunn 		.ops = &mv88e6190_ops,
49171a3b39ecSAndrew Lunn 	},
49181a3b39ecSAndrew Lunn 
49191a3b39ecSAndrew Lunn 	[MV88E6190X] = {
4920107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X,
49211a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
49221a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190X",
49231a3b39ecSAndrew Lunn 		.num_databases = 4096,
4924d9ea5620SAndrew Lunn 		.num_macs = 16384,
49251a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
492695150f29SHeiner Kallweit 		.num_internal_phys = 9,
4927a73ccd61SBrandon Streiff 		.num_gpio = 16,
4928931d1822SVivien Didelot 		.max_vid = 8191,
49291a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
49309255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
49311a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
49329069c13aSVivien Didelot 		.global2_addr = 0x1c,
4933b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
49341a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4935d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4936e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4937f3645652SVivien Didelot 		.pvt = true,
4938b3e05aa1SVivien Didelot 		.multi_chip = true,
4939443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
49401a3b39ecSAndrew Lunn 		.ops = &mv88e6190x_ops,
49411a3b39ecSAndrew Lunn 	},
49421a3b39ecSAndrew Lunn 
49431a3b39ecSAndrew Lunn 	[MV88E6191] = {
4944107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191,
49451a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
49461a3b39ecSAndrew Lunn 		.name = "Marvell 88E6191",
49471a3b39ecSAndrew Lunn 		.num_databases = 4096,
4948d9ea5620SAndrew Lunn 		.num_macs = 16384,
49491a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
495095150f29SHeiner Kallweit 		.num_internal_phys = 9,
4951931d1822SVivien Didelot 		.max_vid = 8191,
49521a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
49539255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
49541a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
49559069c13aSVivien Didelot 		.global2_addr = 0x1c,
4956b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
4957443d5a1bSAndrew Lunn 		.g1_irqs = 9,
4958d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4959e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4960f3645652SVivien Didelot 		.pvt = true,
4961b3e05aa1SVivien Didelot 		.multi_chip = true,
4962443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
49632fa8d3afSBrandon Streiff 		.ptp_support = true,
49642cf4cefbSVivien Didelot 		.ops = &mv88e6191_ops,
49651a3b39ecSAndrew Lunn 	},
49661a3b39ecSAndrew Lunn 
496749022647SHubert Feurstein 	[MV88E6220] = {
496849022647SHubert Feurstein 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
496949022647SHubert Feurstein 		.family = MV88E6XXX_FAMILY_6250,
497049022647SHubert Feurstein 		.name = "Marvell 88E6220",
497149022647SHubert Feurstein 		.num_databases = 64,
497249022647SHubert Feurstein 
497349022647SHubert Feurstein 		/* Ports 2-4 are not routed to pins
497449022647SHubert Feurstein 		 * => usable ports 0, 1, 5, 6
497549022647SHubert Feurstein 		 */
497649022647SHubert Feurstein 		.num_ports = 7,
497749022647SHubert Feurstein 		.num_internal_phys = 2,
4978c857486aSHubert Feurstein 		.invalid_port_mask = BIT(2) | BIT(3) | BIT(4),
497949022647SHubert Feurstein 		.max_vid = 4095,
498049022647SHubert Feurstein 		.port_base_addr = 0x08,
498149022647SHubert Feurstein 		.phy_base_addr = 0x00,
498249022647SHubert Feurstein 		.global1_addr = 0x0f,
498349022647SHubert Feurstein 		.global2_addr = 0x07,
498449022647SHubert Feurstein 		.age_time_coeff = 15000,
498549022647SHubert Feurstein 		.g1_irqs = 9,
498649022647SHubert Feurstein 		.g2_irqs = 10,
498749022647SHubert Feurstein 		.atu_move_port_mask = 0xf,
498849022647SHubert Feurstein 		.dual_chip = true,
498949022647SHubert Feurstein 		.tag_protocol = DSA_TAG_PROTO_DSA,
499071509614SHubert Feurstein 		.ptp_support = true,
499149022647SHubert Feurstein 		.ops = &mv88e6250_ops,
499249022647SHubert Feurstein 	},
499349022647SHubert Feurstein 
4994fad09c73SVivien Didelot 	[MV88E6240] = {
4995107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240,
4996fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4997fad09c73SVivien Didelot 		.name = "Marvell 88E6240",
4998fad09c73SVivien Didelot 		.num_databases = 4096,
4999d9ea5620SAndrew Lunn 		.num_macs = 8192,
5000fad09c73SVivien Didelot 		.num_ports = 7,
5001bc393155SAndrew Lunn 		.num_internal_phys = 5,
5002a73ccd61SBrandon Streiff 		.num_gpio = 15,
50033cf3c846SVivien Didelot 		.max_vid = 4095,
5004fad09c73SVivien Didelot 		.port_base_addr = 0x10,
50059255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5006a935c052SVivien Didelot 		.global1_addr = 0x1b,
50079069c13aSVivien Didelot 		.global2_addr = 0x1c,
5008acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5009dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5010d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5011e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5012f3645652SVivien Didelot 		.pvt = true,
5013b3e05aa1SVivien Didelot 		.multi_chip = true,
5014443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
50152fa8d3afSBrandon Streiff 		.ptp_support = true,
5016b3469dd8SVivien Didelot 		.ops = &mv88e6240_ops,
5017fad09c73SVivien Didelot 	},
5018fad09c73SVivien Didelot 
50191f71836fSRasmus Villemoes 	[MV88E6250] = {
50201f71836fSRasmus Villemoes 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250,
50211f71836fSRasmus Villemoes 		.family = MV88E6XXX_FAMILY_6250,
50221f71836fSRasmus Villemoes 		.name = "Marvell 88E6250",
50231f71836fSRasmus Villemoes 		.num_databases = 64,
50241f71836fSRasmus Villemoes 		.num_ports = 7,
50251f71836fSRasmus Villemoes 		.num_internal_phys = 5,
50261f71836fSRasmus Villemoes 		.max_vid = 4095,
50271f71836fSRasmus Villemoes 		.port_base_addr = 0x08,
50281f71836fSRasmus Villemoes 		.phy_base_addr = 0x00,
50291f71836fSRasmus Villemoes 		.global1_addr = 0x0f,
50301f71836fSRasmus Villemoes 		.global2_addr = 0x07,
50311f71836fSRasmus Villemoes 		.age_time_coeff = 15000,
50321f71836fSRasmus Villemoes 		.g1_irqs = 9,
50331f71836fSRasmus Villemoes 		.g2_irqs = 10,
50341f71836fSRasmus Villemoes 		.atu_move_port_mask = 0xf,
50351f71836fSRasmus Villemoes 		.dual_chip = true,
50361f71836fSRasmus Villemoes 		.tag_protocol = DSA_TAG_PROTO_DSA,
503771509614SHubert Feurstein 		.ptp_support = true,
50381f71836fSRasmus Villemoes 		.ops = &mv88e6250_ops,
50391f71836fSRasmus Villemoes 	},
50401f71836fSRasmus Villemoes 
50411a3b39ecSAndrew Lunn 	[MV88E6290] = {
5042107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
50431a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
50441a3b39ecSAndrew Lunn 		.name = "Marvell 88E6290",
50451a3b39ecSAndrew Lunn 		.num_databases = 4096,
50461a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
504795150f29SHeiner Kallweit 		.num_internal_phys = 9,
5048a73ccd61SBrandon Streiff 		.num_gpio = 16,
5049931d1822SVivien Didelot 		.max_vid = 8191,
50501a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
50519255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
50521a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
50539069c13aSVivien Didelot 		.global2_addr = 0x1c,
5054b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
50551a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5056d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5057e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5058f3645652SVivien Didelot 		.pvt = true,
5059b3e05aa1SVivien Didelot 		.multi_chip = true,
5060443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
50612fa8d3afSBrandon Streiff 		.ptp_support = true,
50621a3b39ecSAndrew Lunn 		.ops = &mv88e6290_ops,
50631a3b39ecSAndrew Lunn 	},
50641a3b39ecSAndrew Lunn 
5065fad09c73SVivien Didelot 	[MV88E6320] = {
5066107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320,
5067fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
5068fad09c73SVivien Didelot 		.name = "Marvell 88E6320",
5069fad09c73SVivien Didelot 		.num_databases = 4096,
5070d9ea5620SAndrew Lunn 		.num_macs = 8192,
5071fad09c73SVivien Didelot 		.num_ports = 7,
5072bc393155SAndrew Lunn 		.num_internal_phys = 5,
5073a73ccd61SBrandon Streiff 		.num_gpio = 15,
50743cf3c846SVivien Didelot 		.max_vid = 4095,
5075fad09c73SVivien Didelot 		.port_base_addr = 0x10,
50769255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5077a935c052SVivien Didelot 		.global1_addr = 0x1b,
50789069c13aSVivien Didelot 		.global2_addr = 0x1c,
5079acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5080dc30c35bSAndrew Lunn 		.g1_irqs = 8,
5081bc393155SAndrew Lunn 		.g2_irqs = 10,
5082e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5083f3645652SVivien Didelot 		.pvt = true,
5084b3e05aa1SVivien Didelot 		.multi_chip = true,
5085443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
50862fa8d3afSBrandon Streiff 		.ptp_support = true,
5087b3469dd8SVivien Didelot 		.ops = &mv88e6320_ops,
5088fad09c73SVivien Didelot 	},
5089fad09c73SVivien Didelot 
5090fad09c73SVivien Didelot 	[MV88E6321] = {
5091107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321,
5092fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
5093fad09c73SVivien Didelot 		.name = "Marvell 88E6321",
5094fad09c73SVivien Didelot 		.num_databases = 4096,
5095d9ea5620SAndrew Lunn 		.num_macs = 8192,
5096fad09c73SVivien Didelot 		.num_ports = 7,
5097bc393155SAndrew Lunn 		.num_internal_phys = 5,
5098a73ccd61SBrandon Streiff 		.num_gpio = 15,
50993cf3c846SVivien Didelot 		.max_vid = 4095,
5100fad09c73SVivien Didelot 		.port_base_addr = 0x10,
51019255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5102a935c052SVivien Didelot 		.global1_addr = 0x1b,
51039069c13aSVivien Didelot 		.global2_addr = 0x1c,
5104acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5105dc30c35bSAndrew Lunn 		.g1_irqs = 8,
5106bc393155SAndrew Lunn 		.g2_irqs = 10,
5107e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5108b3e05aa1SVivien Didelot 		.multi_chip = true,
5109443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
51102fa8d3afSBrandon Streiff 		.ptp_support = true,
5111b3469dd8SVivien Didelot 		.ops = &mv88e6321_ops,
5112fad09c73SVivien Didelot 	},
5113fad09c73SVivien Didelot 
5114a75961d0SGregory CLEMENT 	[MV88E6341] = {
5115107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
5116a75961d0SGregory CLEMENT 		.family = MV88E6XXX_FAMILY_6341,
5117a75961d0SGregory CLEMENT 		.name = "Marvell 88E6341",
5118a75961d0SGregory CLEMENT 		.num_databases = 4096,
5119d9ea5620SAndrew Lunn 		.num_macs = 2048,
5120bc393155SAndrew Lunn 		.num_internal_phys = 5,
5121a75961d0SGregory CLEMENT 		.num_ports = 6,
5122a73ccd61SBrandon Streiff 		.num_gpio = 11,
51233cf3c846SVivien Didelot 		.max_vid = 4095,
5124a75961d0SGregory CLEMENT 		.port_base_addr = 0x10,
51259255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
5126a75961d0SGregory CLEMENT 		.global1_addr = 0x1b,
51279069c13aSVivien Didelot 		.global2_addr = 0x1c,
5128a75961d0SGregory CLEMENT 		.age_time_coeff = 3750,
5129e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5130adfccf11SAndrew Lunn 		.g1_irqs = 9,
5131d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5132f3645652SVivien Didelot 		.pvt = true,
5133b3e05aa1SVivien Didelot 		.multi_chip = true,
5134a75961d0SGregory CLEMENT 		.tag_protocol = DSA_TAG_PROTO_EDSA,
51352fa8d3afSBrandon Streiff 		.ptp_support = true,
5136a75961d0SGregory CLEMENT 		.ops = &mv88e6341_ops,
5137a75961d0SGregory CLEMENT 	},
5138a75961d0SGregory CLEMENT 
5139fad09c73SVivien Didelot 	[MV88E6350] = {
5140107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350,
5141fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5142fad09c73SVivien Didelot 		.name = "Marvell 88E6350",
5143fad09c73SVivien Didelot 		.num_databases = 4096,
5144d9ea5620SAndrew Lunn 		.num_macs = 8192,
5145fad09c73SVivien Didelot 		.num_ports = 7,
5146bc393155SAndrew Lunn 		.num_internal_phys = 5,
51473cf3c846SVivien Didelot 		.max_vid = 4095,
5148fad09c73SVivien Didelot 		.port_base_addr = 0x10,
51499255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5150a935c052SVivien Didelot 		.global1_addr = 0x1b,
51519069c13aSVivien Didelot 		.global2_addr = 0x1c,
5152acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5153dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5154d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5155e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5156f3645652SVivien Didelot 		.pvt = true,
5157b3e05aa1SVivien Didelot 		.multi_chip = true,
5158443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
5159b3469dd8SVivien Didelot 		.ops = &mv88e6350_ops,
5160fad09c73SVivien Didelot 	},
5161fad09c73SVivien Didelot 
5162fad09c73SVivien Didelot 	[MV88E6351] = {
5163107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351,
5164fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5165fad09c73SVivien Didelot 		.name = "Marvell 88E6351",
5166fad09c73SVivien Didelot 		.num_databases = 4096,
5167d9ea5620SAndrew Lunn 		.num_macs = 8192,
5168fad09c73SVivien Didelot 		.num_ports = 7,
5169bc393155SAndrew Lunn 		.num_internal_phys = 5,
51703cf3c846SVivien Didelot 		.max_vid = 4095,
5171fad09c73SVivien Didelot 		.port_base_addr = 0x10,
51729255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5173a935c052SVivien Didelot 		.global1_addr = 0x1b,
51749069c13aSVivien Didelot 		.global2_addr = 0x1c,
5175acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5176dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5177d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5178e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5179f3645652SVivien Didelot 		.pvt = true,
5180b3e05aa1SVivien Didelot 		.multi_chip = true,
5181443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
5182b3469dd8SVivien Didelot 		.ops = &mv88e6351_ops,
5183fad09c73SVivien Didelot 	},
5184fad09c73SVivien Didelot 
5185fad09c73SVivien Didelot 	[MV88E6352] = {
5186107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352,
5187fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
5188fad09c73SVivien Didelot 		.name = "Marvell 88E6352",
5189fad09c73SVivien Didelot 		.num_databases = 4096,
5190d9ea5620SAndrew Lunn 		.num_macs = 8192,
5191fad09c73SVivien Didelot 		.num_ports = 7,
5192bc393155SAndrew Lunn 		.num_internal_phys = 5,
5193a73ccd61SBrandon Streiff 		.num_gpio = 15,
51943cf3c846SVivien Didelot 		.max_vid = 4095,
5195fad09c73SVivien Didelot 		.port_base_addr = 0x10,
51969255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5197a935c052SVivien Didelot 		.global1_addr = 0x1b,
51989069c13aSVivien Didelot 		.global2_addr = 0x1c,
5199acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5200dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5201d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5202e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5203f3645652SVivien Didelot 		.pvt = true,
5204b3e05aa1SVivien Didelot 		.multi_chip = true,
5205443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
52062fa8d3afSBrandon Streiff 		.ptp_support = true,
5207b3469dd8SVivien Didelot 		.ops = &mv88e6352_ops,
5208fad09c73SVivien Didelot 	},
52091a3b39ecSAndrew Lunn 	[MV88E6390] = {
5210107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
52111a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
52121a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390",
52131a3b39ecSAndrew Lunn 		.num_databases = 4096,
5214d9ea5620SAndrew Lunn 		.num_macs = 16384,
52151a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
521695150f29SHeiner Kallweit 		.num_internal_phys = 9,
5217a73ccd61SBrandon Streiff 		.num_gpio = 16,
5218931d1822SVivien Didelot 		.max_vid = 8191,
52191a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
52209255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
52211a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
52229069c13aSVivien Didelot 		.global2_addr = 0x1c,
5223b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
52241a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5225d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5226e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5227f3645652SVivien Didelot 		.pvt = true,
5228b3e05aa1SVivien Didelot 		.multi_chip = true,
5229443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
52302fa8d3afSBrandon Streiff 		.ptp_support = true,
52311a3b39ecSAndrew Lunn 		.ops = &mv88e6390_ops,
52321a3b39ecSAndrew Lunn 	},
52331a3b39ecSAndrew Lunn 	[MV88E6390X] = {
5234107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X,
52351a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
52361a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390X",
52371a3b39ecSAndrew Lunn 		.num_databases = 4096,
5238d9ea5620SAndrew Lunn 		.num_macs = 16384,
52391a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
524095150f29SHeiner Kallweit 		.num_internal_phys = 9,
5241a73ccd61SBrandon Streiff 		.num_gpio = 16,
5242931d1822SVivien Didelot 		.max_vid = 8191,
52431a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
52449255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
52451a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
52469069c13aSVivien Didelot 		.global2_addr = 0x1c,
5247b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
52481a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5249d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5250e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5251f3645652SVivien Didelot 		.pvt = true,
5252b3e05aa1SVivien Didelot 		.multi_chip = true,
5253443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
52542fa8d3afSBrandon Streiff 		.ptp_support = true,
52551a3b39ecSAndrew Lunn 		.ops = &mv88e6390x_ops,
52561a3b39ecSAndrew Lunn 	},
5257fad09c73SVivien Didelot };
5258fad09c73SVivien Didelot 
5259fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
5260fad09c73SVivien Didelot {
5261fad09c73SVivien Didelot 	int i;
5262fad09c73SVivien Didelot 
5263fad09c73SVivien Didelot 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
5264fad09c73SVivien Didelot 		if (mv88e6xxx_table[i].prod_num == prod_num)
5265fad09c73SVivien Didelot 			return &mv88e6xxx_table[i];
5266fad09c73SVivien Didelot 
5267fad09c73SVivien Didelot 	return NULL;
5268fad09c73SVivien Didelot }
5269fad09c73SVivien Didelot 
5270fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
5271fad09c73SVivien Didelot {
5272fad09c73SVivien Didelot 	const struct mv88e6xxx_info *info;
52738f6345b2SVivien Didelot 	unsigned int prod_num, rev;
52748f6345b2SVivien Didelot 	u16 id;
52758f6345b2SVivien Didelot 	int err;
5276fad09c73SVivien Didelot 
5277c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5278107fcc10SVivien Didelot 	err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
5279c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
52808f6345b2SVivien Didelot 	if (err)
52818f6345b2SVivien Didelot 		return err;
5282fad09c73SVivien Didelot 
5283107fcc10SVivien Didelot 	prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK;
5284107fcc10SVivien Didelot 	rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK;
5285fad09c73SVivien Didelot 
5286fad09c73SVivien Didelot 	info = mv88e6xxx_lookup_info(prod_num);
5287fad09c73SVivien Didelot 	if (!info)
5288fad09c73SVivien Didelot 		return -ENODEV;
5289fad09c73SVivien Didelot 
5290fad09c73SVivien Didelot 	/* Update the compatible info with the probed one */
5291fad09c73SVivien Didelot 	chip->info = info;
5292fad09c73SVivien Didelot 
5293ca070c10SVivien Didelot 	err = mv88e6xxx_g2_require(chip);
5294ca070c10SVivien Didelot 	if (err)
5295ca070c10SVivien Didelot 		return err;
5296ca070c10SVivien Didelot 
5297fad09c73SVivien Didelot 	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
5298fad09c73SVivien Didelot 		 chip->info->prod_num, chip->info->name, rev);
5299fad09c73SVivien Didelot 
5300fad09c73SVivien Didelot 	return 0;
5301fad09c73SVivien Didelot }
5302fad09c73SVivien Didelot 
5303fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
5304fad09c73SVivien Didelot {
5305fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
5306fad09c73SVivien Didelot 
5307fad09c73SVivien Didelot 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
5308fad09c73SVivien Didelot 	if (!chip)
5309fad09c73SVivien Didelot 		return NULL;
5310fad09c73SVivien Didelot 
5311fad09c73SVivien Didelot 	chip->dev = dev;
5312fad09c73SVivien Didelot 
5313fad09c73SVivien Didelot 	mutex_init(&chip->reg_lock);
5314a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&chip->mdios);
5315da7dc875SVivien Didelot 	idr_init(&chip->policies);
5316fad09c73SVivien Didelot 
5317fad09c73SVivien Didelot 	return chip;
5318fad09c73SVivien Didelot }
5319fad09c73SVivien Didelot 
53205ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
53214d776482SFlorian Fainelli 							int port,
53224d776482SFlorian Fainelli 							enum dsa_tag_protocol m)
53237b314362SAndrew Lunn {
532404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
53252bbb33beSAndrew Lunn 
5326443d5a1bSAndrew Lunn 	return chip->info->tag_protocol;
53277b314362SAndrew Lunn }
53287b314362SAndrew Lunn 
53297df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port,
53303709aadcSVivien Didelot 				      const struct switchdev_obj_port_mdb *mdb)
53317df8fbddSVivien Didelot {
53327df8fbddSVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
53337df8fbddSVivien Didelot 	 * so skip the prepare phase.
53347df8fbddSVivien Didelot 	 */
53357df8fbddSVivien Didelot 
53367df8fbddSVivien Didelot 	return 0;
53377df8fbddSVivien Didelot }
53387df8fbddSVivien Didelot 
53397df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
53403709aadcSVivien Didelot 				   const struct switchdev_obj_port_mdb *mdb)
53417df8fbddSVivien Didelot {
534204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
53437df8fbddSVivien Didelot 
5344c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
53457df8fbddSVivien Didelot 	if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
534627c0e600SVivien Didelot 					 MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC))
5347774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to load multicast MAC address\n",
5348774439e5SVivien Didelot 			port);
5349c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
53507df8fbddSVivien Didelot }
53517df8fbddSVivien Didelot 
53527df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
53537df8fbddSVivien Didelot 				  const struct switchdev_obj_port_mdb *mdb)
53547df8fbddSVivien Didelot {
535504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
53567df8fbddSVivien Didelot 	int err;
53577df8fbddSVivien Didelot 
5358c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5359d8291a95SVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0);
5360c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
53617df8fbddSVivien Didelot 
53627df8fbddSVivien Didelot 	return err;
53637df8fbddSVivien Didelot }
53647df8fbddSVivien Didelot 
5365f0942e00SIwan R Timmer static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
5366f0942e00SIwan R Timmer 				     struct dsa_mall_mirror_tc_entry *mirror,
5367f0942e00SIwan R Timmer 				     bool ingress)
5368f0942e00SIwan R Timmer {
5369f0942e00SIwan R Timmer 	enum mv88e6xxx_egress_direction direction = ingress ?
5370f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS :
5371f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS;
5372f0942e00SIwan R Timmer 	struct mv88e6xxx_chip *chip = ds->priv;
5373f0942e00SIwan R Timmer 	bool other_mirrors = false;
5374f0942e00SIwan R Timmer 	int i;
5375f0942e00SIwan R Timmer 	int err;
5376f0942e00SIwan R Timmer 
5377f0942e00SIwan R Timmer 	if (!chip->info->ops->set_egress_port)
5378f0942e00SIwan R Timmer 		return -EOPNOTSUPP;
5379f0942e00SIwan R Timmer 
5380f0942e00SIwan R Timmer 	mutex_lock(&chip->reg_lock);
5381f0942e00SIwan R Timmer 	if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
5382f0942e00SIwan R Timmer 	    mirror->to_local_port) {
5383f0942e00SIwan R Timmer 		for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
5384f0942e00SIwan R Timmer 			other_mirrors |= ingress ?
5385f0942e00SIwan R Timmer 					 chip->ports[i].mirror_ingress :
5386f0942e00SIwan R Timmer 					 chip->ports[i].mirror_egress;
5387f0942e00SIwan R Timmer 
5388f0942e00SIwan R Timmer 		/* Can't change egress port when other mirror is active */
5389f0942e00SIwan R Timmer 		if (other_mirrors) {
5390f0942e00SIwan R Timmer 			err = -EBUSY;
5391f0942e00SIwan R Timmer 			goto out;
5392f0942e00SIwan R Timmer 		}
5393f0942e00SIwan R Timmer 
5394f0942e00SIwan R Timmer 		err = chip->info->ops->set_egress_port(chip,
5395f0942e00SIwan R Timmer 						       direction,
5396f0942e00SIwan R Timmer 						       mirror->to_local_port);
5397f0942e00SIwan R Timmer 		if (err)
5398f0942e00SIwan R Timmer 			goto out;
5399f0942e00SIwan R Timmer 	}
5400f0942e00SIwan R Timmer 
5401f0942e00SIwan R Timmer 	err = mv88e6xxx_port_set_mirror(chip, port, direction, true);
5402f0942e00SIwan R Timmer out:
5403f0942e00SIwan R Timmer 	mutex_unlock(&chip->reg_lock);
5404f0942e00SIwan R Timmer 
5405f0942e00SIwan R Timmer 	return err;
5406f0942e00SIwan R Timmer }
5407f0942e00SIwan R Timmer 
5408f0942e00SIwan R Timmer static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
5409f0942e00SIwan R Timmer 				      struct dsa_mall_mirror_tc_entry *mirror)
5410f0942e00SIwan R Timmer {
5411f0942e00SIwan R Timmer 	enum mv88e6xxx_egress_direction direction = mirror->ingress ?
5412f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS :
5413f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS;
5414f0942e00SIwan R Timmer 	struct mv88e6xxx_chip *chip = ds->priv;
5415f0942e00SIwan R Timmer 	bool other_mirrors = false;
5416f0942e00SIwan R Timmer 	int i;
5417f0942e00SIwan R Timmer 
5418f0942e00SIwan R Timmer 	mutex_lock(&chip->reg_lock);
5419f0942e00SIwan R Timmer 	if (mv88e6xxx_port_set_mirror(chip, port, direction, false))
5420f0942e00SIwan R Timmer 		dev_err(ds->dev, "p%d: failed to disable mirroring\n", port);
5421f0942e00SIwan R Timmer 
5422f0942e00SIwan R Timmer 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
5423f0942e00SIwan R Timmer 		other_mirrors |= mirror->ingress ?
5424f0942e00SIwan R Timmer 				 chip->ports[i].mirror_ingress :
5425f0942e00SIwan R Timmer 				 chip->ports[i].mirror_egress;
5426f0942e00SIwan R Timmer 
5427f0942e00SIwan R Timmer 	/* Reset egress port when no other mirror is active */
5428f0942e00SIwan R Timmer 	if (!other_mirrors) {
5429f0942e00SIwan R Timmer 		if (chip->info->ops->set_egress_port(chip,
5430f0942e00SIwan R Timmer 						     direction,
5431f0942e00SIwan R Timmer 						     dsa_upstream_port(ds,
54324e4637b1SColin Ian King 								       port)))
5433f0942e00SIwan R Timmer 			dev_err(ds->dev, "failed to set egress port\n");
5434f0942e00SIwan R Timmer 	}
5435f0942e00SIwan R Timmer 
5436f0942e00SIwan R Timmer 	mutex_unlock(&chip->reg_lock);
5437f0942e00SIwan R Timmer }
5438f0942e00SIwan R Timmer 
54394f85901fSRussell King static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
54404f85901fSRussell King 					 bool unicast, bool multicast)
54414f85901fSRussell King {
54424f85901fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
54434f85901fSRussell King 	int err = -EOPNOTSUPP;
54444f85901fSRussell King 
5445c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
54464f85901fSRussell King 	if (chip->info->ops->port_set_egress_floods)
54474f85901fSRussell King 		err = chip->info->ops->port_set_egress_floods(chip, port,
54484f85901fSRussell King 							      unicast,
54494f85901fSRussell King 							      multicast);
5450c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
54514f85901fSRussell King 
54524f85901fSRussell King 	return err;
54534f85901fSRussell King }
54544f85901fSRussell King 
5455a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
54567b314362SAndrew Lunn 	.get_tag_protocol	= mv88e6xxx_get_tag_protocol,
5457fad09c73SVivien Didelot 	.setup			= mv88e6xxx_setup,
545823e8b470SAndrew Lunn 	.teardown		= mv88e6xxx_teardown,
5459c9a2356fSRussell King 	.phylink_validate	= mv88e6xxx_validate,
5460c9a2356fSRussell King 	.phylink_mac_link_state	= mv88e6xxx_link_state,
5461c9a2356fSRussell King 	.phylink_mac_config	= mv88e6xxx_mac_config,
5462c9a2356fSRussell King 	.phylink_mac_link_down	= mv88e6xxx_mac_link_down,
5463c9a2356fSRussell King 	.phylink_mac_link_up	= mv88e6xxx_mac_link_up,
5464fad09c73SVivien Didelot 	.get_strings		= mv88e6xxx_get_strings,
5465fad09c73SVivien Didelot 	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
5466fad09c73SVivien Didelot 	.get_sset_count		= mv88e6xxx_get_sset_count,
546704aca993SAndrew Lunn 	.port_enable		= mv88e6xxx_port_enable,
546804aca993SAndrew Lunn 	.port_disable		= mv88e6xxx_port_disable,
546908f50061SVivien Didelot 	.get_mac_eee		= mv88e6xxx_get_mac_eee,
547008f50061SVivien Didelot 	.set_mac_eee		= mv88e6xxx_set_mac_eee,
5471fad09c73SVivien Didelot 	.get_eeprom_len		= mv88e6xxx_get_eeprom_len,
5472fad09c73SVivien Didelot 	.get_eeprom		= mv88e6xxx_get_eeprom,
5473fad09c73SVivien Didelot 	.set_eeprom		= mv88e6xxx_set_eeprom,
5474fad09c73SVivien Didelot 	.get_regs_len		= mv88e6xxx_get_regs_len,
5475fad09c73SVivien Didelot 	.get_regs		= mv88e6xxx_get_regs,
5476da7dc875SVivien Didelot 	.get_rxnfc		= mv88e6xxx_get_rxnfc,
5477da7dc875SVivien Didelot 	.set_rxnfc		= mv88e6xxx_set_rxnfc,
54782cfcd964SVivien Didelot 	.set_ageing_time	= mv88e6xxx_set_ageing_time,
5479fad09c73SVivien Didelot 	.port_bridge_join	= mv88e6xxx_port_bridge_join,
5480fad09c73SVivien Didelot 	.port_bridge_leave	= mv88e6xxx_port_bridge_leave,
54814f85901fSRussell King 	.port_egress_floods	= mv88e6xxx_port_egress_floods,
5482fad09c73SVivien Didelot 	.port_stp_state_set	= mv88e6xxx_port_stp_state_set,
5483749efcb8SVivien Didelot 	.port_fast_age		= mv88e6xxx_port_fast_age,
5484fad09c73SVivien Didelot 	.port_vlan_filtering	= mv88e6xxx_port_vlan_filtering,
5485fad09c73SVivien Didelot 	.port_vlan_prepare	= mv88e6xxx_port_vlan_prepare,
5486fad09c73SVivien Didelot 	.port_vlan_add		= mv88e6xxx_port_vlan_add,
5487fad09c73SVivien Didelot 	.port_vlan_del		= mv88e6xxx_port_vlan_del,
5488fad09c73SVivien Didelot 	.port_fdb_add           = mv88e6xxx_port_fdb_add,
5489fad09c73SVivien Didelot 	.port_fdb_del           = mv88e6xxx_port_fdb_del,
5490fad09c73SVivien Didelot 	.port_fdb_dump          = mv88e6xxx_port_fdb_dump,
54917df8fbddSVivien Didelot 	.port_mdb_prepare       = mv88e6xxx_port_mdb_prepare,
54927df8fbddSVivien Didelot 	.port_mdb_add           = mv88e6xxx_port_mdb_add,
54937df8fbddSVivien Didelot 	.port_mdb_del           = mv88e6xxx_port_mdb_del,
5494f0942e00SIwan R Timmer 	.port_mirror_add	= mv88e6xxx_port_mirror_add,
5495f0942e00SIwan R Timmer 	.port_mirror_del	= mv88e6xxx_port_mirror_del,
5496aec5ac88SVivien Didelot 	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
5497aec5ac88SVivien Didelot 	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
5498c6fe0ad2SBrandon Streiff 	.port_hwtstamp_set	= mv88e6xxx_port_hwtstamp_set,
5499c6fe0ad2SBrandon Streiff 	.port_hwtstamp_get	= mv88e6xxx_port_hwtstamp_get,
5500c6fe0ad2SBrandon Streiff 	.port_txtstamp		= mv88e6xxx_port_txtstamp,
5501c6fe0ad2SBrandon Streiff 	.port_rxtstamp		= mv88e6xxx_port_rxtstamp,
5502c6fe0ad2SBrandon Streiff 	.get_ts_info		= mv88e6xxx_get_ts_info,
550323e8b470SAndrew Lunn 	.devlink_param_get	= mv88e6xxx_devlink_param_get,
550423e8b470SAndrew Lunn 	.devlink_param_set	= mv88e6xxx_devlink_param_set,
5505fad09c73SVivien Didelot };
5506fad09c73SVivien Didelot 
550755ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
5508fad09c73SVivien Didelot {
5509fad09c73SVivien Didelot 	struct device *dev = chip->dev;
5510fad09c73SVivien Didelot 	struct dsa_switch *ds;
5511fad09c73SVivien Didelot 
55127e99e347SVivien Didelot 	ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
5513fad09c73SVivien Didelot 	if (!ds)
5514fad09c73SVivien Didelot 		return -ENOMEM;
5515fad09c73SVivien Didelot 
55167e99e347SVivien Didelot 	ds->dev = dev;
55177e99e347SVivien Didelot 	ds->num_ports = mv88e6xxx_num_ports(chip);
5518fad09c73SVivien Didelot 	ds->priv = chip;
5519877b7cb0SAndrew Lunn 	ds->dev = dev;
55209d490b4eSVivien Didelot 	ds->ops = &mv88e6xxx_switch_ops;
55219ff74f24SVivien Didelot 	ds->ageing_time_min = chip->info->age_time_coeff;
55229ff74f24SVivien Didelot 	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
5523fad09c73SVivien Didelot 
5524fad09c73SVivien Didelot 	dev_set_drvdata(dev, ds);
5525fad09c73SVivien Didelot 
552623c9ee49SVivien Didelot 	return dsa_register_switch(ds);
5527fad09c73SVivien Didelot }
5528fad09c73SVivien Didelot 
5529fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
5530fad09c73SVivien Didelot {
5531fad09c73SVivien Didelot 	dsa_unregister_switch(chip->ds);
5532fad09c73SVivien Didelot }
5533fad09c73SVivien Didelot 
5534877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev)
5535877b7cb0SAndrew Lunn {
5536877b7cb0SAndrew Lunn 	const struct of_device_id *matches = dev->driver->of_match_table;
5537877b7cb0SAndrew Lunn 	const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data;
5538877b7cb0SAndrew Lunn 
5539877b7cb0SAndrew Lunn 	for (; matches->name[0] || matches->type[0] || matches->compatible[0];
5540877b7cb0SAndrew Lunn 	     matches++) {
5541877b7cb0SAndrew Lunn 		if (!strcmp(pdata->compatible, matches->compatible))
5542877b7cb0SAndrew Lunn 			return matches->data;
5543877b7cb0SAndrew Lunn 	}
5544877b7cb0SAndrew Lunn 	return NULL;
5545877b7cb0SAndrew Lunn }
5546877b7cb0SAndrew Lunn 
5547bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration
5548bcd3d9d9SMiquel Raynal  * would be lost after a power cycle so prevent it to be suspended.
5549bcd3d9d9SMiquel Raynal  */
5550bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev)
5551bcd3d9d9SMiquel Raynal {
5552bcd3d9d9SMiquel Raynal 	return -EOPNOTSUPP;
5553bcd3d9d9SMiquel Raynal }
5554bcd3d9d9SMiquel Raynal 
5555bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev)
5556bcd3d9d9SMiquel Raynal {
5557bcd3d9d9SMiquel Raynal 	return 0;
5558bcd3d9d9SMiquel Raynal }
5559bcd3d9d9SMiquel Raynal 
5560bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume);
5561bcd3d9d9SMiquel Raynal 
5562fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev)
5563fad09c73SVivien Didelot {
5564877b7cb0SAndrew Lunn 	struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data;
55657ddae24fSDavid S. Miller 	const struct mv88e6xxx_info *compat_info = NULL;
5566fad09c73SVivien Didelot 	struct device *dev = &mdiodev->dev;
5567fad09c73SVivien Didelot 	struct device_node *np = dev->of_node;
5568fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
5569877b7cb0SAndrew Lunn 	int port;
5570fad09c73SVivien Didelot 	int err;
5571fad09c73SVivien Didelot 
55727bb8c996SAndrew Lunn 	if (!np && !pdata)
55737bb8c996SAndrew Lunn 		return -EINVAL;
55747bb8c996SAndrew Lunn 
5575877b7cb0SAndrew Lunn 	if (np)
5576fad09c73SVivien Didelot 		compat_info = of_device_get_match_data(dev);
5577877b7cb0SAndrew Lunn 
5578877b7cb0SAndrew Lunn 	if (pdata) {
5579877b7cb0SAndrew Lunn 		compat_info = pdata_device_get_match_data(dev);
5580877b7cb0SAndrew Lunn 
5581877b7cb0SAndrew Lunn 		if (!pdata->netdev)
5582877b7cb0SAndrew Lunn 			return -EINVAL;
5583877b7cb0SAndrew Lunn 
5584877b7cb0SAndrew Lunn 		for (port = 0; port < DSA_MAX_PORTS; port++) {
5585877b7cb0SAndrew Lunn 			if (!(pdata->enabled_ports & (1 << port)))
5586877b7cb0SAndrew Lunn 				continue;
5587877b7cb0SAndrew Lunn 			if (strcmp(pdata->cd.port_names[port], "cpu"))
5588877b7cb0SAndrew Lunn 				continue;
5589877b7cb0SAndrew Lunn 			pdata->cd.netdev[port] = &pdata->netdev->dev;
5590877b7cb0SAndrew Lunn 			break;
5591877b7cb0SAndrew Lunn 		}
5592877b7cb0SAndrew Lunn 	}
5593877b7cb0SAndrew Lunn 
5594fad09c73SVivien Didelot 	if (!compat_info)
5595fad09c73SVivien Didelot 		return -EINVAL;
5596fad09c73SVivien Didelot 
5597fad09c73SVivien Didelot 	chip = mv88e6xxx_alloc_chip(dev);
5598877b7cb0SAndrew Lunn 	if (!chip) {
5599877b7cb0SAndrew Lunn 		err = -ENOMEM;
5600877b7cb0SAndrew Lunn 		goto out;
5601877b7cb0SAndrew Lunn 	}
5602fad09c73SVivien Didelot 
5603fad09c73SVivien Didelot 	chip->info = compat_info;
5604fad09c73SVivien Didelot 
5605fad09c73SVivien Didelot 	err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
5606fad09c73SVivien Didelot 	if (err)
5607877b7cb0SAndrew Lunn 		goto out;
5608fad09c73SVivien Didelot 
5609b4308f04SAndrew Lunn 	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
5610877b7cb0SAndrew Lunn 	if (IS_ERR(chip->reset)) {
5611877b7cb0SAndrew Lunn 		err = PTR_ERR(chip->reset);
5612877b7cb0SAndrew Lunn 		goto out;
5613877b7cb0SAndrew Lunn 	}
56147b75e49dSBaruch Siach 	if (chip->reset)
56157b75e49dSBaruch Siach 		usleep_range(1000, 2000);
5616b4308f04SAndrew Lunn 
5617fad09c73SVivien Didelot 	err = mv88e6xxx_detect(chip);
5618fad09c73SVivien Didelot 	if (err)
5619877b7cb0SAndrew Lunn 		goto out;
5620fad09c73SVivien Didelot 
5621e57e5e77SVivien Didelot 	mv88e6xxx_phy_init(chip);
5622e57e5e77SVivien Didelot 
562300baabe5SAndrew Lunn 	if (chip->info->ops->get_eeprom) {
562400baabe5SAndrew Lunn 		if (np)
562500baabe5SAndrew Lunn 			of_property_read_u32(np, "eeprom-length",
562600baabe5SAndrew Lunn 					     &chip->eeprom_len);
562700baabe5SAndrew Lunn 		else
562800baabe5SAndrew Lunn 			chip->eeprom_len = pdata->eeprom_len;
562900baabe5SAndrew Lunn 	}
5630fad09c73SVivien Didelot 
5631c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5632dc30c35bSAndrew Lunn 	err = mv88e6xxx_switch_reset(chip);
5633c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
5634fad09c73SVivien Didelot 	if (err)
5635dc30c35bSAndrew Lunn 		goto out;
5636fad09c73SVivien Didelot 
5637a27415deSAndrew Lunn 	if (np) {
5638dc30c35bSAndrew Lunn 		chip->irq = of_irq_get(np, 0);
5639dc30c35bSAndrew Lunn 		if (chip->irq == -EPROBE_DEFER) {
5640dc30c35bSAndrew Lunn 			err = chip->irq;
5641dc30c35bSAndrew Lunn 			goto out;
5642fad09c73SVivien Didelot 		}
5643a27415deSAndrew Lunn 	}
5644a27415deSAndrew Lunn 
5645a27415deSAndrew Lunn 	if (pdata)
5646a27415deSAndrew Lunn 		chip->irq = pdata->irq;
5647fad09c73SVivien Didelot 
5648294d711eSAndrew Lunn 	/* Has to be performed before the MDIO bus is created, because
5649a708767eSUwe Kleine-König 	 * the PHYs will link their interrupts to these interrupt
5650294d711eSAndrew Lunn 	 * controllers
5651dc30c35bSAndrew Lunn 	 */
5652c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5653294d711eSAndrew Lunn 	if (chip->irq > 0)
5654dc30c35bSAndrew Lunn 		err = mv88e6xxx_g1_irq_setup(chip);
5655294d711eSAndrew Lunn 	else
5656294d711eSAndrew Lunn 		err = mv88e6xxx_irq_poll_setup(chip);
5657c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
5658dc30c35bSAndrew Lunn 
5659dc30c35bSAndrew Lunn 	if (err)
5660dc30c35bSAndrew Lunn 		goto out;
5661dc30c35bSAndrew Lunn 
5662d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0) {
5663dc30c35bSAndrew Lunn 		err = mv88e6xxx_g2_irq_setup(chip);
5664dc30c35bSAndrew Lunn 		if (err)
5665dc30c35bSAndrew Lunn 			goto out_g1_irq;
5666dc30c35bSAndrew Lunn 	}
56670977644cSAndrew Lunn 
56680977644cSAndrew Lunn 	err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
56690977644cSAndrew Lunn 	if (err)
56700977644cSAndrew Lunn 		goto out_g2_irq;
567162eb1162SAndrew Lunn 
567262eb1162SAndrew Lunn 	err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
567362eb1162SAndrew Lunn 	if (err)
567462eb1162SAndrew Lunn 		goto out_g1_atu_prob_irq;
5675dc30c35bSAndrew Lunn 
5676a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdios_register(chip, np);
5677dc30c35bSAndrew Lunn 	if (err)
567862eb1162SAndrew Lunn 		goto out_g1_vtu_prob_irq;
5679dc30c35bSAndrew Lunn 
568055ed0ce0SFlorian Fainelli 	err = mv88e6xxx_register_switch(chip);
5681dc30c35bSAndrew Lunn 	if (err)
5682dc30c35bSAndrew Lunn 		goto out_mdio;
5683dc30c35bSAndrew Lunn 
5684fad09c73SVivien Didelot 	return 0;
5685dc30c35bSAndrew Lunn 
5686dc30c35bSAndrew Lunn out_mdio:
5687a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
568862eb1162SAndrew Lunn out_g1_vtu_prob_irq:
568962eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
56900977644cSAndrew Lunn out_g1_atu_prob_irq:
56910977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
5692dc30c35bSAndrew Lunn out_g2_irq:
5693294d711eSAndrew Lunn 	if (chip->info->g2_irqs > 0)
5694dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
5695dc30c35bSAndrew Lunn out_g1_irq:
5696294d711eSAndrew Lunn 	if (chip->irq > 0)
5697dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
5698294d711eSAndrew Lunn 	else
5699294d711eSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
5700dc30c35bSAndrew Lunn out:
5701877b7cb0SAndrew Lunn 	if (pdata)
5702877b7cb0SAndrew Lunn 		dev_put(pdata->netdev);
5703877b7cb0SAndrew Lunn 
5704dc30c35bSAndrew Lunn 	return err;
5705fad09c73SVivien Didelot }
5706fad09c73SVivien Didelot 
5707fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev)
5708fad09c73SVivien Didelot {
5709fad09c73SVivien Didelot 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
571004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
5711fad09c73SVivien Didelot 
5712c6fe0ad2SBrandon Streiff 	if (chip->info->ptp_support) {
5713c6fe0ad2SBrandon Streiff 		mv88e6xxx_hwtstamp_free(chip);
57142fa8d3afSBrandon Streiff 		mv88e6xxx_ptp_free(chip);
5715c6fe0ad2SBrandon Streiff 	}
57162fa8d3afSBrandon Streiff 
5717930188ceSAndrew Lunn 	mv88e6xxx_phy_destroy(chip);
5718fad09c73SVivien Didelot 	mv88e6xxx_unregister_switch(chip);
5719a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
5720dc30c35bSAndrew Lunn 
572162eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
57220977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
572376f38f1fSAndrew Lunn 
5724d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0)
5725dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
572676f38f1fSAndrew Lunn 
572776f38f1fSAndrew Lunn 	if (chip->irq > 0)
5728dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
572976f38f1fSAndrew Lunn 	else
573076f38f1fSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
5731fad09c73SVivien Didelot }
5732fad09c73SVivien Didelot 
5733fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = {
5734fad09c73SVivien Didelot 	{
5735fad09c73SVivien Didelot 		.compatible = "marvell,mv88e6085",
5736fad09c73SVivien Didelot 		.data = &mv88e6xxx_table[MV88E6085],
5737fad09c73SVivien Didelot 	},
57381a3b39ecSAndrew Lunn 	{
57391a3b39ecSAndrew Lunn 		.compatible = "marvell,mv88e6190",
57401a3b39ecSAndrew Lunn 		.data = &mv88e6xxx_table[MV88E6190],
57411a3b39ecSAndrew Lunn 	},
57421f71836fSRasmus Villemoes 	{
57431f71836fSRasmus Villemoes 		.compatible = "marvell,mv88e6250",
57441f71836fSRasmus Villemoes 		.data = &mv88e6xxx_table[MV88E6250],
57451f71836fSRasmus Villemoes 	},
5746fad09c73SVivien Didelot 	{ /* sentinel */ },
5747fad09c73SVivien Didelot };
5748fad09c73SVivien Didelot 
5749fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);
5750fad09c73SVivien Didelot 
5751fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = {
5752fad09c73SVivien Didelot 	.probe	= mv88e6xxx_probe,
5753fad09c73SVivien Didelot 	.remove = mv88e6xxx_remove,
5754fad09c73SVivien Didelot 	.mdiodrv.driver = {
5755fad09c73SVivien Didelot 		.name = "mv88e6085",
5756fad09c73SVivien Didelot 		.of_match_table = mv88e6xxx_of_match,
5757bcd3d9d9SMiquel Raynal 		.pm = &mv88e6xxx_pm_ops,
5758fad09c73SVivien Didelot 	},
5759fad09c73SVivien Didelot };
5760fad09c73SVivien Didelot 
57617324d50eSAndrew Lunn mdio_module_driver(mv88e6xxx_driver);
5762fad09c73SVivien Didelot 
5763fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
5764fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
5765fad09c73SVivien Didelot MODULE_LICENSE("GPL");
5766