xref: /openbmc/linux/drivers/net/dsa/mv88e6xxx/chip.c (revision 34b5e6a3)
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 
422a5a6858bSRussell King static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
423a5a6858bSRussell King 				    int link, int speed, int duplex, int pause,
424d78343d2SVivien Didelot 				    phy_interface_t mode)
425d78343d2SVivien Didelot {
426d78343d2SVivien Didelot 	int err;
427d78343d2SVivien Didelot 
428d78343d2SVivien Didelot 	if (!chip->info->ops->port_set_link)
429d78343d2SVivien Didelot 		return 0;
430d78343d2SVivien Didelot 
431d78343d2SVivien Didelot 	/* Port's MAC control must not be changed unless the link is down */
43243c8e0aeSHubert Feurstein 	err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN);
433d78343d2SVivien Didelot 	if (err)
434d78343d2SVivien Didelot 		return err;
435d78343d2SVivien Didelot 
436f365c6f7SRussell King 	if (chip->info->ops->port_set_speed_duplex) {
437f365c6f7SRussell King 		err = chip->info->ops->port_set_speed_duplex(chip, port,
438f365c6f7SRussell King 							     speed, duplex);
439d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
440d78343d2SVivien Didelot 			goto restore_link;
441d78343d2SVivien Didelot 	}
442d78343d2SVivien Didelot 
4437cbbee05SAndrew Lunn 	if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode)
4447cbbee05SAndrew Lunn 		mode = chip->info->ops->port_max_speed_mode(port);
4457cbbee05SAndrew Lunn 
44654186b91SAndrew Lunn 	if (chip->info->ops->port_set_pause) {
44754186b91SAndrew Lunn 		err = chip->info->ops->port_set_pause(chip, port, pause);
44854186b91SAndrew Lunn 		if (err)
44954186b91SAndrew Lunn 			goto restore_link;
45054186b91SAndrew Lunn 	}
45154186b91SAndrew Lunn 
45264d47d50SRussell King 	err = mv88e6xxx_port_config_interface(chip, port, mode);
453d78343d2SVivien Didelot restore_link:
454d78343d2SVivien Didelot 	if (chip->info->ops->port_set_link(chip, port, link))
455774439e5SVivien Didelot 		dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
456d78343d2SVivien Didelot 
457d78343d2SVivien Didelot 	return err;
458d78343d2SVivien Didelot }
459d78343d2SVivien Didelot 
460d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
461d700ec41SMarek Vasut {
462d700ec41SMarek Vasut 	struct mv88e6xxx_chip *chip = ds->priv;
463d700ec41SMarek Vasut 
464d700ec41SMarek Vasut 	return port < chip->info->num_internal_phys;
465d700ec41SMarek Vasut }
466d700ec41SMarek Vasut 
4675d5b231dSRussell King static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port)
4685d5b231dSRussell King {
4695d5b231dSRussell King 	u16 reg;
4705d5b231dSRussell King 	int err;
4715d5b231dSRussell King 
4725d5b231dSRussell King 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
4735d5b231dSRussell King 	if (err) {
4745d5b231dSRussell King 		dev_err(chip->dev,
4755d5b231dSRussell King 			"p%d: %s: failed to read port status\n",
4765d5b231dSRussell King 			port, __func__);
4775d5b231dSRussell King 		return err;
4785d5b231dSRussell King 	}
4795d5b231dSRussell King 
4805d5b231dSRussell King 	return !!(reg & MV88E6XXX_PORT_STS_PHY_DETECT);
4815d5b231dSRussell King }
4825d5b231dSRussell King 
483a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port,
484a5a6858bSRussell King 					  struct phylink_link_state *state)
485a5a6858bSRussell King {
486a5a6858bSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
487a5a6858bSRussell King 	u8 lane;
488a5a6858bSRussell King 	int err;
489a5a6858bSRussell King 
490a5a6858bSRussell King 	mv88e6xxx_reg_lock(chip);
491a5a6858bSRussell King 	lane = mv88e6xxx_serdes_get_lane(chip, port);
492a5a6858bSRussell King 	if (lane && chip->info->ops->serdes_pcs_get_state)
493a5a6858bSRussell King 		err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
494a5a6858bSRussell King 							    state);
495a5a6858bSRussell King 	else
496a5a6858bSRussell King 		err = -EOPNOTSUPP;
497a5a6858bSRussell King 	mv88e6xxx_reg_unlock(chip);
498a5a6858bSRussell King 
499a5a6858bSRussell King 	return err;
500a5a6858bSRussell King }
501a5a6858bSRussell King 
502a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
503a5a6858bSRussell King 				       unsigned int mode,
504a5a6858bSRussell King 				       phy_interface_t interface,
505a5a6858bSRussell King 				       const unsigned long *advertise)
506a5a6858bSRussell King {
507a5a6858bSRussell King 	const struct mv88e6xxx_ops *ops = chip->info->ops;
508a5a6858bSRussell King 	u8 lane;
509a5a6858bSRussell King 
510a5a6858bSRussell King 	if (ops->serdes_pcs_config) {
511a5a6858bSRussell King 		lane = mv88e6xxx_serdes_get_lane(chip, port);
512a5a6858bSRussell King 		if (lane)
513a5a6858bSRussell King 			return ops->serdes_pcs_config(chip, port, lane, mode,
514a5a6858bSRussell King 						      interface, advertise);
515a5a6858bSRussell King 	}
516a5a6858bSRussell King 
517a5a6858bSRussell King 	return 0;
518a5a6858bSRussell King }
519a5a6858bSRussell King 
520a5a6858bSRussell King static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port)
521a5a6858bSRussell King {
522a5a6858bSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
523a5a6858bSRussell King 	const struct mv88e6xxx_ops *ops;
524a5a6858bSRussell King 	int err = 0;
525a5a6858bSRussell King 	u8 lane;
526a5a6858bSRussell King 
527a5a6858bSRussell King 	ops = chip->info->ops;
528a5a6858bSRussell King 
529a5a6858bSRussell King 	if (ops->serdes_pcs_an_restart) {
530a5a6858bSRussell King 		mv88e6xxx_reg_lock(chip);
531a5a6858bSRussell King 		lane = mv88e6xxx_serdes_get_lane(chip, port);
532a5a6858bSRussell King 		if (lane)
533a5a6858bSRussell King 			err = ops->serdes_pcs_an_restart(chip, port, lane);
534a5a6858bSRussell King 		mv88e6xxx_reg_unlock(chip);
535a5a6858bSRussell King 
536a5a6858bSRussell King 		if (err)
537a5a6858bSRussell King 			dev_err(ds->dev, "p%d: failed to restart AN\n", port);
538a5a6858bSRussell King 	}
539a5a6858bSRussell King }
540a5a6858bSRussell King 
541a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
542a5a6858bSRussell King 					unsigned int mode,
543a5a6858bSRussell King 					int speed, int duplex)
544a5a6858bSRussell King {
545a5a6858bSRussell King 	const struct mv88e6xxx_ops *ops = chip->info->ops;
546a5a6858bSRussell King 	u8 lane;
547a5a6858bSRussell King 
548a5a6858bSRussell King 	if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) {
549a5a6858bSRussell King 		lane = mv88e6xxx_serdes_get_lane(chip, port);
550a5a6858bSRussell King 		if (lane)
551a5a6858bSRussell King 			return ops->serdes_pcs_link_up(chip, port, lane,
552a5a6858bSRussell King 						       speed, duplex);
553a5a6858bSRussell King 	}
554a5a6858bSRussell King 
555a5a6858bSRussell King 	return 0;
556a5a6858bSRussell King }
557a5a6858bSRussell King 
5586c422e34SRussell King static void mv88e6065_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 (!phy_interface_mode_is_8023z(state->interface)) {
5636c422e34SRussell King 		/* 10M and 100M are only supported in non-802.3z mode */
5646c422e34SRussell King 		phylink_set(mask, 10baseT_Half);
5656c422e34SRussell King 		phylink_set(mask, 10baseT_Full);
5666c422e34SRussell King 		phylink_set(mask, 100baseT_Half);
5676c422e34SRussell King 		phylink_set(mask, 100baseT_Full);
5686c422e34SRussell King 	}
5696c422e34SRussell King }
5706c422e34SRussell King 
5716c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5726c422e34SRussell King 				       unsigned long *mask,
5736c422e34SRussell King 				       struct phylink_link_state *state)
5746c422e34SRussell King {
5756c422e34SRussell King 	/* FIXME: if the port is in 1000Base-X mode, then it only supports
5766c422e34SRussell King 	 * 1000M FD speeds.  In this case, CMODE will indicate 5.
5776c422e34SRussell King 	 */
5786c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
5796c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
5806c422e34SRussell King 
5816c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
5826c422e34SRussell King }
5836c422e34SRussell King 
584e3af71a3SMarek Behún static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port,
585e3af71a3SMarek Behún 				       unsigned long *mask,
586e3af71a3SMarek Behún 				       struct phylink_link_state *state)
587e3af71a3SMarek Behún {
588e3af71a3SMarek Behún 	if (port >= 5)
589e3af71a3SMarek Behún 		phylink_set(mask, 2500baseX_Full);
590e3af71a3SMarek Behún 
591e3af71a3SMarek Behún 	/* No ethtool bits for 200Mbps */
592e3af71a3SMarek Behún 	phylink_set(mask, 1000baseT_Full);
593e3af71a3SMarek Behún 	phylink_set(mask, 1000baseX_Full);
594e3af71a3SMarek Behún 
595e3af71a3SMarek Behún 	mv88e6065_phylink_validate(chip, port, mask, state);
596e3af71a3SMarek Behún }
597e3af71a3SMarek Behún 
5986c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5996c422e34SRussell King 				       unsigned long *mask,
6006c422e34SRussell King 				       struct phylink_link_state *state)
6016c422e34SRussell King {
6026c422e34SRussell King 	/* No ethtool bits for 200Mbps */
6036c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
6046c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
6056c422e34SRussell King 
6066c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
6076c422e34SRussell King }
6086c422e34SRussell King 
6096c422e34SRussell King static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6106c422e34SRussell King 				       unsigned long *mask,
6116c422e34SRussell King 				       struct phylink_link_state *state)
6126c422e34SRussell King {
613ec26016bSAndrew Lunn 	if (port >= 9) {
6146c422e34SRussell King 		phylink_set(mask, 2500baseX_Full);
615ec26016bSAndrew Lunn 		phylink_set(mask, 2500baseT_Full);
616ec26016bSAndrew Lunn 	}
6176c422e34SRussell King 
6186c422e34SRussell King 	/* No ethtool bits for 200Mbps */
6196c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
6206c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
6216c422e34SRussell King 
6226c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
6236c422e34SRussell King }
6246c422e34SRussell King 
6256c422e34SRussell King static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6266c422e34SRussell King 					unsigned long *mask,
6276c422e34SRussell King 					struct phylink_link_state *state)
6286c422e34SRussell King {
6296c422e34SRussell King 	if (port >= 9) {
6306c422e34SRussell King 		phylink_set(mask, 10000baseT_Full);
6316c422e34SRussell King 		phylink_set(mask, 10000baseKR_Full);
6326c422e34SRussell King 	}
6336c422e34SRussell King 
6346c422e34SRussell King 	mv88e6390_phylink_validate(chip, port, mask, state);
6356c422e34SRussell King }
6366c422e34SRussell King 
637c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
638c9a2356fSRussell King 			       unsigned long *supported,
639c9a2356fSRussell King 			       struct phylink_link_state *state)
640c9a2356fSRussell King {
6416c422e34SRussell King 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
6426c422e34SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
6436c422e34SRussell King 
6446c422e34SRussell King 	/* Allow all the expected bits */
6456c422e34SRussell King 	phylink_set(mask, Autoneg);
6466c422e34SRussell King 	phylink_set(mask, Pause);
6476c422e34SRussell King 	phylink_set_port_modes(mask);
6486c422e34SRussell King 
6496c422e34SRussell King 	if (chip->info->ops->phylink_validate)
6506c422e34SRussell King 		chip->info->ops->phylink_validate(chip, port, mask, state);
6516c422e34SRussell King 
6526c422e34SRussell King 	bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
6536c422e34SRussell King 	bitmap_and(state->advertising, state->advertising, mask,
6546c422e34SRussell King 		   __ETHTOOL_LINK_MODE_MASK_NBITS);
6556c422e34SRussell King 
6566c422e34SRussell King 	/* We can only operate at 2500BaseX or 1000BaseX.  If requested
6576c422e34SRussell King 	 * to advertise both, only report advertising at 2500BaseX.
6586c422e34SRussell King 	 */
6596c422e34SRussell King 	phylink_helper_basex_speed(state);
660c9a2356fSRussell King }
661c9a2356fSRussell King 
662c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
663c9a2356fSRussell King 				 unsigned int mode,
664c9a2356fSRussell King 				 const struct phylink_link_state *state)
665c9a2356fSRussell King {
666c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
66764d47d50SRussell King 	int err;
668c9a2356fSRussell King 
66964d47d50SRussell King 	/* FIXME: is this the correct test? If we're in fixed mode on an
67064d47d50SRussell King 	 * internal port, why should we process this any different from
67164d47d50SRussell King 	 * PHY mode? On the other hand, the port may be automedia between
67264d47d50SRussell King 	 * an internal PHY and the serdes...
67364d47d50SRussell King 	 */
674d700ec41SMarek Vasut 	if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port))
675c9a2356fSRussell King 		return;
676c9a2356fSRussell King 
677c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
67864d47d50SRussell King 	/* FIXME: should we force the link down here - but if we do, how
67964d47d50SRussell King 	 * do we restore the link force/unforce state? The driver layering
68064d47d50SRussell King 	 * gets in the way.
68164d47d50SRussell King 	 */
68264d47d50SRussell King 	err = mv88e6xxx_port_config_interface(chip, port, state->interface);
683a5a6858bSRussell King 	if (err && err != -EOPNOTSUPP)
684a5a6858bSRussell King 		goto err_unlock;
685a5a6858bSRussell King 
686a5a6858bSRussell King 	err = mv88e6xxx_serdes_pcs_config(chip, port, mode, state->interface,
687a5a6858bSRussell King 					  state->advertising);
688a5a6858bSRussell King 	/* FIXME: we should restart negotiation if something changed - which
689a5a6858bSRussell King 	 * is something we get if we convert to using phylinks PCS operations.
690a5a6858bSRussell King 	 */
691a5a6858bSRussell King 	if (err > 0)
692a5a6858bSRussell King 		err = 0;
693a5a6858bSRussell King 
694a5a6858bSRussell King err_unlock:
695c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
696c9a2356fSRussell King 
697c9a2356fSRussell King 	if (err && err != -EOPNOTSUPP)
69864d47d50SRussell King 		dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port);
699c9a2356fSRussell King }
700c9a2356fSRussell King 
701c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
702c9a2356fSRussell King 				    unsigned int mode,
703c9a2356fSRussell King 				    phy_interface_t interface)
704c9a2356fSRussell King {
70530c4a5b0SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
70630c4a5b0SRussell King 	const struct mv88e6xxx_ops *ops;
70730c4a5b0SRussell King 	int err = 0;
70830c4a5b0SRussell King 
70930c4a5b0SRussell King 	ops = chip->info->ops;
71030c4a5b0SRussell King 
71130c4a5b0SRussell King 	mv88e6xxx_reg_lock(chip);
71234b5e6a3SAndrew Lunn 	if ((!mv88e6xxx_port_ppu_updates(chip, port) ||
71334b5e6a3SAndrew Lunn 	     mode == MLO_AN_FIXED) && ops->port_set_link)
71430c4a5b0SRussell King 		err = ops->port_set_link(chip, port, LINK_FORCED_DOWN);
71530c4a5b0SRussell King 	mv88e6xxx_reg_unlock(chip);
71630c4a5b0SRussell King 
71730c4a5b0SRussell King 	if (err)
71830c4a5b0SRussell King 		dev_err(chip->dev,
71930c4a5b0SRussell King 			"p%d: failed to force MAC link down\n", port);
72030c4a5b0SRussell King }
721c9a2356fSRussell King 
722c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
723c9a2356fSRussell King 				  unsigned int mode, phy_interface_t interface,
7245b502a7bSRussell King 				  struct phy_device *phydev,
7255b502a7bSRussell King 				  int speed, int duplex,
7265b502a7bSRussell King 				  bool tx_pause, bool rx_pause)
727c9a2356fSRussell King {
72830c4a5b0SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
72930c4a5b0SRussell King 	const struct mv88e6xxx_ops *ops;
73030c4a5b0SRussell King 	int err = 0;
73130c4a5b0SRussell King 
73230c4a5b0SRussell King 	ops = chip->info->ops;
73330c4a5b0SRussell King 
73430c4a5b0SRussell King 	mv88e6xxx_reg_lock(chip);
73534b5e6a3SAndrew Lunn 	if (!mv88e6xxx_port_ppu_updates(chip, port) || mode == MLO_AN_FIXED) {
73630c4a5b0SRussell King 		/* FIXME: for an automedia port, should we force the link
73730c4a5b0SRussell King 		 * down here - what if the link comes up due to "other" media
73830c4a5b0SRussell King 		 * while we're bringing the port up, how is the exclusivity
739a5a6858bSRussell King 		 * handled in the Marvell hardware? E.g. port 2 on 88E6390
74030c4a5b0SRussell King 		 * shared between internal PHY and Serdes.
74130c4a5b0SRussell King 		 */
742a5a6858bSRussell King 		err = mv88e6xxx_serdes_pcs_link_up(chip, port, mode, speed,
743a5a6858bSRussell King 						   duplex);
744a5a6858bSRussell King 		if (err)
745a5a6858bSRussell King 			goto error;
746a5a6858bSRussell King 
747f365c6f7SRussell King 		if (ops->port_set_speed_duplex) {
748f365c6f7SRussell King 			err = ops->port_set_speed_duplex(chip, port,
749f365c6f7SRussell King 							 speed, duplex);
75030c4a5b0SRussell King 			if (err && err != -EOPNOTSUPP)
75130c4a5b0SRussell King 				goto error;
75230c4a5b0SRussell King 		}
75330c4a5b0SRussell King 
75430c4a5b0SRussell King 		if (ops->port_set_link)
75530c4a5b0SRussell King 			err = ops->port_set_link(chip, port, LINK_FORCED_UP);
7565d5b231dSRussell King 	}
75730c4a5b0SRussell King error:
75830c4a5b0SRussell King 	mv88e6xxx_reg_unlock(chip);
75930c4a5b0SRussell King 
76030c4a5b0SRussell King 	if (err && err != -EOPNOTSUPP)
76130c4a5b0SRussell King 		dev_err(ds->dev,
76230c4a5b0SRussell King 			"p%d: failed to configure MAC link up\n", port);
76330c4a5b0SRussell King }
764c9a2356fSRussell King 
765a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
766fad09c73SVivien Didelot {
767a605a0feSAndrew Lunn 	if (!chip->info->ops->stats_snapshot)
768a605a0feSAndrew Lunn 		return -EOPNOTSUPP;
769fad09c73SVivien Didelot 
770a605a0feSAndrew Lunn 	return chip->info->ops->stats_snapshot(chip, port);
771fad09c73SVivien Didelot }
772fad09c73SVivien Didelot 
773fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
774dfafe449SAndrew Lunn 	{ "in_good_octets",		8, 0x00, STATS_TYPE_BANK0, },
775dfafe449SAndrew Lunn 	{ "in_bad_octets",		4, 0x02, STATS_TYPE_BANK0, },
776dfafe449SAndrew Lunn 	{ "in_unicast",			4, 0x04, STATS_TYPE_BANK0, },
777dfafe449SAndrew Lunn 	{ "in_broadcasts",		4, 0x06, STATS_TYPE_BANK0, },
778dfafe449SAndrew Lunn 	{ "in_multicasts",		4, 0x07, STATS_TYPE_BANK0, },
779dfafe449SAndrew Lunn 	{ "in_pause",			4, 0x16, STATS_TYPE_BANK0, },
780dfafe449SAndrew Lunn 	{ "in_undersize",		4, 0x18, STATS_TYPE_BANK0, },
781dfafe449SAndrew Lunn 	{ "in_fragments",		4, 0x19, STATS_TYPE_BANK0, },
782dfafe449SAndrew Lunn 	{ "in_oversize",		4, 0x1a, STATS_TYPE_BANK0, },
783dfafe449SAndrew Lunn 	{ "in_jabber",			4, 0x1b, STATS_TYPE_BANK0, },
784dfafe449SAndrew Lunn 	{ "in_rx_error",		4, 0x1c, STATS_TYPE_BANK0, },
785dfafe449SAndrew Lunn 	{ "in_fcs_error",		4, 0x1d, STATS_TYPE_BANK0, },
786dfafe449SAndrew Lunn 	{ "out_octets",			8, 0x0e, STATS_TYPE_BANK0, },
787dfafe449SAndrew Lunn 	{ "out_unicast",		4, 0x10, STATS_TYPE_BANK0, },
788dfafe449SAndrew Lunn 	{ "out_broadcasts",		4, 0x13, STATS_TYPE_BANK0, },
789dfafe449SAndrew Lunn 	{ "out_multicasts",		4, 0x12, STATS_TYPE_BANK0, },
790dfafe449SAndrew Lunn 	{ "out_pause",			4, 0x15, STATS_TYPE_BANK0, },
791dfafe449SAndrew Lunn 	{ "excessive",			4, 0x11, STATS_TYPE_BANK0, },
792dfafe449SAndrew Lunn 	{ "collisions",			4, 0x1e, STATS_TYPE_BANK0, },
793dfafe449SAndrew Lunn 	{ "deferred",			4, 0x05, STATS_TYPE_BANK0, },
794dfafe449SAndrew Lunn 	{ "single",			4, 0x14, STATS_TYPE_BANK0, },
795dfafe449SAndrew Lunn 	{ "multiple",			4, 0x17, STATS_TYPE_BANK0, },
796dfafe449SAndrew Lunn 	{ "out_fcs_error",		4, 0x03, STATS_TYPE_BANK0, },
797dfafe449SAndrew Lunn 	{ "late",			4, 0x1f, STATS_TYPE_BANK0, },
798dfafe449SAndrew Lunn 	{ "hist_64bytes",		4, 0x08, STATS_TYPE_BANK0, },
799dfafe449SAndrew Lunn 	{ "hist_65_127bytes",		4, 0x09, STATS_TYPE_BANK0, },
800dfafe449SAndrew Lunn 	{ "hist_128_255bytes",		4, 0x0a, STATS_TYPE_BANK0, },
801dfafe449SAndrew Lunn 	{ "hist_256_511bytes",		4, 0x0b, STATS_TYPE_BANK0, },
802dfafe449SAndrew Lunn 	{ "hist_512_1023bytes",		4, 0x0c, STATS_TYPE_BANK0, },
803dfafe449SAndrew Lunn 	{ "hist_1024_max_bytes",	4, 0x0d, STATS_TYPE_BANK0, },
804dfafe449SAndrew Lunn 	{ "sw_in_discards",		4, 0x10, STATS_TYPE_PORT, },
805dfafe449SAndrew Lunn 	{ "sw_in_filtered",		2, 0x12, STATS_TYPE_PORT, },
806dfafe449SAndrew Lunn 	{ "sw_out_filtered",		2, 0x13, STATS_TYPE_PORT, },
807dfafe449SAndrew Lunn 	{ "in_discards",		4, 0x00, STATS_TYPE_BANK1, },
808dfafe449SAndrew Lunn 	{ "in_filtered",		4, 0x01, STATS_TYPE_BANK1, },
809dfafe449SAndrew Lunn 	{ "in_accepted",		4, 0x02, STATS_TYPE_BANK1, },
810dfafe449SAndrew Lunn 	{ "in_bad_accepted",		4, 0x03, STATS_TYPE_BANK1, },
811dfafe449SAndrew Lunn 	{ "in_good_avb_class_a",	4, 0x04, STATS_TYPE_BANK1, },
812dfafe449SAndrew Lunn 	{ "in_good_avb_class_b",	4, 0x05, STATS_TYPE_BANK1, },
813dfafe449SAndrew Lunn 	{ "in_bad_avb_class_a",		4, 0x06, STATS_TYPE_BANK1, },
814dfafe449SAndrew Lunn 	{ "in_bad_avb_class_b",		4, 0x07, STATS_TYPE_BANK1, },
815dfafe449SAndrew Lunn 	{ "tcam_counter_0",		4, 0x08, STATS_TYPE_BANK1, },
816dfafe449SAndrew Lunn 	{ "tcam_counter_1",		4, 0x09, STATS_TYPE_BANK1, },
817dfafe449SAndrew Lunn 	{ "tcam_counter_2",		4, 0x0a, STATS_TYPE_BANK1, },
818dfafe449SAndrew Lunn 	{ "tcam_counter_3",		4, 0x0b, STATS_TYPE_BANK1, },
819dfafe449SAndrew Lunn 	{ "in_da_unknown",		4, 0x0e, STATS_TYPE_BANK1, },
820dfafe449SAndrew Lunn 	{ "in_management",		4, 0x0f, STATS_TYPE_BANK1, },
821dfafe449SAndrew Lunn 	{ "out_queue_0",		4, 0x10, STATS_TYPE_BANK1, },
822dfafe449SAndrew Lunn 	{ "out_queue_1",		4, 0x11, STATS_TYPE_BANK1, },
823dfafe449SAndrew Lunn 	{ "out_queue_2",		4, 0x12, STATS_TYPE_BANK1, },
824dfafe449SAndrew Lunn 	{ "out_queue_3",		4, 0x13, STATS_TYPE_BANK1, },
825dfafe449SAndrew Lunn 	{ "out_queue_4",		4, 0x14, STATS_TYPE_BANK1, },
826dfafe449SAndrew Lunn 	{ "out_queue_5",		4, 0x15, STATS_TYPE_BANK1, },
827dfafe449SAndrew Lunn 	{ "out_queue_6",		4, 0x16, STATS_TYPE_BANK1, },
828dfafe449SAndrew Lunn 	{ "out_queue_7",		4, 0x17, STATS_TYPE_BANK1, },
829dfafe449SAndrew Lunn 	{ "out_cut_through",		4, 0x18, STATS_TYPE_BANK1, },
830dfafe449SAndrew Lunn 	{ "out_octets_a",		4, 0x1a, STATS_TYPE_BANK1, },
831dfafe449SAndrew Lunn 	{ "out_octets_b",		4, 0x1b, STATS_TYPE_BANK1, },
832dfafe449SAndrew Lunn 	{ "out_management",		4, 0x1f, STATS_TYPE_BANK1, },
833fad09c73SVivien Didelot };
834fad09c73SVivien Didelot 
835fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
836fad09c73SVivien Didelot 					    struct mv88e6xxx_hw_stat *s,
837e0d8b615SAndrew Lunn 					    int port, u16 bank1_select,
838e0d8b615SAndrew Lunn 					    u16 histogram)
839fad09c73SVivien Didelot {
840fad09c73SVivien Didelot 	u32 low;
841fad09c73SVivien Didelot 	u32 high = 0;
842dfafe449SAndrew Lunn 	u16 reg = 0;
8430e7b9925SAndrew Lunn 	int err;
844fad09c73SVivien Didelot 	u64 value;
845fad09c73SVivien Didelot 
846fad09c73SVivien Didelot 	switch (s->type) {
847dfafe449SAndrew Lunn 	case STATS_TYPE_PORT:
8480e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
8490e7b9925SAndrew Lunn 		if (err)
8506c3442f5SJisheng Zhang 			return U64_MAX;
851fad09c73SVivien Didelot 
8520e7b9925SAndrew Lunn 		low = reg;
853cda9f4aaSAndrew Lunn 		if (s->size == 4) {
8540e7b9925SAndrew Lunn 			err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
8550e7b9925SAndrew Lunn 			if (err)
8566c3442f5SJisheng Zhang 				return U64_MAX;
85784b3fd1fSRasmus Villemoes 			low |= ((u32)reg) << 16;
858fad09c73SVivien Didelot 		}
859fad09c73SVivien Didelot 		break;
860dfafe449SAndrew Lunn 	case STATS_TYPE_BANK1:
861e0d8b615SAndrew Lunn 		reg = bank1_select;
862dfafe449SAndrew Lunn 		/* fall through */
863dfafe449SAndrew Lunn 	case STATS_TYPE_BANK0:
864e0d8b615SAndrew Lunn 		reg |= s->reg | histogram;
8657f9ef3afSAndrew Lunn 		mv88e6xxx_g1_stats_read(chip, reg, &low);
866cda9f4aaSAndrew Lunn 		if (s->size == 8)
8677f9ef3afSAndrew Lunn 			mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
8689fc3e4dcSGustavo A. R. Silva 		break;
8699fc3e4dcSGustavo A. R. Silva 	default:
8706c3442f5SJisheng Zhang 		return U64_MAX;
871fad09c73SVivien Didelot 	}
8726e46e2d8SAndrew Lunn 	value = (((u64)high) << 32) | low;
873fad09c73SVivien Didelot 	return value;
874fad09c73SVivien Didelot }
875fad09c73SVivien Didelot 
876436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
877dfafe449SAndrew Lunn 				       uint8_t *data, int types)
878fad09c73SVivien Didelot {
879fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
880fad09c73SVivien Didelot 	int i, j;
881fad09c73SVivien Didelot 
882fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
883fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
884dfafe449SAndrew Lunn 		if (stat->type & types) {
885fad09c73SVivien Didelot 			memcpy(data + j * ETH_GSTRING_LEN, stat->string,
886fad09c73SVivien Didelot 			       ETH_GSTRING_LEN);
887fad09c73SVivien Didelot 			j++;
888fad09c73SVivien Didelot 		}
889fad09c73SVivien Didelot 	}
890436fe17dSAndrew Lunn 
891436fe17dSAndrew Lunn 	return j;
892fad09c73SVivien Didelot }
893fad09c73SVivien Didelot 
894436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
895dfafe449SAndrew Lunn 				       uint8_t *data)
896dfafe449SAndrew Lunn {
897436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
898dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_PORT);
899dfafe449SAndrew Lunn }
900dfafe449SAndrew Lunn 
9011f71836fSRasmus Villemoes static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip,
9021f71836fSRasmus Villemoes 				       uint8_t *data)
9031f71836fSRasmus Villemoes {
9041f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0);
9051f71836fSRasmus Villemoes }
9061f71836fSRasmus Villemoes 
907436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
908dfafe449SAndrew Lunn 				       uint8_t *data)
909dfafe449SAndrew Lunn {
910436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
911dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
912dfafe449SAndrew Lunn }
913dfafe449SAndrew Lunn 
91465f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = {
91565f60e45SAndrew Lunn 	"atu_member_violation",
91665f60e45SAndrew Lunn 	"atu_miss_violation",
91765f60e45SAndrew Lunn 	"atu_full_violation",
91865f60e45SAndrew Lunn 	"vtu_member_violation",
91965f60e45SAndrew Lunn 	"vtu_miss_violation",
92065f60e45SAndrew Lunn };
92165f60e45SAndrew Lunn 
92265f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data)
92365f60e45SAndrew Lunn {
92465f60e45SAndrew Lunn 	unsigned int i;
92565f60e45SAndrew Lunn 
92665f60e45SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++)
92765f60e45SAndrew Lunn 		strlcpy(data + i * ETH_GSTRING_LEN,
92865f60e45SAndrew Lunn 			mv88e6xxx_atu_vtu_stats_strings[i],
92965f60e45SAndrew Lunn 			ETH_GSTRING_LEN);
93065f60e45SAndrew Lunn }
93165f60e45SAndrew Lunn 
932dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
93389f09048SFlorian Fainelli 				  u32 stringset, uint8_t *data)
934fad09c73SVivien Didelot {
93504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
936436fe17dSAndrew Lunn 	int count = 0;
937dfafe449SAndrew Lunn 
93889f09048SFlorian Fainelli 	if (stringset != ETH_SS_STATS)
93989f09048SFlorian Fainelli 		return;
94089f09048SFlorian Fainelli 
941c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
942c6c8cd5eSAndrew Lunn 
943dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_strings)
944436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_strings(chip, data);
945436fe17dSAndrew Lunn 
946436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_strings) {
947436fe17dSAndrew Lunn 		data += count * ETH_GSTRING_LEN;
94865f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_strings(chip, port, data);
949436fe17dSAndrew Lunn 	}
950c6c8cd5eSAndrew Lunn 
95165f60e45SAndrew Lunn 	data += count * ETH_GSTRING_LEN;
95265f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_strings(data);
95365f60e45SAndrew Lunn 
954c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
955dfafe449SAndrew Lunn }
956dfafe449SAndrew Lunn 
957dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
958dfafe449SAndrew Lunn 					  int types)
959dfafe449SAndrew Lunn {
960fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
961fad09c73SVivien Didelot 	int i, j;
962fad09c73SVivien Didelot 
963fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
964fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
965dfafe449SAndrew Lunn 		if (stat->type & types)
966fad09c73SVivien Didelot 			j++;
967fad09c73SVivien Didelot 	}
968fad09c73SVivien Didelot 	return j;
969fad09c73SVivien Didelot }
970fad09c73SVivien Didelot 
971dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
972dfafe449SAndrew Lunn {
973dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
974dfafe449SAndrew Lunn 					      STATS_TYPE_PORT);
975dfafe449SAndrew Lunn }
976dfafe449SAndrew Lunn 
9771f71836fSRasmus Villemoes static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip)
9781f71836fSRasmus Villemoes {
9791f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0);
9801f71836fSRasmus Villemoes }
9811f71836fSRasmus Villemoes 
982dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
983dfafe449SAndrew Lunn {
984dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
985dfafe449SAndrew Lunn 					      STATS_TYPE_BANK1);
986dfafe449SAndrew Lunn }
987dfafe449SAndrew Lunn 
98889f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
989dfafe449SAndrew Lunn {
990dfafe449SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
991436fe17dSAndrew Lunn 	int serdes_count = 0;
992436fe17dSAndrew Lunn 	int count = 0;
993dfafe449SAndrew Lunn 
99489f09048SFlorian Fainelli 	if (sset != ETH_SS_STATS)
99589f09048SFlorian Fainelli 		return 0;
99689f09048SFlorian Fainelli 
997c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
998dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_sset_count)
999436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_sset_count(chip);
1000436fe17dSAndrew Lunn 	if (count < 0)
1001436fe17dSAndrew Lunn 		goto out;
1002436fe17dSAndrew Lunn 
1003436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_sset_count)
1004436fe17dSAndrew Lunn 		serdes_count = chip->info->ops->serdes_get_sset_count(chip,
1005436fe17dSAndrew Lunn 								      port);
100665f60e45SAndrew Lunn 	if (serdes_count < 0) {
1007436fe17dSAndrew Lunn 		count = serdes_count;
100865f60e45SAndrew Lunn 		goto out;
100965f60e45SAndrew Lunn 	}
1010436fe17dSAndrew Lunn 	count += serdes_count;
101165f60e45SAndrew Lunn 	count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings);
101265f60e45SAndrew Lunn 
1013436fe17dSAndrew Lunn out:
1014c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1015dfafe449SAndrew Lunn 
1016436fe17dSAndrew Lunn 	return count;
1017dfafe449SAndrew Lunn }
1018dfafe449SAndrew Lunn 
1019436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1020e0d8b615SAndrew Lunn 				     uint64_t *data, int types,
1021e0d8b615SAndrew Lunn 				     u16 bank1_select, u16 histogram)
1022052f947fSAndrew Lunn {
1023052f947fSAndrew Lunn 	struct mv88e6xxx_hw_stat *stat;
1024052f947fSAndrew Lunn 	int i, j;
1025052f947fSAndrew Lunn 
1026052f947fSAndrew Lunn 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
1027052f947fSAndrew Lunn 		stat = &mv88e6xxx_hw_stats[i];
1028052f947fSAndrew Lunn 		if (stat->type & types) {
1029c9acece0SRasmus Villemoes 			mv88e6xxx_reg_lock(chip);
1030e0d8b615SAndrew Lunn 			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
1031e0d8b615SAndrew Lunn 							      bank1_select,
1032e0d8b615SAndrew Lunn 							      histogram);
1033c9acece0SRasmus Villemoes 			mv88e6xxx_reg_unlock(chip);
1034377cda13SAndrew Lunn 
1035052f947fSAndrew Lunn 			j++;
1036052f947fSAndrew Lunn 		}
1037052f947fSAndrew Lunn 	}
1038436fe17dSAndrew Lunn 	return j;
1039052f947fSAndrew Lunn }
1040052f947fSAndrew Lunn 
1041436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1042052f947fSAndrew Lunn 				     uint64_t *data)
1043052f947fSAndrew Lunn {
1044052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1045e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
104657d1ef38SVivien Didelot 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1047052f947fSAndrew Lunn }
1048052f947fSAndrew Lunn 
10491f71836fSRasmus Villemoes static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
10501f71836fSRasmus Villemoes 				     uint64_t *data)
10511f71836fSRasmus Villemoes {
10521f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0,
10531f71836fSRasmus Villemoes 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
10541f71836fSRasmus Villemoes }
10551f71836fSRasmus Villemoes 
1056436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1057052f947fSAndrew Lunn 				     uint64_t *data)
1058052f947fSAndrew Lunn {
1059052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1060e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
106157d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
106257d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1063e0d8b615SAndrew Lunn }
1064e0d8b615SAndrew Lunn 
1065436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1066e0d8b615SAndrew Lunn 				     uint64_t *data)
1067e0d8b615SAndrew Lunn {
1068e0d8b615SAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1069e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
107057d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
107157d1ef38SVivien Didelot 					 0);
1072052f947fSAndrew Lunn }
1073052f947fSAndrew Lunn 
107465f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
107565f60e45SAndrew Lunn 					uint64_t *data)
107665f60e45SAndrew Lunn {
107765f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_member_violation;
107865f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_miss_violation;
107965f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_full_violation;
108065f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_member_violation;
108165f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_miss_violation;
108265f60e45SAndrew Lunn }
108365f60e45SAndrew Lunn 
1084052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
1085052f947fSAndrew Lunn 				uint64_t *data)
1086052f947fSAndrew Lunn {
1087436fe17dSAndrew Lunn 	int count = 0;
1088436fe17dSAndrew Lunn 
1089052f947fSAndrew Lunn 	if (chip->info->ops->stats_get_stats)
1090436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_stats(chip, port, data);
1091436fe17dSAndrew Lunn 
1092c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1093436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_stats) {
1094436fe17dSAndrew Lunn 		data += count;
109565f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_stats(chip, port, data);
1096436fe17dSAndrew Lunn 	}
109765f60e45SAndrew Lunn 	data += count;
109865f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_stats(chip, port, data);
1099c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1100052f947fSAndrew Lunn }
1101052f947fSAndrew Lunn 
1102fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
1103fad09c73SVivien Didelot 					uint64_t *data)
1104fad09c73SVivien Didelot {
110504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1106fad09c73SVivien Didelot 	int ret;
1107fad09c73SVivien Didelot 
1108c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1109fad09c73SVivien Didelot 
1110a605a0feSAndrew Lunn 	ret = mv88e6xxx_stats_snapshot(chip, port);
1111c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1112377cda13SAndrew Lunn 
1113377cda13SAndrew Lunn 	if (ret < 0)
1114fad09c73SVivien Didelot 		return;
1115052f947fSAndrew Lunn 
1116052f947fSAndrew Lunn 	mv88e6xxx_get_stats(chip, port, data);
1117fad09c73SVivien Didelot 
1118fad09c73SVivien Didelot }
1119fad09c73SVivien Didelot 
1120fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
1121fad09c73SVivien Didelot {
11220d30bbd0SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
11230d30bbd0SAndrew Lunn 	int len;
11240d30bbd0SAndrew Lunn 
11250d30bbd0SAndrew Lunn 	len = 32 * sizeof(u16);
11260d30bbd0SAndrew Lunn 	if (chip->info->ops->serdes_get_regs_len)
11270d30bbd0SAndrew Lunn 		len += chip->info->ops->serdes_get_regs_len(chip, port);
11280d30bbd0SAndrew Lunn 
11290d30bbd0SAndrew Lunn 	return len;
1130fad09c73SVivien Didelot }
1131fad09c73SVivien Didelot 
1132fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
1133fad09c73SVivien Didelot 			       struct ethtool_regs *regs, void *_p)
1134fad09c73SVivien Didelot {
113504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
11360e7b9925SAndrew Lunn 	int err;
11370e7b9925SAndrew Lunn 	u16 reg;
1138fad09c73SVivien Didelot 	u16 *p = _p;
1139fad09c73SVivien Didelot 	int i;
1140fad09c73SVivien Didelot 
1141a5f39326SVivien Didelot 	regs->version = chip->info->prod_num;
1142fad09c73SVivien Didelot 
1143fad09c73SVivien Didelot 	memset(p, 0xff, 32 * sizeof(u16));
1144fad09c73SVivien Didelot 
1145c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1146fad09c73SVivien Didelot 
1147fad09c73SVivien Didelot 	for (i = 0; i < 32; i++) {
1148fad09c73SVivien Didelot 
11490e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, i, &reg);
11500e7b9925SAndrew Lunn 		if (!err)
11510e7b9925SAndrew Lunn 			p[i] = reg;
1152fad09c73SVivien Didelot 	}
1153fad09c73SVivien Didelot 
11540d30bbd0SAndrew Lunn 	if (chip->info->ops->serdes_get_regs)
11550d30bbd0SAndrew Lunn 		chip->info->ops->serdes_get_regs(chip, port, &p[i]);
11560d30bbd0SAndrew Lunn 
1157c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1158fad09c73SVivien Didelot }
1159fad09c73SVivien Didelot 
116008f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
1161fad09c73SVivien Didelot 				 struct ethtool_eee *e)
1162fad09c73SVivien Didelot {
11635480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
11645480db69SVivien Didelot 	return 0;
1165fad09c73SVivien Didelot }
1166fad09c73SVivien Didelot 
116708f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port,
116846587e4aSVivien Didelot 				 struct ethtool_eee *e)
1169fad09c73SVivien Didelot {
11705480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
11715480db69SVivien Didelot 	return 0;
1172fad09c73SVivien Didelot }
1173fad09c73SVivien Didelot 
11749dc8b13eSVivien Didelot /* Mask of the local ports allowed to receive frames from a given fabric port */
1175e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
1176fad09c73SVivien Didelot {
11779dc8b13eSVivien Didelot 	struct dsa_switch *ds = chip->ds;
11789dc8b13eSVivien Didelot 	struct dsa_switch_tree *dst = ds->dst;
1179e5887a2aSVivien Didelot 	struct net_device *br;
11809dc8b13eSVivien Didelot 	struct dsa_port *dp;
11819dc8b13eSVivien Didelot 	bool found = false;
1182e5887a2aSVivien Didelot 	u16 pvlan;
1183fad09c73SVivien Didelot 
11849dc8b13eSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list) {
11859dc8b13eSVivien Didelot 		if (dp->ds->index == dev && dp->index == port) {
11869dc8b13eSVivien Didelot 			found = true;
11879dc8b13eSVivien Didelot 			break;
11889dc8b13eSVivien Didelot 		}
11899dc8b13eSVivien Didelot 	}
1190fad09c73SVivien Didelot 
1191e5887a2aSVivien Didelot 	/* Prevent frames from unknown switch or port */
11929dc8b13eSVivien Didelot 	if (!found)
1193e5887a2aSVivien Didelot 		return 0;
1194e5887a2aSVivien Didelot 
1195e5887a2aSVivien Didelot 	/* Frames from DSA links and CPU ports can egress any local port */
11969dc8b13eSVivien Didelot 	if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA)
1197e5887a2aSVivien Didelot 		return mv88e6xxx_port_mask(chip);
1198e5887a2aSVivien Didelot 
11999dc8b13eSVivien Didelot 	br = dp->bridge_dev;
1200e5887a2aSVivien Didelot 	pvlan = 0;
1201e5887a2aSVivien Didelot 
1202e5887a2aSVivien Didelot 	/* Frames from user ports can egress any local DSA links and CPU ports,
1203e5887a2aSVivien Didelot 	 * as well as any local member of their bridge group.
1204e5887a2aSVivien Didelot 	 */
12059dc8b13eSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list)
12069dc8b13eSVivien Didelot 		if (dp->ds == ds &&
12079dc8b13eSVivien Didelot 		    (dp->type == DSA_PORT_TYPE_CPU ||
12089dc8b13eSVivien Didelot 		     dp->type == DSA_PORT_TYPE_DSA ||
12099dc8b13eSVivien Didelot 		     (br && dp->bridge_dev == br)))
12109dc8b13eSVivien Didelot 			pvlan |= BIT(dp->index);
1211e5887a2aSVivien Didelot 
1212e5887a2aSVivien Didelot 	return pvlan;
1213fad09c73SVivien Didelot }
1214e5887a2aSVivien Didelot 
1215240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port)
1216e5887a2aSVivien Didelot {
1217e5887a2aSVivien Didelot 	u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port);
1218fad09c73SVivien Didelot 
1219fad09c73SVivien Didelot 	/* prevent frames from going back out of the port they came in on */
1220fad09c73SVivien Didelot 	output_ports &= ~BIT(port);
1221fad09c73SVivien Didelot 
12225a7921f4SVivien Didelot 	return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
1223fad09c73SVivien Didelot }
1224fad09c73SVivien Didelot 
1225fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
1226fad09c73SVivien Didelot 					 u8 state)
1227fad09c73SVivien Didelot {
122804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1229fad09c73SVivien Didelot 	int err;
1230fad09c73SVivien Didelot 
1231c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1232f894c29cSVivien Didelot 	err = mv88e6xxx_port_set_state(chip, port, state);
1233c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1234fad09c73SVivien Didelot 
1235fad09c73SVivien Didelot 	if (err)
1236774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to update state\n", port);
1237fad09c73SVivien Didelot }
1238fad09c73SVivien Didelot 
123993e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip)
124093e18d61SVivien Didelot {
124193e18d61SVivien Didelot 	int err;
124293e18d61SVivien Didelot 
124393e18d61SVivien Didelot 	if (chip->info->ops->ieee_pri_map) {
124493e18d61SVivien Didelot 		err = chip->info->ops->ieee_pri_map(chip);
124593e18d61SVivien Didelot 		if (err)
124693e18d61SVivien Didelot 			return err;
124793e18d61SVivien Didelot 	}
124893e18d61SVivien Didelot 
124993e18d61SVivien Didelot 	if (chip->info->ops->ip_pri_map) {
125093e18d61SVivien Didelot 		err = chip->info->ops->ip_pri_map(chip);
125193e18d61SVivien Didelot 		if (err)
125293e18d61SVivien Didelot 			return err;
125393e18d61SVivien Didelot 	}
125493e18d61SVivien Didelot 
125593e18d61SVivien Didelot 	return 0;
125693e18d61SVivien Didelot }
125793e18d61SVivien Didelot 
1258c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
1259c7f047b6SVivien Didelot {
1260c5f51765SVivien Didelot 	struct dsa_switch *ds = chip->ds;
1261c7f047b6SVivien Didelot 	int target, port;
1262c7f047b6SVivien Didelot 	int err;
1263c7f047b6SVivien Didelot 
1264c7f047b6SVivien Didelot 	if (!chip->info->global2_addr)
1265c7f047b6SVivien Didelot 		return 0;
1266c7f047b6SVivien Didelot 
1267c7f047b6SVivien Didelot 	/* Initialize the routing port to the 32 possible target devices */
1268c7f047b6SVivien Didelot 	for (target = 0; target < 32; target++) {
1269c5f51765SVivien Didelot 		port = dsa_routing_port(ds, target);
1270c5f51765SVivien Didelot 		if (port == ds->num_ports)
1271c7f047b6SVivien Didelot 			port = 0x1f;
1272c7f047b6SVivien Didelot 
1273c7f047b6SVivien Didelot 		err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
1274c7f047b6SVivien Didelot 		if (err)
1275c7f047b6SVivien Didelot 			return err;
1276c7f047b6SVivien Didelot 	}
1277c7f047b6SVivien Didelot 
127802317e68SVivien Didelot 	if (chip->info->ops->set_cascade_port) {
127902317e68SVivien Didelot 		port = MV88E6XXX_CASCADE_PORT_MULTIPLE;
128002317e68SVivien Didelot 		err = chip->info->ops->set_cascade_port(chip, port);
128102317e68SVivien Didelot 		if (err)
128202317e68SVivien Didelot 			return err;
128302317e68SVivien Didelot 	}
128402317e68SVivien Didelot 
128523c98919SVivien Didelot 	err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index);
128623c98919SVivien Didelot 	if (err)
128723c98919SVivien Didelot 		return err;
128823c98919SVivien Didelot 
1289c7f047b6SVivien Didelot 	return 0;
1290c7f047b6SVivien Didelot }
1291c7f047b6SVivien Didelot 
1292b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip)
1293b28f872dSVivien Didelot {
1294b28f872dSVivien Didelot 	/* Clear all trunk masks and mapping */
1295b28f872dSVivien Didelot 	if (chip->info->global2_addr)
1296b28f872dSVivien Didelot 		return mv88e6xxx_g2_trunk_clear(chip);
1297b28f872dSVivien Didelot 
1298b28f872dSVivien Didelot 	return 0;
1299b28f872dSVivien Didelot }
1300b28f872dSVivien Didelot 
13019e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
13029e5baf9bSVivien Didelot {
13039e5baf9bSVivien Didelot 	if (chip->info->ops->rmu_disable)
13049e5baf9bSVivien Didelot 		return chip->info->ops->rmu_disable(chip);
13059e5baf9bSVivien Didelot 
13069e5baf9bSVivien Didelot 	return 0;
13079e5baf9bSVivien Didelot }
13089e5baf9bSVivien Didelot 
13099e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
13109e907d73SVivien Didelot {
13119e907d73SVivien Didelot 	if (chip->info->ops->pot_clear)
13129e907d73SVivien Didelot 		return chip->info->ops->pot_clear(chip);
13139e907d73SVivien Didelot 
13149e907d73SVivien Didelot 	return 0;
13159e907d73SVivien Didelot }
13169e907d73SVivien Didelot 
131751c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip)
131851c901a7SVivien Didelot {
131951c901a7SVivien Didelot 	if (chip->info->ops->mgmt_rsvd2cpu)
132051c901a7SVivien Didelot 		return chip->info->ops->mgmt_rsvd2cpu(chip);
132151c901a7SVivien Didelot 
132251c901a7SVivien Didelot 	return 0;
132351c901a7SVivien Didelot }
132451c901a7SVivien Didelot 
1325a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
1326a2ac29d2SVivien Didelot {
1327c3a7d4adSVivien Didelot 	int err;
1328c3a7d4adSVivien Didelot 
1329daefc943SVivien Didelot 	err = mv88e6xxx_g1_atu_flush(chip, 0, true);
1330daefc943SVivien Didelot 	if (err)
1331daefc943SVivien Didelot 		return err;
1332daefc943SVivien Didelot 
1333c3a7d4adSVivien Didelot 	err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
1334c3a7d4adSVivien Didelot 	if (err)
1335c3a7d4adSVivien Didelot 		return err;
1336c3a7d4adSVivien Didelot 
1337a2ac29d2SVivien Didelot 	return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
1338a2ac29d2SVivien Didelot }
1339a2ac29d2SVivien Didelot 
1340cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip)
1341cd8da8bbSVivien Didelot {
1342cd8da8bbSVivien Didelot 	int port;
1343cd8da8bbSVivien Didelot 	int err;
1344cd8da8bbSVivien Didelot 
1345cd8da8bbSVivien Didelot 	if (!chip->info->ops->irl_init_all)
1346cd8da8bbSVivien Didelot 		return 0;
1347cd8da8bbSVivien Didelot 
1348cd8da8bbSVivien Didelot 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
1349cd8da8bbSVivien Didelot 		/* Disable ingress rate limiting by resetting all per port
1350cd8da8bbSVivien Didelot 		 * ingress rate limit resources to their initial state.
1351cd8da8bbSVivien Didelot 		 */
1352cd8da8bbSVivien Didelot 		err = chip->info->ops->irl_init_all(chip, port);
1353cd8da8bbSVivien Didelot 		if (err)
1354cd8da8bbSVivien Didelot 			return err;
1355cd8da8bbSVivien Didelot 	}
1356cd8da8bbSVivien Didelot 
1357cd8da8bbSVivien Didelot 	return 0;
1358cd8da8bbSVivien Didelot }
1359cd8da8bbSVivien Didelot 
136004a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip)
136104a69a17SVivien Didelot {
136204a69a17SVivien Didelot 	if (chip->info->ops->set_switch_mac) {
136304a69a17SVivien Didelot 		u8 addr[ETH_ALEN];
136404a69a17SVivien Didelot 
136504a69a17SVivien Didelot 		eth_random_addr(addr);
136604a69a17SVivien Didelot 
136704a69a17SVivien Didelot 		return chip->info->ops->set_switch_mac(chip, addr);
136804a69a17SVivien Didelot 	}
136904a69a17SVivien Didelot 
137004a69a17SVivien Didelot 	return 0;
137104a69a17SVivien Didelot }
137204a69a17SVivien Didelot 
137317a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
137417a1594eSVivien Didelot {
137517a1594eSVivien Didelot 	u16 pvlan = 0;
137617a1594eSVivien Didelot 
137717a1594eSVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
1378d14939beSVivien Didelot 		return 0;
137917a1594eSVivien Didelot 
138017a1594eSVivien Didelot 	/* Skip the local source device, which uses in-chip port VLAN */
138117a1594eSVivien Didelot 	if (dev != chip->ds->index)
1382aec5ac88SVivien Didelot 		pvlan = mv88e6xxx_port_vlan(chip, dev, port);
138317a1594eSVivien Didelot 
138417a1594eSVivien Didelot 	return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
138517a1594eSVivien Didelot }
138617a1594eSVivien Didelot 
138781228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
138881228996SVivien Didelot {
138917a1594eSVivien Didelot 	int dev, port;
139017a1594eSVivien Didelot 	int err;
139117a1594eSVivien Didelot 
139281228996SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
139381228996SVivien Didelot 		return 0;
139481228996SVivien Didelot 
139581228996SVivien Didelot 	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
139681228996SVivien Didelot 	 * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
139781228996SVivien Didelot 	 */
139817a1594eSVivien Didelot 	err = mv88e6xxx_g2_misc_4_bit_port(chip);
139917a1594eSVivien Didelot 	if (err)
140017a1594eSVivien Didelot 		return err;
140117a1594eSVivien Didelot 
140217a1594eSVivien Didelot 	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) {
140317a1594eSVivien Didelot 		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) {
140417a1594eSVivien Didelot 			err = mv88e6xxx_pvt_map(chip, dev, port);
140517a1594eSVivien Didelot 			if (err)
140617a1594eSVivien Didelot 				return err;
140717a1594eSVivien Didelot 		}
140817a1594eSVivien Didelot 	}
140917a1594eSVivien Didelot 
141017a1594eSVivien Didelot 	return 0;
141181228996SVivien Didelot }
141281228996SVivien Didelot 
1413749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
1414749efcb8SVivien Didelot {
1415749efcb8SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1416749efcb8SVivien Didelot 	int err;
1417749efcb8SVivien Didelot 
1418c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1419e606ca36SVivien Didelot 	err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
1420c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1421749efcb8SVivien Didelot 
1422749efcb8SVivien Didelot 	if (err)
1423774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to flush ATU\n", port);
1424749efcb8SVivien Didelot }
1425749efcb8SVivien Didelot 
1426b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)
1427b486d7c9SVivien Didelot {
1428b486d7c9SVivien Didelot 	if (!chip->info->max_vid)
1429b486d7c9SVivien Didelot 		return 0;
1430b486d7c9SVivien Didelot 
1431b486d7c9SVivien Didelot 	return mv88e6xxx_g1_vtu_flush(chip);
1432b486d7c9SVivien Didelot }
1433b486d7c9SVivien Didelot 
1434f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,
1435f1394b78SVivien Didelot 				 struct mv88e6xxx_vtu_entry *entry)
1436f1394b78SVivien Didelot {
1437f1394b78SVivien Didelot 	if (!chip->info->ops->vtu_getnext)
1438f1394b78SVivien Didelot 		return -EOPNOTSUPP;
1439f1394b78SVivien Didelot 
1440f1394b78SVivien Didelot 	return chip->info->ops->vtu_getnext(chip, entry);
1441f1394b78SVivien Didelot }
1442f1394b78SVivien Didelot 
14430ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
14440ad5daf6SVivien Didelot 				   struct mv88e6xxx_vtu_entry *entry)
14450ad5daf6SVivien Didelot {
14460ad5daf6SVivien Didelot 	if (!chip->info->ops->vtu_loadpurge)
14470ad5daf6SVivien Didelot 		return -EOPNOTSUPP;
14480ad5daf6SVivien Didelot 
14490ad5daf6SVivien Didelot 	return chip->info->ops->vtu_loadpurge(chip, entry);
14500ad5daf6SVivien Didelot }
14510ad5daf6SVivien Didelot 
1452d7f435f9SVivien Didelot static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
1453fad09c73SVivien Didelot {
1454fad09c73SVivien Didelot 	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
1455425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1456fad09c73SVivien Didelot 	int i, err;
1457fad09c73SVivien Didelot 
1458fad09c73SVivien Didelot 	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
1459fad09c73SVivien Didelot 
1460fad09c73SVivien Didelot 	/* Set every FID bit used by the (un)bridged ports */
1461370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1462b4e48c50SVivien Didelot 		err = mv88e6xxx_port_get_fid(chip, i, fid);
1463fad09c73SVivien Didelot 		if (err)
1464fad09c73SVivien Didelot 			return err;
1465fad09c73SVivien Didelot 
1466fad09c73SVivien Didelot 		set_bit(*fid, fid_bitmap);
1467fad09c73SVivien Didelot 	}
1468fad09c73SVivien Didelot 
1469fad09c73SVivien Didelot 	/* Set every FID bit used by the VLAN entries */
1470425d2d37SVivien Didelot 	vlan.vid = chip->info->max_vid;
1471425d2d37SVivien Didelot 	vlan.valid = false;
1472425d2d37SVivien Didelot 
1473fad09c73SVivien Didelot 	do {
1474f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1475fad09c73SVivien Didelot 		if (err)
1476fad09c73SVivien Didelot 			return err;
1477fad09c73SVivien Didelot 
1478fad09c73SVivien Didelot 		if (!vlan.valid)
1479fad09c73SVivien Didelot 			break;
1480fad09c73SVivien Didelot 
1481fad09c73SVivien Didelot 		set_bit(vlan.fid, fid_bitmap);
14823cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
1483fad09c73SVivien Didelot 
1484fad09c73SVivien Didelot 	/* The reset value 0x000 is used to indicate that multiple address
1485fad09c73SVivien Didelot 	 * databases are not needed. Return the next positive available.
1486fad09c73SVivien Didelot 	 */
1487fad09c73SVivien Didelot 	*fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1);
1488fad09c73SVivien Didelot 	if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
1489fad09c73SVivien Didelot 		return -ENOSPC;
1490fad09c73SVivien Didelot 
1491fad09c73SVivien Didelot 	/* Clear the database */
1492daefc943SVivien Didelot 	return mv88e6xxx_g1_atu_flush(chip, *fid, true);
1493fad09c73SVivien Didelot }
1494fad09c73SVivien Didelot 
149523e8b470SAndrew Lunn static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
149623e8b470SAndrew Lunn {
149723e8b470SAndrew Lunn 	if (chip->info->ops->atu_get_hash)
149823e8b470SAndrew Lunn 		return chip->info->ops->atu_get_hash(chip, hash);
149923e8b470SAndrew Lunn 
150023e8b470SAndrew Lunn 	return -EOPNOTSUPP;
150123e8b470SAndrew Lunn }
150223e8b470SAndrew Lunn 
150323e8b470SAndrew Lunn static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash)
150423e8b470SAndrew Lunn {
150523e8b470SAndrew Lunn 	if (chip->info->ops->atu_set_hash)
150623e8b470SAndrew Lunn 		return chip->info->ops->atu_set_hash(chip, hash);
150723e8b470SAndrew Lunn 
150823e8b470SAndrew Lunn 	return -EOPNOTSUPP;
150923e8b470SAndrew Lunn }
151023e8b470SAndrew Lunn 
1511fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
1512fad09c73SVivien Didelot 					u16 vid_begin, u16 vid_end)
1513fad09c73SVivien Didelot {
151404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1515425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1516fad09c73SVivien Didelot 	int i, err;
1517fad09c73SVivien Didelot 
1518db06ae41SAndrew Lunn 	/* DSA and CPU ports have to be members of multiple vlans */
1519db06ae41SAndrew Lunn 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
1520db06ae41SAndrew Lunn 		return 0;
1521db06ae41SAndrew Lunn 
1522fad09c73SVivien Didelot 	if (!vid_begin)
1523fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1524fad09c73SVivien Didelot 
1525425d2d37SVivien Didelot 	vlan.vid = vid_begin - 1;
1526425d2d37SVivien Didelot 	vlan.valid = false;
1527425d2d37SVivien Didelot 
1528fad09c73SVivien Didelot 	do {
1529f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1530fad09c73SVivien Didelot 		if (err)
15317095a4c4SVivien Didelot 			return err;
1532fad09c73SVivien Didelot 
1533fad09c73SVivien Didelot 		if (!vlan.valid)
1534fad09c73SVivien Didelot 			break;
1535fad09c73SVivien Didelot 
1536fad09c73SVivien Didelot 		if (vlan.vid > vid_end)
1537fad09c73SVivien Didelot 			break;
1538fad09c73SVivien Didelot 
1539370b4ffbSVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1540fad09c73SVivien Didelot 			if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
1541fad09c73SVivien Didelot 				continue;
1542fad09c73SVivien Didelot 
154368bb8ea8SVivien Didelot 			if (!dsa_to_port(ds, i)->slave)
154466e2809dSAndrew Lunn 				continue;
154566e2809dSAndrew Lunn 
1546bd00e053SVivien Didelot 			if (vlan.member[i] ==
15477ec60d6eSVivien Didelot 			    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1548fad09c73SVivien Didelot 				continue;
1549fad09c73SVivien Didelot 
1550c8652c83SVivien Didelot 			if (dsa_to_port(ds, i)->bridge_dev ==
155168bb8ea8SVivien Didelot 			    dsa_to_port(ds, port)->bridge_dev)
1552fad09c73SVivien Didelot 				break; /* same bridge, check next VLAN */
1553fad09c73SVivien Didelot 
1554c8652c83SVivien Didelot 			if (!dsa_to_port(ds, i)->bridge_dev)
155566e2809dSAndrew Lunn 				continue;
155666e2809dSAndrew Lunn 
1557743fcc28SAndrew Lunn 			dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
1558743fcc28SAndrew Lunn 				port, vlan.vid, i,
1559c8652c83SVivien Didelot 				netdev_name(dsa_to_port(ds, i)->bridge_dev));
15607095a4c4SVivien Didelot 			return -EOPNOTSUPP;
1561fad09c73SVivien Didelot 		}
1562fad09c73SVivien Didelot 	} while (vlan.vid < vid_end);
1563fad09c73SVivien Didelot 
15647095a4c4SVivien Didelot 	return 0;
1565fad09c73SVivien Didelot }
1566fad09c73SVivien Didelot 
1567fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
1568fad09c73SVivien Didelot 					 bool vlan_filtering)
1569fad09c73SVivien Didelot {
157004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
157181c6edb2SVivien Didelot 	u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
157281c6edb2SVivien Didelot 		MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
15730e7b9925SAndrew Lunn 	int err;
1574fad09c73SVivien Didelot 
15753cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1576fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1577fad09c73SVivien Didelot 
1578c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1579385a0995SVivien Didelot 	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
1580c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1581fad09c73SVivien Didelot 
15820e7b9925SAndrew Lunn 	return err;
1583fad09c73SVivien Didelot }
1584fad09c73SVivien Didelot 
1585fad09c73SVivien Didelot static int
1586fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
158780e02360SVivien Didelot 			    const struct switchdev_obj_port_vlan *vlan)
1588fad09c73SVivien Didelot {
158904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1590fad09c73SVivien Didelot 	int err;
1591fad09c73SVivien Didelot 
15923cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1593fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1594fad09c73SVivien Didelot 
1595fad09c73SVivien Didelot 	/* If the requested port doesn't belong to the same bridge as the VLAN
1596fad09c73SVivien Didelot 	 * members, do not support it (yet) and fallback to software VLAN.
1597fad09c73SVivien Didelot 	 */
15987095a4c4SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1599fad09c73SVivien Didelot 	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
1600fad09c73SVivien Didelot 					   vlan->vid_end);
16017095a4c4SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1602fad09c73SVivien Didelot 
1603fad09c73SVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
1604fad09c73SVivien Didelot 	 * so skip the prepare phase.
1605fad09c73SVivien Didelot 	 */
16067095a4c4SVivien Didelot 	return err;
1607fad09c73SVivien Didelot }
1608fad09c73SVivien Didelot 
1609a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
1610a4c93ae1SAndrew Lunn 					const unsigned char *addr, u16 vid,
1611a4c93ae1SAndrew Lunn 					u8 state)
1612a4c93ae1SAndrew Lunn {
1613a4c93ae1SAndrew Lunn 	struct mv88e6xxx_atu_entry entry;
16145ef8d249SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
16155ef8d249SVivien Didelot 	u16 fid;
1616a4c93ae1SAndrew Lunn 	int err;
1617a4c93ae1SAndrew Lunn 
1618a4c93ae1SAndrew Lunn 	/* Null VLAN ID corresponds to the port private database */
16195ef8d249SVivien Didelot 	if (vid == 0) {
16205ef8d249SVivien Didelot 		err = mv88e6xxx_port_get_fid(chip, port, &fid);
1621a4c93ae1SAndrew Lunn 		if (err)
1622a4c93ae1SAndrew Lunn 			return err;
16235ef8d249SVivien Didelot 	} else {
16245ef8d249SVivien Didelot 		vlan.vid = vid - 1;
16255ef8d249SVivien Didelot 		vlan.valid = false;
16265ef8d249SVivien Didelot 
16275ef8d249SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
16285ef8d249SVivien Didelot 		if (err)
16295ef8d249SVivien Didelot 			return err;
16305ef8d249SVivien Didelot 
16315ef8d249SVivien Didelot 		/* switchdev expects -EOPNOTSUPP to honor software VLANs */
16325ef8d249SVivien Didelot 		if (vlan.vid != vid || !vlan.valid)
16335ef8d249SVivien Didelot 			return -EOPNOTSUPP;
16345ef8d249SVivien Didelot 
16355ef8d249SVivien Didelot 		fid = vlan.fid;
16365ef8d249SVivien Didelot 	}
1637a4c93ae1SAndrew Lunn 
1638d8291a95SVivien Didelot 	entry.state = 0;
1639a4c93ae1SAndrew Lunn 	ether_addr_copy(entry.mac, addr);
1640a4c93ae1SAndrew Lunn 	eth_addr_dec(entry.mac);
1641a4c93ae1SAndrew Lunn 
16425ef8d249SVivien Didelot 	err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry);
1643a4c93ae1SAndrew Lunn 	if (err)
1644a4c93ae1SAndrew Lunn 		return err;
1645a4c93ae1SAndrew Lunn 
1646a4c93ae1SAndrew Lunn 	/* Initialize a fresh ATU entry if it isn't found */
1647d8291a95SVivien Didelot 	if (!entry.state || !ether_addr_equal(entry.mac, addr)) {
1648a4c93ae1SAndrew Lunn 		memset(&entry, 0, sizeof(entry));
1649a4c93ae1SAndrew Lunn 		ether_addr_copy(entry.mac, addr);
1650a4c93ae1SAndrew Lunn 	}
1651a4c93ae1SAndrew Lunn 
1652a4c93ae1SAndrew Lunn 	/* Purge the ATU entry only if no port is using it anymore */
1653d8291a95SVivien Didelot 	if (!state) {
1654a4c93ae1SAndrew Lunn 		entry.portvec &= ~BIT(port);
1655a4c93ae1SAndrew Lunn 		if (!entry.portvec)
1656d8291a95SVivien Didelot 			entry.state = 0;
1657a4c93ae1SAndrew Lunn 	} else {
1658a4c93ae1SAndrew Lunn 		entry.portvec |= BIT(port);
1659a4c93ae1SAndrew Lunn 		entry.state = state;
1660a4c93ae1SAndrew Lunn 	}
1661a4c93ae1SAndrew Lunn 
16625ef8d249SVivien Didelot 	return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry);
1663a4c93ae1SAndrew Lunn }
1664a4c93ae1SAndrew Lunn 
1665da7dc875SVivien Didelot static int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port,
1666da7dc875SVivien Didelot 				  const struct mv88e6xxx_policy *policy)
1667da7dc875SVivien Didelot {
1668da7dc875SVivien Didelot 	enum mv88e6xxx_policy_mapping mapping = policy->mapping;
1669da7dc875SVivien Didelot 	enum mv88e6xxx_policy_action action = policy->action;
1670da7dc875SVivien Didelot 	const u8 *addr = policy->addr;
1671da7dc875SVivien Didelot 	u16 vid = policy->vid;
1672da7dc875SVivien Didelot 	u8 state;
1673da7dc875SVivien Didelot 	int err;
1674da7dc875SVivien Didelot 	int id;
1675da7dc875SVivien Didelot 
1676da7dc875SVivien Didelot 	if (!chip->info->ops->port_set_policy)
1677da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1678da7dc875SVivien Didelot 
1679da7dc875SVivien Didelot 	switch (mapping) {
1680da7dc875SVivien Didelot 	case MV88E6XXX_POLICY_MAPPING_DA:
1681da7dc875SVivien Didelot 	case MV88E6XXX_POLICY_MAPPING_SA:
1682da7dc875SVivien Didelot 		if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
1683da7dc875SVivien Didelot 			state = 0; /* Dissociate the port and address */
1684da7dc875SVivien Didelot 		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
1685da7dc875SVivien Didelot 			 is_multicast_ether_addr(addr))
1686da7dc875SVivien Didelot 			state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY;
1687da7dc875SVivien Didelot 		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
1688da7dc875SVivien Didelot 			 is_unicast_ether_addr(addr))
1689da7dc875SVivien Didelot 			state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY;
1690da7dc875SVivien Didelot 		else
1691da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1692da7dc875SVivien Didelot 
1693da7dc875SVivien Didelot 		err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
1694da7dc875SVivien Didelot 						   state);
1695da7dc875SVivien Didelot 		if (err)
1696da7dc875SVivien Didelot 			return err;
1697da7dc875SVivien Didelot 		break;
1698da7dc875SVivien Didelot 	default:
1699da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1700da7dc875SVivien Didelot 	}
1701da7dc875SVivien Didelot 
1702da7dc875SVivien Didelot 	/* Skip the port's policy clearing if the mapping is still in use */
1703da7dc875SVivien Didelot 	if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
1704da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1705da7dc875SVivien Didelot 			if (policy->port == port &&
1706da7dc875SVivien Didelot 			    policy->mapping == mapping &&
1707da7dc875SVivien Didelot 			    policy->action != action)
1708da7dc875SVivien Didelot 				return 0;
1709da7dc875SVivien Didelot 
1710da7dc875SVivien Didelot 	return chip->info->ops->port_set_policy(chip, port, mapping, action);
1711da7dc875SVivien Didelot }
1712da7dc875SVivien Didelot 
1713da7dc875SVivien Didelot static int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port,
1714da7dc875SVivien Didelot 				   struct ethtool_rx_flow_spec *fs)
1715da7dc875SVivien Didelot {
1716da7dc875SVivien Didelot 	struct ethhdr *mac_entry = &fs->h_u.ether_spec;
1717da7dc875SVivien Didelot 	struct ethhdr *mac_mask = &fs->m_u.ether_spec;
1718da7dc875SVivien Didelot 	enum mv88e6xxx_policy_mapping mapping;
1719da7dc875SVivien Didelot 	enum mv88e6xxx_policy_action action;
1720da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1721da7dc875SVivien Didelot 	u16 vid = 0;
1722da7dc875SVivien Didelot 	u8 *addr;
1723da7dc875SVivien Didelot 	int err;
1724da7dc875SVivien Didelot 	int id;
1725da7dc875SVivien Didelot 
1726da7dc875SVivien Didelot 	if (fs->location != RX_CLS_LOC_ANY)
1727da7dc875SVivien Didelot 		return -EINVAL;
1728da7dc875SVivien Didelot 
1729da7dc875SVivien Didelot 	if (fs->ring_cookie == RX_CLS_FLOW_DISC)
1730da7dc875SVivien Didelot 		action = MV88E6XXX_POLICY_ACTION_DISCARD;
1731da7dc875SVivien Didelot 	else
1732da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1733da7dc875SVivien Didelot 
1734da7dc875SVivien Didelot 	switch (fs->flow_type & ~FLOW_EXT) {
1735da7dc875SVivien Didelot 	case ETHER_FLOW:
1736da7dc875SVivien Didelot 		if (!is_zero_ether_addr(mac_mask->h_dest) &&
1737da7dc875SVivien Didelot 		    is_zero_ether_addr(mac_mask->h_source)) {
1738da7dc875SVivien Didelot 			mapping = MV88E6XXX_POLICY_MAPPING_DA;
1739da7dc875SVivien Didelot 			addr = mac_entry->h_dest;
1740da7dc875SVivien Didelot 		} else if (is_zero_ether_addr(mac_mask->h_dest) &&
1741da7dc875SVivien Didelot 		    !is_zero_ether_addr(mac_mask->h_source)) {
1742da7dc875SVivien Didelot 			mapping = MV88E6XXX_POLICY_MAPPING_SA;
1743da7dc875SVivien Didelot 			addr = mac_entry->h_source;
1744da7dc875SVivien Didelot 		} else {
1745da7dc875SVivien Didelot 			/* Cannot support DA and SA mapping in the same rule */
1746da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1747da7dc875SVivien Didelot 		}
1748da7dc875SVivien Didelot 		break;
1749da7dc875SVivien Didelot 	default:
1750da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1751da7dc875SVivien Didelot 	}
1752da7dc875SVivien Didelot 
1753da7dc875SVivien Didelot 	if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) {
1754da7dc875SVivien Didelot 		if (fs->m_ext.vlan_tci != 0xffff)
1755da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1756da7dc875SVivien Didelot 		vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK;
1757da7dc875SVivien Didelot 	}
1758da7dc875SVivien Didelot 
1759da7dc875SVivien Didelot 	idr_for_each_entry(&chip->policies, policy, id) {
1760da7dc875SVivien Didelot 		if (policy->port == port && policy->mapping == mapping &&
1761da7dc875SVivien Didelot 		    policy->action == action && policy->vid == vid &&
1762da7dc875SVivien Didelot 		    ether_addr_equal(policy->addr, addr))
1763da7dc875SVivien Didelot 			return -EEXIST;
1764da7dc875SVivien Didelot 	}
1765da7dc875SVivien Didelot 
1766da7dc875SVivien Didelot 	policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL);
1767da7dc875SVivien Didelot 	if (!policy)
1768da7dc875SVivien Didelot 		return -ENOMEM;
1769da7dc875SVivien Didelot 
1770da7dc875SVivien Didelot 	fs->location = 0;
1771da7dc875SVivien Didelot 	err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff,
1772da7dc875SVivien Didelot 			    GFP_KERNEL);
1773da7dc875SVivien Didelot 	if (err) {
1774da7dc875SVivien Didelot 		devm_kfree(chip->dev, policy);
1775da7dc875SVivien Didelot 		return err;
1776da7dc875SVivien Didelot 	}
1777da7dc875SVivien Didelot 
1778da7dc875SVivien Didelot 	memcpy(&policy->fs, fs, sizeof(*fs));
1779da7dc875SVivien Didelot 	ether_addr_copy(policy->addr, addr);
1780da7dc875SVivien Didelot 	policy->mapping = mapping;
1781da7dc875SVivien Didelot 	policy->action = action;
1782da7dc875SVivien Didelot 	policy->port = port;
1783da7dc875SVivien Didelot 	policy->vid = vid;
1784da7dc875SVivien Didelot 
1785da7dc875SVivien Didelot 	err = mv88e6xxx_policy_apply(chip, port, policy);
1786da7dc875SVivien Didelot 	if (err) {
1787da7dc875SVivien Didelot 		idr_remove(&chip->policies, fs->location);
1788da7dc875SVivien Didelot 		devm_kfree(chip->dev, policy);
1789da7dc875SVivien Didelot 		return err;
1790da7dc875SVivien Didelot 	}
1791da7dc875SVivien Didelot 
1792da7dc875SVivien Didelot 	return 0;
1793da7dc875SVivien Didelot }
1794da7dc875SVivien Didelot 
1795da7dc875SVivien Didelot static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,
1796da7dc875SVivien Didelot 			       struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
1797da7dc875SVivien Didelot {
1798da7dc875SVivien Didelot 	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
1799da7dc875SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1800da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1801da7dc875SVivien Didelot 	int err;
1802da7dc875SVivien Didelot 	int id;
1803da7dc875SVivien Didelot 
1804da7dc875SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1805da7dc875SVivien Didelot 
1806da7dc875SVivien Didelot 	switch (rxnfc->cmd) {
1807da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRLCNT:
1808da7dc875SVivien Didelot 		rxnfc->data = 0;
1809da7dc875SVivien Didelot 		rxnfc->data |= RX_CLS_LOC_SPECIAL;
1810da7dc875SVivien Didelot 		rxnfc->rule_cnt = 0;
1811da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1812da7dc875SVivien Didelot 			if (policy->port == port)
1813da7dc875SVivien Didelot 				rxnfc->rule_cnt++;
1814da7dc875SVivien Didelot 		err = 0;
1815da7dc875SVivien Didelot 		break;
1816da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRULE:
1817da7dc875SVivien Didelot 		err = -ENOENT;
1818da7dc875SVivien Didelot 		policy = idr_find(&chip->policies, fs->location);
1819da7dc875SVivien Didelot 		if (policy) {
1820da7dc875SVivien Didelot 			memcpy(fs, &policy->fs, sizeof(*fs));
1821da7dc875SVivien Didelot 			err = 0;
1822da7dc875SVivien Didelot 		}
1823da7dc875SVivien Didelot 		break;
1824da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRLALL:
1825da7dc875SVivien Didelot 		rxnfc->data = 0;
1826da7dc875SVivien Didelot 		rxnfc->rule_cnt = 0;
1827da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1828da7dc875SVivien Didelot 			if (policy->port == port)
1829da7dc875SVivien Didelot 				rule_locs[rxnfc->rule_cnt++] = id;
1830da7dc875SVivien Didelot 		err = 0;
1831da7dc875SVivien Didelot 		break;
1832da7dc875SVivien Didelot 	default:
1833da7dc875SVivien Didelot 		err = -EOPNOTSUPP;
1834da7dc875SVivien Didelot 		break;
1835da7dc875SVivien Didelot 	}
1836da7dc875SVivien Didelot 
1837da7dc875SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1838da7dc875SVivien Didelot 
1839da7dc875SVivien Didelot 	return err;
1840da7dc875SVivien Didelot }
1841da7dc875SVivien Didelot 
1842da7dc875SVivien Didelot static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port,
1843da7dc875SVivien Didelot 			       struct ethtool_rxnfc *rxnfc)
1844da7dc875SVivien Didelot {
1845da7dc875SVivien Didelot 	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
1846da7dc875SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1847da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1848da7dc875SVivien Didelot 	int err;
1849da7dc875SVivien Didelot 
1850da7dc875SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1851da7dc875SVivien Didelot 
1852da7dc875SVivien Didelot 	switch (rxnfc->cmd) {
1853da7dc875SVivien Didelot 	case ETHTOOL_SRXCLSRLINS:
1854da7dc875SVivien Didelot 		err = mv88e6xxx_policy_insert(chip, port, fs);
1855da7dc875SVivien Didelot 		break;
1856da7dc875SVivien Didelot 	case ETHTOOL_SRXCLSRLDEL:
1857da7dc875SVivien Didelot 		err = -ENOENT;
1858da7dc875SVivien Didelot 		policy = idr_remove(&chip->policies, fs->location);
1859da7dc875SVivien Didelot 		if (policy) {
1860da7dc875SVivien Didelot 			policy->action = MV88E6XXX_POLICY_ACTION_NORMAL;
1861da7dc875SVivien Didelot 			err = mv88e6xxx_policy_apply(chip, port, policy);
1862da7dc875SVivien Didelot 			devm_kfree(chip->dev, policy);
1863da7dc875SVivien Didelot 		}
1864da7dc875SVivien Didelot 		break;
1865da7dc875SVivien Didelot 	default:
1866da7dc875SVivien Didelot 		err = -EOPNOTSUPP;
1867da7dc875SVivien Didelot 		break;
1868da7dc875SVivien Didelot 	}
1869da7dc875SVivien Didelot 
1870da7dc875SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1871da7dc875SVivien Didelot 
1872da7dc875SVivien Didelot 	return err;
1873da7dc875SVivien Didelot }
1874da7dc875SVivien Didelot 
187587fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
187687fa886eSAndrew Lunn 					u16 vid)
187787fa886eSAndrew Lunn {
187887fa886eSAndrew Lunn 	const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
187987fa886eSAndrew Lunn 	u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
188087fa886eSAndrew Lunn 
188187fa886eSAndrew Lunn 	return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
188287fa886eSAndrew Lunn }
188387fa886eSAndrew Lunn 
188487fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
188587fa886eSAndrew Lunn {
188687fa886eSAndrew Lunn 	int port;
188787fa886eSAndrew Lunn 	int err;
188887fa886eSAndrew Lunn 
188987fa886eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
189087fa886eSAndrew Lunn 		err = mv88e6xxx_port_add_broadcast(chip, port, vid);
189187fa886eSAndrew Lunn 		if (err)
189287fa886eSAndrew Lunn 			return err;
189387fa886eSAndrew Lunn 	}
189487fa886eSAndrew Lunn 
189587fa886eSAndrew Lunn 	return 0;
189687fa886eSAndrew Lunn }
189787fa886eSAndrew Lunn 
1898b1ac6fb4SVivien Didelot static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port,
1899933b4425SRussell King 				    u16 vid, u8 member, bool warn)
1900fad09c73SVivien Didelot {
1901b1ac6fb4SVivien Didelot 	const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1902b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1903b1ac6fb4SVivien Didelot 	int i, err;
1904fad09c73SVivien Didelot 
1905b1ac6fb4SVivien Didelot 	if (!vid)
1906b1ac6fb4SVivien Didelot 		return -EOPNOTSUPP;
1907b1ac6fb4SVivien Didelot 
1908b1ac6fb4SVivien Didelot 	vlan.vid = vid - 1;
1909b1ac6fb4SVivien Didelot 	vlan.valid = false;
1910b1ac6fb4SVivien Didelot 
1911b1ac6fb4SVivien Didelot 	err = mv88e6xxx_vtu_getnext(chip, &vlan);
1912fad09c73SVivien Didelot 	if (err)
1913fad09c73SVivien Didelot 		return err;
1914fad09c73SVivien Didelot 
1915b1ac6fb4SVivien Didelot 	if (vlan.vid != vid || !vlan.valid) {
1916b1ac6fb4SVivien Didelot 		memset(&vlan, 0, sizeof(vlan));
1917b1ac6fb4SVivien Didelot 
1918b1ac6fb4SVivien Didelot 		err = mv88e6xxx_atu_new(chip, &vlan.fid);
1919b1ac6fb4SVivien Didelot 		if (err)
1920b1ac6fb4SVivien Didelot 			return err;
1921b1ac6fb4SVivien Didelot 
1922b1ac6fb4SVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
1923b1ac6fb4SVivien Didelot 			if (i == port)
1924b1ac6fb4SVivien Didelot 				vlan.member[i] = member;
1925b1ac6fb4SVivien Didelot 			else
1926b1ac6fb4SVivien Didelot 				vlan.member[i] = non_member;
1927b1ac6fb4SVivien Didelot 
1928b1ac6fb4SVivien Didelot 		vlan.vid = vid;
19291cb9dfcaSRasmus Villemoes 		vlan.valid = true;
1930fad09c73SVivien Didelot 
193187fa886eSAndrew Lunn 		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
193287fa886eSAndrew Lunn 		if (err)
193387fa886eSAndrew Lunn 			return err;
193487fa886eSAndrew Lunn 
1935b1ac6fb4SVivien Didelot 		err = mv88e6xxx_broadcast_setup(chip, vlan.vid);
1936b1ac6fb4SVivien Didelot 		if (err)
1937b1ac6fb4SVivien Didelot 			return err;
1938b1ac6fb4SVivien Didelot 	} else if (vlan.member[port] != member) {
1939b1ac6fb4SVivien Didelot 		vlan.member[port] = member;
1940b1ac6fb4SVivien Didelot 
1941b1ac6fb4SVivien Didelot 		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
1942b1ac6fb4SVivien Didelot 		if (err)
1943b1ac6fb4SVivien Didelot 			return err;
1944933b4425SRussell King 	} else if (warn) {
1945b1ac6fb4SVivien Didelot 		dev_info(chip->dev, "p%d: already a member of VLAN %d\n",
1946b1ac6fb4SVivien Didelot 			 port, vid);
1947b1ac6fb4SVivien Didelot 	}
1948b1ac6fb4SVivien Didelot 
1949b1ac6fb4SVivien Didelot 	return 0;
1950fad09c73SVivien Didelot }
1951fad09c73SVivien Didelot 
1952fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
195380e02360SVivien Didelot 				    const struct switchdev_obj_port_vlan *vlan)
1954fad09c73SVivien Didelot {
195504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1956fad09c73SVivien Didelot 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1957fad09c73SVivien Didelot 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1958933b4425SRussell King 	bool warn;
1959c91498e1SVivien Didelot 	u8 member;
1960fad09c73SVivien Didelot 	u16 vid;
1961fad09c73SVivien Didelot 
19623cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1963fad09c73SVivien Didelot 		return;
1964fad09c73SVivien Didelot 
1965c91498e1SVivien Didelot 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
19667ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED;
1967c91498e1SVivien Didelot 	else if (untagged)
19687ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED;
1969c91498e1SVivien Didelot 	else
19707ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
1971c91498e1SVivien Didelot 
1972933b4425SRussell King 	/* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port
1973933b4425SRussell King 	 * and then the CPU port. Do not warn for duplicates for the CPU port.
1974933b4425SRussell King 	 */
1975933b4425SRussell King 	warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port);
1976933b4425SRussell King 
1977c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1978fad09c73SVivien Didelot 
1979fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
1980933b4425SRussell King 		if (mv88e6xxx_port_vlan_join(chip, port, vid, member, warn))
1981774439e5SVivien Didelot 			dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
1982fad09c73SVivien Didelot 				vid, untagged ? 'u' : 't');
1983fad09c73SVivien Didelot 
198477064f37SVivien Didelot 	if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end))
1985774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to set PVID %d\n", port,
1986fad09c73SVivien Didelot 			vlan->vid_end);
1987fad09c73SVivien Didelot 
1988c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1989fad09c73SVivien Didelot }
1990fad09c73SVivien Didelot 
199152109892SVivien Didelot static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip,
1992fad09c73SVivien Didelot 				     int port, u16 vid)
1993fad09c73SVivien Didelot {
1994b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1995fad09c73SVivien Didelot 	int i, err;
1996fad09c73SVivien Didelot 
199752109892SVivien Didelot 	if (!vid)
199852109892SVivien Didelot 		return -EOPNOTSUPP;
199952109892SVivien Didelot 
200052109892SVivien Didelot 	vlan.vid = vid - 1;
200152109892SVivien Didelot 	vlan.valid = false;
200252109892SVivien Didelot 
200352109892SVivien Didelot 	err = mv88e6xxx_vtu_getnext(chip, &vlan);
2004fad09c73SVivien Didelot 	if (err)
2005fad09c73SVivien Didelot 		return err;
2006fad09c73SVivien Didelot 
200752109892SVivien Didelot 	/* If the VLAN doesn't exist in hardware or the port isn't a member,
200852109892SVivien Didelot 	 * tell switchdev that this VLAN is likely handled in software.
200952109892SVivien Didelot 	 */
201052109892SVivien Didelot 	if (vlan.vid != vid || !vlan.valid ||
201152109892SVivien Didelot 	    vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
2012fad09c73SVivien Didelot 		return -EOPNOTSUPP;
2013fad09c73SVivien Didelot 
20147ec60d6eSVivien Didelot 	vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
2015fad09c73SVivien Didelot 
2016fad09c73SVivien Didelot 	/* keep the VLAN unless all ports are excluded */
2017fad09c73SVivien Didelot 	vlan.valid = false;
2018370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
20197ec60d6eSVivien Didelot 		if (vlan.member[i] !=
20207ec60d6eSVivien Didelot 		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
2021fad09c73SVivien Didelot 			vlan.valid = true;
2022fad09c73SVivien Didelot 			break;
2023fad09c73SVivien Didelot 		}
2024fad09c73SVivien Didelot 	}
2025fad09c73SVivien Didelot 
20260ad5daf6SVivien Didelot 	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
2027fad09c73SVivien Didelot 	if (err)
2028fad09c73SVivien Didelot 		return err;
2029fad09c73SVivien Didelot 
2030e606ca36SVivien Didelot 	return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
2031fad09c73SVivien Didelot }
2032fad09c73SVivien Didelot 
2033fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
2034fad09c73SVivien Didelot 				   const struct switchdev_obj_port_vlan *vlan)
2035fad09c73SVivien Didelot {
203604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2037fad09c73SVivien Didelot 	u16 pvid, vid;
2038fad09c73SVivien Didelot 	int err = 0;
2039fad09c73SVivien Didelot 
20403cf3c846SVivien Didelot 	if (!chip->info->max_vid)
2041fad09c73SVivien Didelot 		return -EOPNOTSUPP;
2042fad09c73SVivien Didelot 
2043c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2044fad09c73SVivien Didelot 
204577064f37SVivien Didelot 	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
2046fad09c73SVivien Didelot 	if (err)
2047fad09c73SVivien Didelot 		goto unlock;
2048fad09c73SVivien Didelot 
2049fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
205052109892SVivien Didelot 		err = mv88e6xxx_port_vlan_leave(chip, port, vid);
2051fad09c73SVivien Didelot 		if (err)
2052fad09c73SVivien Didelot 			goto unlock;
2053fad09c73SVivien Didelot 
2054fad09c73SVivien Didelot 		if (vid == pvid) {
205577064f37SVivien Didelot 			err = mv88e6xxx_port_set_pvid(chip, port, 0);
2056fad09c73SVivien Didelot 			if (err)
2057fad09c73SVivien Didelot 				goto unlock;
2058fad09c73SVivien Didelot 		}
2059fad09c73SVivien Didelot 	}
2060fad09c73SVivien Didelot 
2061fad09c73SVivien Didelot unlock:
2062c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2063fad09c73SVivien Didelot 
2064fad09c73SVivien Didelot 	return err;
2065fad09c73SVivien Didelot }
2066fad09c73SVivien Didelot 
20671b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
20686c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
2069fad09c73SVivien Didelot {
207004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
20711b6dd556SArkadi Sharshevsky 	int err;
2072fad09c73SVivien Didelot 
2073c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
20741b6dd556SArkadi Sharshevsky 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
20751b6dd556SArkadi Sharshevsky 					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
2076c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
20771b6dd556SArkadi Sharshevsky 
20781b6dd556SArkadi Sharshevsky 	return err;
2079fad09c73SVivien Didelot }
2080fad09c73SVivien Didelot 
2081fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
20826c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
2083fad09c73SVivien Didelot {
208404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
208583dabd1fSVivien Didelot 	int err;
2086fad09c73SVivien Didelot 
2087c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2088d8291a95SVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
2089c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2090fad09c73SVivien Didelot 
209183dabd1fSVivien Didelot 	return err;
2092fad09c73SVivien Didelot }
2093fad09c73SVivien Didelot 
209483dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
2095fad09c73SVivien Didelot 				      u16 fid, u16 vid, int port,
20962bedde1aSArkadi Sharshevsky 				      dsa_fdb_dump_cb_t *cb, void *data)
2097fad09c73SVivien Didelot {
2098dabc1a96SVivien Didelot 	struct mv88e6xxx_atu_entry addr;
20992bedde1aSArkadi Sharshevsky 	bool is_static;
2100fad09c73SVivien Didelot 	int err;
2101fad09c73SVivien Didelot 
2102d8291a95SVivien Didelot 	addr.state = 0;
2103dabc1a96SVivien Didelot 	eth_broadcast_addr(addr.mac);
2104fad09c73SVivien Didelot 
2105fad09c73SVivien Didelot 	do {
2106dabc1a96SVivien Didelot 		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
2107fad09c73SVivien Didelot 		if (err)
210883dabd1fSVivien Didelot 			return err;
2109fad09c73SVivien Didelot 
2110d8291a95SVivien Didelot 		if (!addr.state)
2111fad09c73SVivien Didelot 			break;
2112fad09c73SVivien Didelot 
211301bd96c8SVivien Didelot 		if (addr.trunk || (addr.portvec & BIT(port)) == 0)
211483dabd1fSVivien Didelot 			continue;
2115fad09c73SVivien Didelot 
211683dabd1fSVivien Didelot 		if (!is_unicast_ether_addr(addr.mac))
211783dabd1fSVivien Didelot 			continue;
211883dabd1fSVivien Didelot 
21192bedde1aSArkadi Sharshevsky 		is_static = (addr.state ==
21202bedde1aSArkadi Sharshevsky 			     MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
21212bedde1aSArkadi Sharshevsky 		err = cb(addr.mac, vid, is_static, data);
212283dabd1fSVivien Didelot 		if (err)
212383dabd1fSVivien Didelot 			return err;
2124fad09c73SVivien Didelot 	} while (!is_broadcast_ether_addr(addr.mac));
2125fad09c73SVivien Didelot 
2126fad09c73SVivien Didelot 	return err;
2127fad09c73SVivien Didelot }
2128fad09c73SVivien Didelot 
212983dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
21302bedde1aSArkadi Sharshevsky 				  dsa_fdb_dump_cb_t *cb, void *data)
213183dabd1fSVivien Didelot {
2132425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
213383dabd1fSVivien Didelot 	u16 fid;
213483dabd1fSVivien Didelot 	int err;
213583dabd1fSVivien Didelot 
213683dabd1fSVivien Didelot 	/* Dump port's default Filtering Information Database (VLAN ID 0) */
2137b4e48c50SVivien Didelot 	err = mv88e6xxx_port_get_fid(chip, port, &fid);
213883dabd1fSVivien Didelot 	if (err)
213983dabd1fSVivien Didelot 		return err;
214083dabd1fSVivien Didelot 
21412bedde1aSArkadi Sharshevsky 	err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data);
214283dabd1fSVivien Didelot 	if (err)
214383dabd1fSVivien Didelot 		return err;
214483dabd1fSVivien Didelot 
214583dabd1fSVivien Didelot 	/* Dump VLANs' Filtering Information Databases */
2146425d2d37SVivien Didelot 	vlan.vid = chip->info->max_vid;
2147425d2d37SVivien Didelot 	vlan.valid = false;
2148425d2d37SVivien Didelot 
214983dabd1fSVivien Didelot 	do {
2150f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
215183dabd1fSVivien Didelot 		if (err)
215283dabd1fSVivien Didelot 			return err;
215383dabd1fSVivien Didelot 
215483dabd1fSVivien Didelot 		if (!vlan.valid)
215583dabd1fSVivien Didelot 			break;
215683dabd1fSVivien Didelot 
215783dabd1fSVivien Didelot 		err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port,
21582bedde1aSArkadi Sharshevsky 						 cb, data);
215983dabd1fSVivien Didelot 		if (err)
216083dabd1fSVivien Didelot 			return err;
21613cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
216283dabd1fSVivien Didelot 
216383dabd1fSVivien Didelot 	return err;
216483dabd1fSVivien Didelot }
216583dabd1fSVivien Didelot 
2166fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
21672bedde1aSArkadi Sharshevsky 				   dsa_fdb_dump_cb_t *cb, void *data)
2168fad09c73SVivien Didelot {
216904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2170fcf15367SVivien Didelot 	int err;
2171fad09c73SVivien Didelot 
2172c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2173fcf15367SVivien Didelot 	err = mv88e6xxx_port_db_dump(chip, port, cb, data);
2174c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2175fcf15367SVivien Didelot 
2176fcf15367SVivien Didelot 	return err;
2177fad09c73SVivien Didelot }
2178fad09c73SVivien Didelot 
2179240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
2180240ea3efSVivien Didelot 				struct net_device *br)
2181240ea3efSVivien Didelot {
2182ef2025ecSVivien Didelot 	struct dsa_switch *ds = chip->ds;
2183ef2025ecSVivien Didelot 	struct dsa_switch_tree *dst = ds->dst;
2184ef2025ecSVivien Didelot 	struct dsa_port *dp;
2185240ea3efSVivien Didelot 	int err;
2186240ea3efSVivien Didelot 
2187ef2025ecSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list) {
2188ef2025ecSVivien Didelot 		if (dp->bridge_dev == br) {
2189ef2025ecSVivien Didelot 			if (dp->ds == ds) {
2190ef2025ecSVivien Didelot 				/* This is a local bridge group member,
2191ef2025ecSVivien Didelot 				 * remap its Port VLAN Map.
2192ef2025ecSVivien Didelot 				 */
2193ef2025ecSVivien Didelot 				err = mv88e6xxx_port_vlan_map(chip, dp->index);
2194240ea3efSVivien Didelot 				if (err)
2195240ea3efSVivien Didelot 					return err;
2196ef2025ecSVivien Didelot 			} else {
2197ef2025ecSVivien Didelot 				/* This is an external bridge group member,
2198ef2025ecSVivien Didelot 				 * remap its cross-chip Port VLAN Table entry.
2199ef2025ecSVivien Didelot 				 */
2200ef2025ecSVivien Didelot 				err = mv88e6xxx_pvt_map(chip, dp->ds->index,
2201ef2025ecSVivien Didelot 							dp->index);
2202e96a6e02SVivien Didelot 				if (err)
2203e96a6e02SVivien Didelot 					return err;
2204e96a6e02SVivien Didelot 			}
2205e96a6e02SVivien Didelot 		}
2206e96a6e02SVivien Didelot 	}
2207e96a6e02SVivien Didelot 
2208240ea3efSVivien Didelot 	return 0;
2209240ea3efSVivien Didelot }
2210240ea3efSVivien Didelot 
2211fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
2212fae8a25eSVivien Didelot 				      struct net_device *br)
2213fad09c73SVivien Didelot {
221404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2215240ea3efSVivien Didelot 	int err;
2216fad09c73SVivien Didelot 
2217c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2218240ea3efSVivien Didelot 	err = mv88e6xxx_bridge_map(chip, br);
2219c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2220fad09c73SVivien Didelot 
2221fad09c73SVivien Didelot 	return err;
2222fad09c73SVivien Didelot }
2223fad09c73SVivien Didelot 
2224f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
2225f123f2fbSVivien Didelot 					struct net_device *br)
2226fad09c73SVivien Didelot {
222704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2228fad09c73SVivien Didelot 
2229c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2230240ea3efSVivien Didelot 	if (mv88e6xxx_bridge_map(chip, br) ||
2231240ea3efSVivien Didelot 	    mv88e6xxx_port_vlan_map(chip, port))
2232240ea3efSVivien Didelot 		dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
2233c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2234fad09c73SVivien Didelot }
2235fad09c73SVivien Didelot 
2236aec5ac88SVivien Didelot static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev,
2237aec5ac88SVivien Didelot 					   int port, struct net_device *br)
2238aec5ac88SVivien Didelot {
2239aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2240aec5ac88SVivien Didelot 	int err;
2241aec5ac88SVivien Didelot 
2242c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2243aec5ac88SVivien Didelot 	err = mv88e6xxx_pvt_map(chip, dev, port);
2244c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2245aec5ac88SVivien Didelot 
2246aec5ac88SVivien Didelot 	return err;
2247aec5ac88SVivien Didelot }
2248aec5ac88SVivien Didelot 
2249aec5ac88SVivien Didelot static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev,
2250aec5ac88SVivien Didelot 					     int port, struct net_device *br)
2251aec5ac88SVivien Didelot {
2252aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2253aec5ac88SVivien Didelot 
2254c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2255aec5ac88SVivien Didelot 	if (mv88e6xxx_pvt_map(chip, dev, port))
2256aec5ac88SVivien Didelot 		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
2257c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2258aec5ac88SVivien Didelot }
2259aec5ac88SVivien Didelot 
226017e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
226117e708baSVivien Didelot {
226217e708baSVivien Didelot 	if (chip->info->ops->reset)
226317e708baSVivien Didelot 		return chip->info->ops->reset(chip);
226417e708baSVivien Didelot 
226517e708baSVivien Didelot 	return 0;
226617e708baSVivien Didelot }
226717e708baSVivien Didelot 
2268309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
2269309eca6dSVivien Didelot {
2270309eca6dSVivien Didelot 	struct gpio_desc *gpiod = chip->reset;
2271309eca6dSVivien Didelot 
2272309eca6dSVivien Didelot 	/* If there is a GPIO connected to the reset pin, toggle it */
2273309eca6dSVivien Didelot 	if (gpiod) {
2274309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 1);
2275309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2276309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 0);
2277309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2278309eca6dSVivien Didelot 	}
2279309eca6dSVivien Didelot }
2280309eca6dSVivien Didelot 
22814ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
22824ac4b5a6SVivien Didelot {
22834ac4b5a6SVivien Didelot 	int i, err;
22844ac4b5a6SVivien Didelot 
22854ac4b5a6SVivien Didelot 	/* Set all ports to the Disabled state */
22864ac4b5a6SVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2287f894c29cSVivien Didelot 		err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED);
22884ac4b5a6SVivien Didelot 		if (err)
22894ac4b5a6SVivien Didelot 			return err;
22904ac4b5a6SVivien Didelot 	}
22914ac4b5a6SVivien Didelot 
22924ac4b5a6SVivien Didelot 	/* Wait for transmit queues to drain,
22934ac4b5a6SVivien Didelot 	 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
22944ac4b5a6SVivien Didelot 	 */
22954ac4b5a6SVivien Didelot 	usleep_range(2000, 4000);
22964ac4b5a6SVivien Didelot 
22974ac4b5a6SVivien Didelot 	return 0;
22984ac4b5a6SVivien Didelot }
22994ac4b5a6SVivien Didelot 
2300fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
2301fad09c73SVivien Didelot {
2302a935c052SVivien Didelot 	int err;
2303fad09c73SVivien Didelot 
23044ac4b5a6SVivien Didelot 	err = mv88e6xxx_disable_ports(chip);
23050e7b9925SAndrew Lunn 	if (err)
23060e7b9925SAndrew Lunn 		return err;
2307fad09c73SVivien Didelot 
2308309eca6dSVivien Didelot 	mv88e6xxx_hardware_reset(chip);
2309fad09c73SVivien Didelot 
231017e708baSVivien Didelot 	return mv88e6xxx_software_reset(chip);
2311fad09c73SVivien Didelot }
2312fad09c73SVivien Didelot 
23134314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
231431bef4e9SVivien Didelot 				   enum mv88e6xxx_frame_mode frame,
231531bef4e9SVivien Didelot 				   enum mv88e6xxx_egress_mode egress, u16 etype)
231656995cbcSAndrew Lunn {
231756995cbcSAndrew Lunn 	int err;
231856995cbcSAndrew Lunn 
23194314557cSVivien Didelot 	if (!chip->info->ops->port_set_frame_mode)
23204314557cSVivien Didelot 		return -EOPNOTSUPP;
23214314557cSVivien Didelot 
23224314557cSVivien Didelot 	err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
232356995cbcSAndrew Lunn 	if (err)
232456995cbcSAndrew Lunn 		return err;
232556995cbcSAndrew Lunn 
23264314557cSVivien Didelot 	err = chip->info->ops->port_set_frame_mode(chip, port, frame);
23274314557cSVivien Didelot 	if (err)
23284314557cSVivien Didelot 		return err;
23294314557cSVivien Didelot 
23304314557cSVivien Didelot 	if (chip->info->ops->port_set_ether_type)
23314314557cSVivien Didelot 		return chip->info->ops->port_set_ether_type(chip, port, etype);
23324314557cSVivien Didelot 
23334314557cSVivien Didelot 	return 0;
23344314557cSVivien Didelot }
23354314557cSVivien Didelot 
23364314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
23374314557cSVivien Didelot {
23384314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
233931bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2340b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
23414314557cSVivien Didelot }
23424314557cSVivien Didelot 
23434314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
23444314557cSVivien Didelot {
23454314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
234631bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2347b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
23484314557cSVivien Didelot }
23494314557cSVivien Didelot 
23504314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
23514314557cSVivien Didelot {
23524314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port,
23534314557cSVivien Didelot 				       MV88E6XXX_FRAME_MODE_ETHERTYPE,
235431bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_ETHERTYPE,
235531bef4e9SVivien Didelot 				       ETH_P_EDSA);
23564314557cSVivien Didelot }
23574314557cSVivien Didelot 
23584314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port)
23594314557cSVivien Didelot {
23604314557cSVivien Didelot 	if (dsa_is_dsa_port(chip->ds, port))
23614314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
23624314557cSVivien Didelot 
23632b3e9891SVivien Didelot 	if (dsa_is_user_port(chip->ds, port))
23644314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_normal(chip, port);
23654314557cSVivien Didelot 
23664314557cSVivien Didelot 	/* Setup CPU port mode depending on its supported tag format */
23674314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA)
23684314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
23694314557cSVivien Didelot 
23704314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA)
23714314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_edsa(chip, port);
23724314557cSVivien Didelot 
23734314557cSVivien Didelot 	return -EINVAL;
23744314557cSVivien Didelot }
23754314557cSVivien Didelot 
2376ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
2377ea698f4fSVivien Didelot {
2378ea698f4fSVivien Didelot 	bool message = dsa_is_dsa_port(chip->ds, port);
2379ea698f4fSVivien Didelot 
2380ea698f4fSVivien Didelot 	return mv88e6xxx_port_set_message_port(chip, port, message);
2381ea698f4fSVivien Didelot }
2382ea698f4fSVivien Didelot 
2383601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
2384601aeed3SVivien Didelot {
23853ee50cbfSVivien Didelot 	struct dsa_switch *ds = chip->ds;
2386407308f6SDavid S. Miller 	bool flood;
2387601aeed3SVivien Didelot 
2388407308f6SDavid S. Miller 	/* Upstream ports flood frames with unknown unicast or multicast DA */
2389407308f6SDavid S. Miller 	flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port);
2390407308f6SDavid S. Miller 	if (chip->info->ops->port_set_egress_floods)
2391407308f6SDavid S. Miller 		return chip->info->ops->port_set_egress_floods(chip, port,
2392407308f6SDavid S. Miller 							       flood, flood);
2393407308f6SDavid S. Miller 
2394601aeed3SVivien Didelot 	return 0;
2395601aeed3SVivien Didelot }
2396601aeed3SVivien Didelot 
239745de77ffSVivien Didelot static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
239845de77ffSVivien Didelot {
239945de77ffSVivien Didelot 	struct mv88e6xxx_port *mvp = dev_id;
240045de77ffSVivien Didelot 	struct mv88e6xxx_chip *chip = mvp->chip;
240145de77ffSVivien Didelot 	irqreturn_t ret = IRQ_NONE;
240245de77ffSVivien Didelot 	int port = mvp->port;
240345de77ffSVivien Didelot 	u8 lane;
240445de77ffSVivien Didelot 
240545de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
240645de77ffSVivien Didelot 	lane = mv88e6xxx_serdes_get_lane(chip, port);
240745de77ffSVivien Didelot 	if (lane)
240845de77ffSVivien Didelot 		ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
240945de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
241045de77ffSVivien Didelot 
241145de77ffSVivien Didelot 	return ret;
241245de77ffSVivien Didelot }
241345de77ffSVivien Didelot 
241445de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
241545de77ffSVivien Didelot 					u8 lane)
241645de77ffSVivien Didelot {
241745de77ffSVivien Didelot 	struct mv88e6xxx_port *dev_id = &chip->ports[port];
241845de77ffSVivien Didelot 	unsigned int irq;
241945de77ffSVivien Didelot 	int err;
242045de77ffSVivien Didelot 
242145de77ffSVivien Didelot 	/* Nothing to request if this SERDES port has no IRQ */
242245de77ffSVivien Didelot 	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
242345de77ffSVivien Didelot 	if (!irq)
242445de77ffSVivien Didelot 		return 0;
242545de77ffSVivien Didelot 
2426e6f2f6b8SAndrew Lunn 	snprintf(dev_id->serdes_irq_name, sizeof(dev_id->serdes_irq_name),
2427e6f2f6b8SAndrew Lunn 		 "mv88e6xxx-%s-serdes-%d", dev_name(chip->dev), port);
2428e6f2f6b8SAndrew Lunn 
242945de77ffSVivien Didelot 	/* Requesting the IRQ will trigger IRQ callbacks, so release the lock */
243045de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
243145de77ffSVivien Didelot 	err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn,
2432e6f2f6b8SAndrew Lunn 				   IRQF_ONESHOT, dev_id->serdes_irq_name,
2433e6f2f6b8SAndrew Lunn 				   dev_id);
243445de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
243545de77ffSVivien Didelot 	if (err)
243645de77ffSVivien Didelot 		return err;
243745de77ffSVivien Didelot 
243845de77ffSVivien Didelot 	dev_id->serdes_irq = irq;
243945de77ffSVivien Didelot 
244045de77ffSVivien Didelot 	return mv88e6xxx_serdes_irq_enable(chip, port, lane);
244145de77ffSVivien Didelot }
244245de77ffSVivien Didelot 
244345de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
244445de77ffSVivien Didelot 				     u8 lane)
244545de77ffSVivien Didelot {
244645de77ffSVivien Didelot 	struct mv88e6xxx_port *dev_id = &chip->ports[port];
244745de77ffSVivien Didelot 	unsigned int irq = dev_id->serdes_irq;
244845de77ffSVivien Didelot 	int err;
244945de77ffSVivien Didelot 
245045de77ffSVivien Didelot 	/* Nothing to free if no IRQ has been requested */
245145de77ffSVivien Didelot 	if (!irq)
245245de77ffSVivien Didelot 		return 0;
245345de77ffSVivien Didelot 
245445de77ffSVivien Didelot 	err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
245545de77ffSVivien Didelot 
245645de77ffSVivien Didelot 	/* Freeing the IRQ will trigger IRQ callbacks, so release the lock */
245745de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
245845de77ffSVivien Didelot 	free_irq(irq, dev_id);
245945de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
246045de77ffSVivien Didelot 
246145de77ffSVivien Didelot 	dev_id->serdes_irq = 0;
246245de77ffSVivien Didelot 
246345de77ffSVivien Didelot 	return err;
246445de77ffSVivien Didelot }
246545de77ffSVivien Didelot 
24666d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
24676d91782fSAndrew Lunn 				  bool on)
24686d91782fSAndrew Lunn {
2469dc272f60SVivien Didelot 	u8 lane;
2470fc0bc019SVivien Didelot 	int err;
24716d91782fSAndrew Lunn 
2472dc272f60SVivien Didelot 	lane = mv88e6xxx_serdes_get_lane(chip, port);
2473dc272f60SVivien Didelot 	if (!lane)
2474523a8904SVivien Didelot 		return 0;
2475fc0bc019SVivien Didelot 
2476fc0bc019SVivien Didelot 	if (on) {
2477dc272f60SVivien Didelot 		err = mv88e6xxx_serdes_power_up(chip, port, lane);
2478fc0bc019SVivien Didelot 		if (err)
2479fc0bc019SVivien Didelot 			return err;
2480fc0bc019SVivien Didelot 
248145de77ffSVivien Didelot 		err = mv88e6xxx_serdes_irq_request(chip, port, lane);
2482fc0bc019SVivien Didelot 	} else {
248345de77ffSVivien Didelot 		err = mv88e6xxx_serdes_irq_free(chip, port, lane);
248445de77ffSVivien Didelot 		if (err)
248545de77ffSVivien Didelot 			return err;
2486fc0bc019SVivien Didelot 
2487dc272f60SVivien Didelot 		err = mv88e6xxx_serdes_power_down(chip, port, lane);
2488fc0bc019SVivien Didelot 	}
2489fc0bc019SVivien Didelot 
2490fc0bc019SVivien Didelot 	return err;
24916d91782fSAndrew Lunn }
24926d91782fSAndrew Lunn 
2493fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
2494fa371c80SVivien Didelot {
2495fa371c80SVivien Didelot 	struct dsa_switch *ds = chip->ds;
2496fa371c80SVivien Didelot 	int upstream_port;
2497fa371c80SVivien Didelot 	int err;
2498fa371c80SVivien Didelot 
249907073c79SVivien Didelot 	upstream_port = dsa_upstream_port(ds, port);
2500fa371c80SVivien Didelot 	if (chip->info->ops->port_set_upstream_port) {
2501fa371c80SVivien Didelot 		err = chip->info->ops->port_set_upstream_port(chip, port,
2502fa371c80SVivien Didelot 							      upstream_port);
2503fa371c80SVivien Didelot 		if (err)
2504fa371c80SVivien Didelot 			return err;
2505fa371c80SVivien Didelot 	}
2506fa371c80SVivien Didelot 
25070ea54ddaSVivien Didelot 	if (port == upstream_port) {
25080ea54ddaSVivien Didelot 		if (chip->info->ops->set_cpu_port) {
25090ea54ddaSVivien Didelot 			err = chip->info->ops->set_cpu_port(chip,
25100ea54ddaSVivien Didelot 							    upstream_port);
25110ea54ddaSVivien Didelot 			if (err)
25120ea54ddaSVivien Didelot 				return err;
25130ea54ddaSVivien Didelot 		}
25140ea54ddaSVivien Didelot 
25150ea54ddaSVivien Didelot 		if (chip->info->ops->set_egress_port) {
25160ea54ddaSVivien Didelot 			err = chip->info->ops->set_egress_port(chip,
25175c74c54cSIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS,
25185c74c54cSIwan R Timmer 						upstream_port);
25195c74c54cSIwan R Timmer 			if (err)
25205c74c54cSIwan R Timmer 				return err;
25215c74c54cSIwan R Timmer 
25225c74c54cSIwan R Timmer 			err = chip->info->ops->set_egress_port(chip,
25235c74c54cSIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS,
25240ea54ddaSVivien Didelot 						upstream_port);
25250ea54ddaSVivien Didelot 			if (err)
25260ea54ddaSVivien Didelot 				return err;
25270ea54ddaSVivien Didelot 		}
25280ea54ddaSVivien Didelot 	}
25290ea54ddaSVivien Didelot 
2530fa371c80SVivien Didelot 	return 0;
2531fa371c80SVivien Didelot }
2532fa371c80SVivien Didelot 
2533fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
2534fad09c73SVivien Didelot {
2535fad09c73SVivien Didelot 	struct dsa_switch *ds = chip->ds;
25360e7b9925SAndrew Lunn 	int err;
2537fad09c73SVivien Didelot 	u16 reg;
2538fad09c73SVivien Didelot 
25397b898469SAndrew Lunn 	chip->ports[port].chip = chip;
25407b898469SAndrew Lunn 	chip->ports[port].port = port;
25417b898469SAndrew Lunn 
2542d78343d2SVivien Didelot 	/* MAC Forcing register: don't force link, speed, duplex or flow control
2543d78343d2SVivien Didelot 	 * state to any particular values on physical ports, but force the CPU
2544d78343d2SVivien Didelot 	 * port and all DSA ports to their maximum bandwidth and full duplex.
2545fad09c73SVivien Didelot 	 */
2546d78343d2SVivien Didelot 	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
2547d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
2548d78343d2SVivien Didelot 					       SPEED_MAX, DUPLEX_FULL,
254954186b91SAndrew Lunn 					       PAUSE_OFF,
2550d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
2551fad09c73SVivien Didelot 	else
2552d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
2553d78343d2SVivien Didelot 					       SPEED_UNFORCED, DUPLEX_UNFORCED,
255454186b91SAndrew Lunn 					       PAUSE_ON,
2555d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
25560e7b9925SAndrew Lunn 	if (err)
25570e7b9925SAndrew Lunn 		return err;
2558fad09c73SVivien Didelot 
2559fad09c73SVivien Didelot 	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
2560fad09c73SVivien Didelot 	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
2561fad09c73SVivien Didelot 	 * tunneling, determine priority by looking at 802.1p and IP
2562fad09c73SVivien Didelot 	 * priority fields (IP prio has precedence), and set STP state
2563fad09c73SVivien Didelot 	 * to Forwarding.
2564fad09c73SVivien Didelot 	 *
2565fad09c73SVivien Didelot 	 * If this is the CPU link, use DSA or EDSA tagging depending
2566fad09c73SVivien Didelot 	 * on which tagging mode was configured.
2567fad09c73SVivien Didelot 	 *
2568fad09c73SVivien Didelot 	 * If this is a link to another switch, use DSA tagging mode.
2569fad09c73SVivien Didelot 	 *
2570fad09c73SVivien Didelot 	 * If this is the upstream port for this switch, enable
2571fad09c73SVivien Didelot 	 * forwarding of unknown unicasts and multicasts.
2572fad09c73SVivien Didelot 	 */
2573a89b433bSVivien Didelot 	reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP |
2574a89b433bSVivien Didelot 		MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
2575a89b433bSVivien Didelot 		MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
2576a89b433bSVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
25770e7b9925SAndrew Lunn 	if (err)
25780e7b9925SAndrew Lunn 		return err;
257956995cbcSAndrew Lunn 
2580601aeed3SVivien Didelot 	err = mv88e6xxx_setup_port_mode(chip, port);
258156995cbcSAndrew Lunn 	if (err)
258256995cbcSAndrew Lunn 		return err;
2583fad09c73SVivien Didelot 
2584601aeed3SVivien Didelot 	err = mv88e6xxx_setup_egress_floods(chip, port);
25854314557cSVivien Didelot 	if (err)
25864314557cSVivien Didelot 		return err;
25874314557cSVivien Didelot 
2588fad09c73SVivien Didelot 	/* Port Control 2: don't force a good FCS, set the maximum frame size to
2589fad09c73SVivien Didelot 	 * 10240 bytes, disable 802.1q tags checking, don't discard tagged or
2590fad09c73SVivien Didelot 	 * untagged frames on this port, do a destination address lookup on all
2591fad09c73SVivien Didelot 	 * received packets as usual, disable ARP mirroring and don't send a
2592fad09c73SVivien Didelot 	 * copy of all transmitted/received frames on this port to the CPU.
2593fad09c73SVivien Didelot 	 */
2594a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_map_da(chip, port);
2595a23b2961SAndrew Lunn 	if (err)
2596a23b2961SAndrew Lunn 		return err;
2597a23b2961SAndrew Lunn 
2598fa371c80SVivien Didelot 	err = mv88e6xxx_setup_upstream_port(chip, port);
25990e7b9925SAndrew Lunn 	if (err)
26000e7b9925SAndrew Lunn 		return err;
2601fad09c73SVivien Didelot 
2602a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_8021q_mode(chip, port,
260381c6edb2SVivien Didelot 				MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED);
2604a23b2961SAndrew Lunn 	if (err)
2605a23b2961SAndrew Lunn 		return err;
2606a23b2961SAndrew Lunn 
2607cd782656SVivien Didelot 	if (chip->info->ops->port_set_jumbo_size) {
2608cd782656SVivien Didelot 		err = chip->info->ops->port_set_jumbo_size(chip, port, 10240);
26095f436666SAndrew Lunn 		if (err)
26105f436666SAndrew Lunn 			return err;
26115f436666SAndrew Lunn 	}
26125f436666SAndrew Lunn 
2613fad09c73SVivien Didelot 	/* Port Association Vector: when learning source addresses
2614fad09c73SVivien Didelot 	 * of packets, add the address to the address database using
2615fad09c73SVivien Didelot 	 * a port bitmap that has only the bit for this port set and
2616fad09c73SVivien Didelot 	 * the other bits clear.
2617fad09c73SVivien Didelot 	 */
2618fad09c73SVivien Didelot 	reg = 1 << port;
2619fad09c73SVivien Didelot 	/* Disable learning for CPU port */
2620fad09c73SVivien Didelot 	if (dsa_is_cpu_port(ds, port))
2621fad09c73SVivien Didelot 		reg = 0;
2622fad09c73SVivien Didelot 
26232a4614e4SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
26242a4614e4SVivien Didelot 				   reg);
26250e7b9925SAndrew Lunn 	if (err)
26260e7b9925SAndrew Lunn 		return err;
2627fad09c73SVivien Didelot 
2628fad09c73SVivien Didelot 	/* Egress rate control 2: disable egress rate control. */
26292cb8cb14SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2,
26302cb8cb14SVivien Didelot 				   0x0000);
26310e7b9925SAndrew Lunn 	if (err)
26320e7b9925SAndrew Lunn 		return err;
2633fad09c73SVivien Didelot 
26340898432cSVivien Didelot 	if (chip->info->ops->port_pause_limit) {
26350898432cSVivien Didelot 		err = chip->info->ops->port_pause_limit(chip, port, 0, 0);
2636b35d322aSAndrew Lunn 		if (err)
2637b35d322aSAndrew Lunn 			return err;
2638b35d322aSAndrew Lunn 	}
2639b35d322aSAndrew Lunn 
2640c8c94891SVivien Didelot 	if (chip->info->ops->port_disable_learn_limit) {
2641c8c94891SVivien Didelot 		err = chip->info->ops->port_disable_learn_limit(chip, port);
2642c8c94891SVivien Didelot 		if (err)
2643c8c94891SVivien Didelot 			return err;
2644c8c94891SVivien Didelot 	}
2645c8c94891SVivien Didelot 
26469dbfb4e1SVivien Didelot 	if (chip->info->ops->port_disable_pri_override) {
26479dbfb4e1SVivien Didelot 		err = chip->info->ops->port_disable_pri_override(chip, port);
26480e7b9925SAndrew Lunn 		if (err)
26490e7b9925SAndrew Lunn 			return err;
2650ef0a7318SAndrew Lunn 	}
26512bbb33beSAndrew Lunn 
2652ef0a7318SAndrew Lunn 	if (chip->info->ops->port_tag_remap) {
2653ef0a7318SAndrew Lunn 		err = chip->info->ops->port_tag_remap(chip, port);
26540e7b9925SAndrew Lunn 		if (err)
26550e7b9925SAndrew Lunn 			return err;
2656fad09c73SVivien Didelot 	}
2657fad09c73SVivien Didelot 
2658ef70b111SAndrew Lunn 	if (chip->info->ops->port_egress_rate_limiting) {
2659ef70b111SAndrew Lunn 		err = chip->info->ops->port_egress_rate_limiting(chip, port);
26600e7b9925SAndrew Lunn 		if (err)
26610e7b9925SAndrew Lunn 			return err;
2662fad09c73SVivien Didelot 	}
2663fad09c73SVivien Didelot 
2664121b8fe2SHubert Feurstein 	if (chip->info->ops->port_setup_message_port) {
2665121b8fe2SHubert Feurstein 		err = chip->info->ops->port_setup_message_port(chip, port);
26660e7b9925SAndrew Lunn 		if (err)
26670e7b9925SAndrew Lunn 			return err;
2668121b8fe2SHubert Feurstein 	}
2669fad09c73SVivien Didelot 
2670fad09c73SVivien Didelot 	/* Port based VLAN map: give each port the same default address
2671fad09c73SVivien Didelot 	 * database, and allow bidirectional communication between the
2672fad09c73SVivien Didelot 	 * CPU and DSA port(s), and the other ports.
2673fad09c73SVivien Didelot 	 */
2674b4e48c50SVivien Didelot 	err = mv88e6xxx_port_set_fid(chip, port, 0);
26750e7b9925SAndrew Lunn 	if (err)
26760e7b9925SAndrew Lunn 		return err;
2677fad09c73SVivien Didelot 
2678240ea3efSVivien Didelot 	err = mv88e6xxx_port_vlan_map(chip, port);
26790e7b9925SAndrew Lunn 	if (err)
26800e7b9925SAndrew Lunn 		return err;
2681fad09c73SVivien Didelot 
2682fad09c73SVivien Didelot 	/* Default VLAN ID and priority: don't set a default VLAN
2683fad09c73SVivien Didelot 	 * ID, and set the default packet priority to zero.
2684fad09c73SVivien Didelot 	 */
2685b7929fb3SVivien Didelot 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0);
2686fad09c73SVivien Didelot }
2687fad09c73SVivien Didelot 
268804aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
268904aca993SAndrew Lunn 				 struct phy_device *phydev)
269004aca993SAndrew Lunn {
269104aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
2692523a8904SVivien Didelot 	int err;
269304aca993SAndrew Lunn 
2694c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2695523a8904SVivien Didelot 	err = mv88e6xxx_serdes_power(chip, port, true);
2696c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
269704aca993SAndrew Lunn 
269804aca993SAndrew Lunn 	return err;
269904aca993SAndrew Lunn }
270004aca993SAndrew Lunn 
270175104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
270204aca993SAndrew Lunn {
270304aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
270404aca993SAndrew Lunn 
2705c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2706523a8904SVivien Didelot 	if (mv88e6xxx_serdes_power(chip, port, false))
2707523a8904SVivien Didelot 		dev_err(chip->dev, "failed to power off SERDES\n");
2708c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
270904aca993SAndrew Lunn }
271004aca993SAndrew Lunn 
27112cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
27122cfcd964SVivien Didelot 				     unsigned int ageing_time)
27132cfcd964SVivien Didelot {
271404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
27152cfcd964SVivien Didelot 	int err;
27162cfcd964SVivien Didelot 
2717c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2718720c6343SVivien Didelot 	err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
2719c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
27202cfcd964SVivien Didelot 
27212cfcd964SVivien Didelot 	return err;
27222cfcd964SVivien Didelot }
27232cfcd964SVivien Didelot 
2724447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
2725fad09c73SVivien Didelot {
2726fad09c73SVivien Didelot 	int err;
2727fad09c73SVivien Didelot 
2728de227387SAndrew Lunn 	/* Initialize the statistics unit */
2729447b1bb8SVivien Didelot 	if (chip->info->ops->stats_set_histogram) {
2730447b1bb8SVivien Didelot 		err = chip->info->ops->stats_set_histogram(chip);
2731de227387SAndrew Lunn 		if (err)
2732de227387SAndrew Lunn 			return err;
2733447b1bb8SVivien Didelot 	}
2734de227387SAndrew Lunn 
273540cff8fcSAndrew Lunn 	return mv88e6xxx_g1_stats_clear(chip);
27369729934cSVivien Didelot }
27379729934cSVivien Didelot 
2738ea89098eSAndrew Lunn /* Check if the errata has already been applied. */
2739ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
2740ea89098eSAndrew Lunn {
2741ea89098eSAndrew Lunn 	int port;
2742ea89098eSAndrew Lunn 	int err;
2743ea89098eSAndrew Lunn 	u16 val;
2744ea89098eSAndrew Lunn 
2745ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
274660907013SMarek Behún 		err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val);
2747ea89098eSAndrew Lunn 		if (err) {
2748ea89098eSAndrew Lunn 			dev_err(chip->dev,
2749ea89098eSAndrew Lunn 				"Error reading hidden register: %d\n", err);
2750ea89098eSAndrew Lunn 			return false;
2751ea89098eSAndrew Lunn 		}
2752ea89098eSAndrew Lunn 		if (val != 0x01c0)
2753ea89098eSAndrew Lunn 			return false;
2754ea89098eSAndrew Lunn 	}
2755ea89098eSAndrew Lunn 
2756ea89098eSAndrew Lunn 	return true;
2757ea89098eSAndrew Lunn }
2758ea89098eSAndrew Lunn 
2759ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic
2760ea89098eSAndrew Lunn  * values into undocumented hidden registers and then performing a
2761ea89098eSAndrew Lunn  * software reset.
2762ea89098eSAndrew Lunn  */
2763ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
2764ea89098eSAndrew Lunn {
2765ea89098eSAndrew Lunn 	int port;
2766ea89098eSAndrew Lunn 	int err;
2767ea89098eSAndrew Lunn 
2768ea89098eSAndrew Lunn 	if (mv88e6390_setup_errata_applied(chip))
2769ea89098eSAndrew Lunn 		return 0;
2770ea89098eSAndrew Lunn 
2771ea89098eSAndrew Lunn 	/* Set the ports into blocking mode */
2772ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
2773ea89098eSAndrew Lunn 		err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED);
2774ea89098eSAndrew Lunn 		if (err)
2775ea89098eSAndrew Lunn 			return err;
2776ea89098eSAndrew Lunn 	}
2777ea89098eSAndrew Lunn 
2778ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
277960907013SMarek Behún 		err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0);
2780ea89098eSAndrew Lunn 		if (err)
2781ea89098eSAndrew Lunn 			return err;
2782ea89098eSAndrew Lunn 	}
2783ea89098eSAndrew Lunn 
2784ea89098eSAndrew Lunn 	return mv88e6xxx_software_reset(chip);
2785ea89098eSAndrew Lunn }
2786ea89098eSAndrew Lunn 
278723e8b470SAndrew Lunn enum mv88e6xxx_devlink_param_id {
278823e8b470SAndrew Lunn 	MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
278923e8b470SAndrew Lunn 	MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
279023e8b470SAndrew Lunn };
279123e8b470SAndrew Lunn 
279223e8b470SAndrew Lunn static int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id,
279323e8b470SAndrew Lunn 				       struct devlink_param_gset_ctx *ctx)
279423e8b470SAndrew Lunn {
279523e8b470SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
279623e8b470SAndrew Lunn 	int err;
279723e8b470SAndrew Lunn 
279823e8b470SAndrew Lunn 	mv88e6xxx_reg_lock(chip);
279923e8b470SAndrew Lunn 
280023e8b470SAndrew Lunn 	switch (id) {
280123e8b470SAndrew Lunn 	case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
280223e8b470SAndrew Lunn 		err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8);
280323e8b470SAndrew Lunn 		break;
280423e8b470SAndrew Lunn 	default:
280523e8b470SAndrew Lunn 		err = -EOPNOTSUPP;
280623e8b470SAndrew Lunn 		break;
280723e8b470SAndrew Lunn 	}
280823e8b470SAndrew Lunn 
280923e8b470SAndrew Lunn 	mv88e6xxx_reg_unlock(chip);
281023e8b470SAndrew Lunn 
281123e8b470SAndrew Lunn 	return err;
281223e8b470SAndrew Lunn }
281323e8b470SAndrew Lunn 
281423e8b470SAndrew Lunn static int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id,
281523e8b470SAndrew Lunn 				       struct devlink_param_gset_ctx *ctx)
281623e8b470SAndrew Lunn {
281723e8b470SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
281823e8b470SAndrew Lunn 	int err;
281923e8b470SAndrew Lunn 
282023e8b470SAndrew Lunn 	mv88e6xxx_reg_lock(chip);
282123e8b470SAndrew Lunn 
282223e8b470SAndrew Lunn 	switch (id) {
282323e8b470SAndrew Lunn 	case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
282423e8b470SAndrew Lunn 		err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8);
282523e8b470SAndrew Lunn 		break;
282623e8b470SAndrew Lunn 	default:
282723e8b470SAndrew Lunn 		err = -EOPNOTSUPP;
282823e8b470SAndrew Lunn 		break;
282923e8b470SAndrew Lunn 	}
283023e8b470SAndrew Lunn 
283123e8b470SAndrew Lunn 	mv88e6xxx_reg_unlock(chip);
283223e8b470SAndrew Lunn 
283323e8b470SAndrew Lunn 	return err;
283423e8b470SAndrew Lunn }
283523e8b470SAndrew Lunn 
283623e8b470SAndrew Lunn static const struct devlink_param mv88e6xxx_devlink_params[] = {
283723e8b470SAndrew Lunn 	DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
283823e8b470SAndrew Lunn 				 "ATU_hash", DEVLINK_PARAM_TYPE_U8,
283923e8b470SAndrew Lunn 				 BIT(DEVLINK_PARAM_CMODE_RUNTIME)),
284023e8b470SAndrew Lunn };
284123e8b470SAndrew Lunn 
284223e8b470SAndrew Lunn static int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds)
284323e8b470SAndrew Lunn {
284423e8b470SAndrew Lunn 	return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params,
284523e8b470SAndrew Lunn 					   ARRAY_SIZE(mv88e6xxx_devlink_params));
284623e8b470SAndrew Lunn }
284723e8b470SAndrew Lunn 
284823e8b470SAndrew Lunn static void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds)
284923e8b470SAndrew Lunn {
285023e8b470SAndrew Lunn 	dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params,
285123e8b470SAndrew Lunn 				      ARRAY_SIZE(mv88e6xxx_devlink_params));
285223e8b470SAndrew Lunn }
285323e8b470SAndrew Lunn 
2854e0c69ca7SAndrew Lunn enum mv88e6xxx_devlink_resource_id {
2855e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU,
2856e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
2857e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
2858e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
2859e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
2860e0c69ca7SAndrew Lunn };
2861e0c69ca7SAndrew Lunn 
2862e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip,
2863e0c69ca7SAndrew Lunn 					 u16 bin)
2864e0c69ca7SAndrew Lunn {
2865e0c69ca7SAndrew Lunn 	u16 occupancy = 0;
2866e0c69ca7SAndrew Lunn 	int err;
2867e0c69ca7SAndrew Lunn 
2868e0c69ca7SAndrew Lunn 	mv88e6xxx_reg_lock(chip);
2869e0c69ca7SAndrew Lunn 
2870e0c69ca7SAndrew Lunn 	err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL,
2871e0c69ca7SAndrew Lunn 					 bin);
2872e0c69ca7SAndrew Lunn 	if (err) {
2873e0c69ca7SAndrew Lunn 		dev_err(chip->dev, "failed to set ATU stats kind/bin\n");
2874e0c69ca7SAndrew Lunn 		goto unlock;
2875e0c69ca7SAndrew Lunn 	}
2876e0c69ca7SAndrew Lunn 
2877e0c69ca7SAndrew Lunn 	err = mv88e6xxx_g1_atu_get_next(chip, 0);
2878e0c69ca7SAndrew Lunn 	if (err) {
2879e0c69ca7SAndrew Lunn 		dev_err(chip->dev, "failed to perform ATU get next\n");
2880e0c69ca7SAndrew Lunn 		goto unlock;
2881e0c69ca7SAndrew Lunn 	}
2882e0c69ca7SAndrew Lunn 
2883e0c69ca7SAndrew Lunn 	err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy);
2884e0c69ca7SAndrew Lunn 	if (err) {
2885e0c69ca7SAndrew Lunn 		dev_err(chip->dev, "failed to get ATU stats\n");
2886e0c69ca7SAndrew Lunn 		goto unlock;
2887e0c69ca7SAndrew Lunn 	}
2888e0c69ca7SAndrew Lunn 
2889012fc745SAndrew Lunn 	occupancy &= MV88E6XXX_G2_ATU_STATS_MASK;
2890012fc745SAndrew Lunn 
2891e0c69ca7SAndrew Lunn unlock:
2892e0c69ca7SAndrew Lunn 	mv88e6xxx_reg_unlock(chip);
2893e0c69ca7SAndrew Lunn 
2894e0c69ca7SAndrew Lunn 	return occupancy;
2895e0c69ca7SAndrew Lunn }
2896e0c69ca7SAndrew Lunn 
2897e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv)
2898e0c69ca7SAndrew Lunn {
2899e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = priv;
2900e0c69ca7SAndrew Lunn 
2901e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_get(chip,
2902e0c69ca7SAndrew Lunn 					     MV88E6XXX_G2_ATU_STATS_BIN_0);
2903e0c69ca7SAndrew Lunn }
2904e0c69ca7SAndrew Lunn 
2905e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv)
2906e0c69ca7SAndrew Lunn {
2907e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = priv;
2908e0c69ca7SAndrew Lunn 
2909e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_get(chip,
2910e0c69ca7SAndrew Lunn 					     MV88E6XXX_G2_ATU_STATS_BIN_1);
2911e0c69ca7SAndrew Lunn }
2912e0c69ca7SAndrew Lunn 
2913e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv)
2914e0c69ca7SAndrew Lunn {
2915e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = priv;
2916e0c69ca7SAndrew Lunn 
2917e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_get(chip,
2918e0c69ca7SAndrew Lunn 					     MV88E6XXX_G2_ATU_STATS_BIN_2);
2919e0c69ca7SAndrew Lunn }
2920e0c69ca7SAndrew Lunn 
2921e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv)
2922e0c69ca7SAndrew Lunn {
2923e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = priv;
2924e0c69ca7SAndrew Lunn 
2925e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_get(chip,
2926e0c69ca7SAndrew Lunn 					     MV88E6XXX_G2_ATU_STATS_BIN_3);
2927e0c69ca7SAndrew Lunn }
2928e0c69ca7SAndrew Lunn 
2929e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_get(void *priv)
2930e0c69ca7SAndrew Lunn {
2931e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_0_get(priv) +
2932e0c69ca7SAndrew Lunn 		mv88e6xxx_devlink_atu_bin_1_get(priv) +
2933e0c69ca7SAndrew Lunn 		mv88e6xxx_devlink_atu_bin_2_get(priv) +
2934e0c69ca7SAndrew Lunn 		mv88e6xxx_devlink_atu_bin_3_get(priv);
2935e0c69ca7SAndrew Lunn }
2936e0c69ca7SAndrew Lunn 
2937e0c69ca7SAndrew Lunn static int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds)
2938e0c69ca7SAndrew Lunn {
2939e0c69ca7SAndrew Lunn 	struct devlink_resource_size_params size_params;
2940e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
2941e0c69ca7SAndrew Lunn 	int err;
2942e0c69ca7SAndrew Lunn 
2943e0c69ca7SAndrew Lunn 	devlink_resource_size_params_init(&size_params,
2944e0c69ca7SAndrew Lunn 					  mv88e6xxx_num_macs(chip),
2945e0c69ca7SAndrew Lunn 					  mv88e6xxx_num_macs(chip),
2946e0c69ca7SAndrew Lunn 					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
2947e0c69ca7SAndrew Lunn 
2948e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU",
2949e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip),
2950e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2951e0c69ca7SAndrew Lunn 					    DEVLINK_RESOURCE_ID_PARENT_TOP,
2952e0c69ca7SAndrew Lunn 					    &size_params);
2953e0c69ca7SAndrew Lunn 	if (err)
2954e0c69ca7SAndrew Lunn 		goto out;
2955e0c69ca7SAndrew Lunn 
2956e0c69ca7SAndrew Lunn 	devlink_resource_size_params_init(&size_params,
2957e0c69ca7SAndrew Lunn 					  mv88e6xxx_num_macs(chip) / 4,
2958e0c69ca7SAndrew Lunn 					  mv88e6xxx_num_macs(chip) / 4,
2959e0c69ca7SAndrew Lunn 					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
2960e0c69ca7SAndrew Lunn 
2961e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU_bin_0",
2962e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip) / 4,
2963e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
2964e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2965e0c69ca7SAndrew Lunn 					    &size_params);
2966e0c69ca7SAndrew Lunn 	if (err)
2967e0c69ca7SAndrew Lunn 		goto out;
2968e0c69ca7SAndrew Lunn 
2969e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU_bin_1",
2970e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip) / 4,
2971e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
2972e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2973e0c69ca7SAndrew Lunn 					    &size_params);
2974e0c69ca7SAndrew Lunn 	if (err)
2975e0c69ca7SAndrew Lunn 		goto out;
2976e0c69ca7SAndrew Lunn 
2977e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU_bin_2",
2978e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip) / 4,
2979e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
2980e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2981e0c69ca7SAndrew Lunn 					    &size_params);
2982e0c69ca7SAndrew Lunn 	if (err)
2983e0c69ca7SAndrew Lunn 		goto out;
2984e0c69ca7SAndrew Lunn 
2985e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU_bin_3",
2986e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip) / 4,
2987e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
2988e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2989e0c69ca7SAndrew Lunn 					    &size_params);
2990e0c69ca7SAndrew Lunn 	if (err)
2991e0c69ca7SAndrew Lunn 		goto out;
2992e0c69ca7SAndrew Lunn 
2993e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
2994e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU,
2995e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_get,
2996e0c69ca7SAndrew Lunn 					      chip);
2997e0c69ca7SAndrew Lunn 
2998e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
2999e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
3000e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_bin_0_get,
3001e0c69ca7SAndrew Lunn 					      chip);
3002e0c69ca7SAndrew Lunn 
3003e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
3004e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
3005e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_bin_1_get,
3006e0c69ca7SAndrew Lunn 					      chip);
3007e0c69ca7SAndrew Lunn 
3008e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
3009e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
3010e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_bin_2_get,
3011e0c69ca7SAndrew Lunn 					      chip);
3012e0c69ca7SAndrew Lunn 
3013e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
3014e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
3015e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_bin_3_get,
3016e0c69ca7SAndrew Lunn 					      chip);
3017e0c69ca7SAndrew Lunn 
3018e0c69ca7SAndrew Lunn 	return 0;
3019e0c69ca7SAndrew Lunn 
3020e0c69ca7SAndrew Lunn out:
3021e0c69ca7SAndrew Lunn 	dsa_devlink_resources_unregister(ds);
3022e0c69ca7SAndrew Lunn 	return err;
3023e0c69ca7SAndrew Lunn }
3024e0c69ca7SAndrew Lunn 
302523e8b470SAndrew Lunn static void mv88e6xxx_teardown(struct dsa_switch *ds)
302623e8b470SAndrew Lunn {
302723e8b470SAndrew Lunn 	mv88e6xxx_teardown_devlink_params(ds);
3028e0c69ca7SAndrew Lunn 	dsa_devlink_resources_unregister(ds);
302923e8b470SAndrew Lunn }
303023e8b470SAndrew Lunn 
3031fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds)
3032fad09c73SVivien Didelot {
303304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
30342d2e1dd2SAndrew Lunn 	u8 cmode;
3035fad09c73SVivien Didelot 	int err;
3036fad09c73SVivien Didelot 	int i;
3037fad09c73SVivien Didelot 
3038fad09c73SVivien Didelot 	chip->ds = ds;
3039a3c53be5SAndrew Lunn 	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
3040fad09c73SVivien Didelot 
3041c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3042fad09c73SVivien Didelot 
3043ea89098eSAndrew Lunn 	if (chip->info->ops->setup_errata) {
3044ea89098eSAndrew Lunn 		err = chip->info->ops->setup_errata(chip);
3045ea89098eSAndrew Lunn 		if (err)
3046ea89098eSAndrew Lunn 			goto unlock;
3047ea89098eSAndrew Lunn 	}
3048ea89098eSAndrew Lunn 
30492d2e1dd2SAndrew Lunn 	/* Cache the cmode of each port. */
30502d2e1dd2SAndrew Lunn 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
30512d2e1dd2SAndrew Lunn 		if (chip->info->ops->port_get_cmode) {
30522d2e1dd2SAndrew Lunn 			err = chip->info->ops->port_get_cmode(chip, i, &cmode);
30532d2e1dd2SAndrew Lunn 			if (err)
3054e29129fcSDan Carpenter 				goto unlock;
30552d2e1dd2SAndrew Lunn 
30562d2e1dd2SAndrew Lunn 			chip->ports[i].cmode = cmode;
30572d2e1dd2SAndrew Lunn 		}
30582d2e1dd2SAndrew Lunn 	}
30592d2e1dd2SAndrew Lunn 
30609729934cSVivien Didelot 	/* Setup Switch Port Registers */
3061370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
3062b759f528SVivien Didelot 		if (dsa_is_unused_port(ds, i))
3063b759f528SVivien Didelot 			continue;
3064b759f528SVivien Didelot 
3065c857486aSHubert Feurstein 		/* Prevent the use of an invalid port. */
3066b759f528SVivien Didelot 		if (mv88e6xxx_is_invalid_port(chip, i)) {
3067c857486aSHubert Feurstein 			dev_err(chip->dev, "port %d is invalid\n", i);
3068c857486aSHubert Feurstein 			err = -EINVAL;
3069c857486aSHubert Feurstein 			goto unlock;
3070c857486aSHubert Feurstein 		}
3071c857486aSHubert Feurstein 
30729729934cSVivien Didelot 		err = mv88e6xxx_setup_port(chip, i);
30739729934cSVivien Didelot 		if (err)
30749729934cSVivien Didelot 			goto unlock;
30759729934cSVivien Didelot 	}
30769729934cSVivien Didelot 
3077cd8da8bbSVivien Didelot 	err = mv88e6xxx_irl_setup(chip);
3078cd8da8bbSVivien Didelot 	if (err)
3079cd8da8bbSVivien Didelot 		goto unlock;
3080cd8da8bbSVivien Didelot 
308104a69a17SVivien Didelot 	err = mv88e6xxx_mac_setup(chip);
308204a69a17SVivien Didelot 	if (err)
308304a69a17SVivien Didelot 		goto unlock;
308404a69a17SVivien Didelot 
30851b17aedfSVivien Didelot 	err = mv88e6xxx_phy_setup(chip);
30861b17aedfSVivien Didelot 	if (err)
30871b17aedfSVivien Didelot 		goto unlock;
30881b17aedfSVivien Didelot 
3089b486d7c9SVivien Didelot 	err = mv88e6xxx_vtu_setup(chip);
3090b486d7c9SVivien Didelot 	if (err)
3091b486d7c9SVivien Didelot 		goto unlock;
3092b486d7c9SVivien Didelot 
309381228996SVivien Didelot 	err = mv88e6xxx_pvt_setup(chip);
309481228996SVivien Didelot 	if (err)
309581228996SVivien Didelot 		goto unlock;
309681228996SVivien Didelot 
3097a2ac29d2SVivien Didelot 	err = mv88e6xxx_atu_setup(chip);
3098a2ac29d2SVivien Didelot 	if (err)
3099a2ac29d2SVivien Didelot 		goto unlock;
3100a2ac29d2SVivien Didelot 
310187fa886eSAndrew Lunn 	err = mv88e6xxx_broadcast_setup(chip, 0);
310287fa886eSAndrew Lunn 	if (err)
310387fa886eSAndrew Lunn 		goto unlock;
310487fa886eSAndrew Lunn 
31059e907d73SVivien Didelot 	err = mv88e6xxx_pot_setup(chip);
31069e907d73SVivien Didelot 	if (err)
31079e907d73SVivien Didelot 		goto unlock;
31089e907d73SVivien Didelot 
31099e5baf9bSVivien Didelot 	err = mv88e6xxx_rmu_setup(chip);
31109e5baf9bSVivien Didelot 	if (err)
31119e5baf9bSVivien Didelot 		goto unlock;
31129e5baf9bSVivien Didelot 
311351c901a7SVivien Didelot 	err = mv88e6xxx_rsvd2cpu_setup(chip);
31146e55f698SAndrew Lunn 	if (err)
31156e55f698SAndrew Lunn 		goto unlock;
31166e55f698SAndrew Lunn 
3117b28f872dSVivien Didelot 	err = mv88e6xxx_trunk_setup(chip);
3118b28f872dSVivien Didelot 	if (err)
3119b28f872dSVivien Didelot 		goto unlock;
3120b28f872dSVivien Didelot 
3121c7f047b6SVivien Didelot 	err = mv88e6xxx_devmap_setup(chip);
3122c7f047b6SVivien Didelot 	if (err)
3123c7f047b6SVivien Didelot 		goto unlock;
3124c7f047b6SVivien Didelot 
312593e18d61SVivien Didelot 	err = mv88e6xxx_pri_setup(chip);
312693e18d61SVivien Didelot 	if (err)
312793e18d61SVivien Didelot 		goto unlock;
312893e18d61SVivien Didelot 
3129c6fe0ad2SBrandon Streiff 	/* Setup PTP Hardware Clock and timestamping */
31302fa8d3afSBrandon Streiff 	if (chip->info->ptp_support) {
31312fa8d3afSBrandon Streiff 		err = mv88e6xxx_ptp_setup(chip);
31322fa8d3afSBrandon Streiff 		if (err)
31332fa8d3afSBrandon Streiff 			goto unlock;
3134c6fe0ad2SBrandon Streiff 
3135c6fe0ad2SBrandon Streiff 		err = mv88e6xxx_hwtstamp_setup(chip);
3136c6fe0ad2SBrandon Streiff 		if (err)
3137c6fe0ad2SBrandon Streiff 			goto unlock;
31382fa8d3afSBrandon Streiff 	}
31392fa8d3afSBrandon Streiff 
3140447b1bb8SVivien Didelot 	err = mv88e6xxx_stats_setup(chip);
3141447b1bb8SVivien Didelot 	if (err)
3142447b1bb8SVivien Didelot 		goto unlock;
3143447b1bb8SVivien Didelot 
3144fad09c73SVivien Didelot unlock:
3145c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3146fad09c73SVivien Didelot 
3147e0c69ca7SAndrew Lunn 	if (err)
3148e0c69ca7SAndrew Lunn 		return err;
3149e0c69ca7SAndrew Lunn 
3150e0c69ca7SAndrew Lunn 	/* Have to be called without holding the register lock, since
3151e0c69ca7SAndrew Lunn 	 * they take the devlink lock, and we later take the locks in
3152e0c69ca7SAndrew Lunn 	 * the reverse order when getting/setting parameters or
3153e0c69ca7SAndrew Lunn 	 * resource occupancy.
315423e8b470SAndrew Lunn 	 */
3155e0c69ca7SAndrew Lunn 	err = mv88e6xxx_setup_devlink_resources(ds);
3156e0c69ca7SAndrew Lunn 	if (err)
3157e0c69ca7SAndrew Lunn 		return err;
3158e0c69ca7SAndrew Lunn 
3159e0c69ca7SAndrew Lunn 	err = mv88e6xxx_setup_devlink_params(ds);
3160e0c69ca7SAndrew Lunn 	if (err)
3161e0c69ca7SAndrew Lunn 		dsa_devlink_resources_unregister(ds);
3162e0c69ca7SAndrew Lunn 
3163e0c69ca7SAndrew Lunn 	return err;
3164fad09c73SVivien Didelot }
3165fad09c73SVivien Didelot 
3166e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
3167fad09c73SVivien Didelot {
31680dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
31690dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
3170e57e5e77SVivien Didelot 	u16 val;
3171e57e5e77SVivien Didelot 	int err;
3172fad09c73SVivien Didelot 
3173ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_read)
3174ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
3175ee26a228SAndrew Lunn 
3176c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3177ee26a228SAndrew Lunn 	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
3178c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3179e57e5e77SVivien Didelot 
3180da9f3301SAndrew Lunn 	if (reg == MII_PHYSID2) {
3181ddc49acbSAndrew Lunn 		/* Some internal PHYs don't have a model number. */
3182ddc49acbSAndrew Lunn 		if (chip->info->family != MV88E6XXX_FAMILY_6165)
3183ddc49acbSAndrew Lunn 			/* Then there is the 6165 family. It gets is
3184ddc49acbSAndrew Lunn 			 * PHYs correct. But it can also have two
3185ddc49acbSAndrew Lunn 			 * SERDES interfaces in the PHY address
3186ddc49acbSAndrew Lunn 			 * space. And these don't have a model
3187ddc49acbSAndrew Lunn 			 * number. But they are not PHYs, so we don't
3188ddc49acbSAndrew Lunn 			 * want to give them something a PHY driver
3189ddc49acbSAndrew Lunn 			 * will recognise.
3190ddc49acbSAndrew Lunn 			 *
3191ddc49acbSAndrew Lunn 			 * Use the mv88e6390 family model number
3192ddc49acbSAndrew Lunn 			 * instead, for anything which really could be
3193ddc49acbSAndrew Lunn 			 * a PHY,
3194da9f3301SAndrew Lunn 			 */
3195da9f3301SAndrew Lunn 			if (!(val & 0x3f0))
3196107fcc10SVivien Didelot 				val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4;
3197da9f3301SAndrew Lunn 	}
3198da9f3301SAndrew Lunn 
3199e57e5e77SVivien Didelot 	return err ? err : val;
3200fad09c73SVivien Didelot }
3201fad09c73SVivien Didelot 
3202e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
3203fad09c73SVivien Didelot {
32040dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
32050dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
3206e57e5e77SVivien Didelot 	int err;
3207fad09c73SVivien Didelot 
3208ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_write)
3209ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
3210ee26a228SAndrew Lunn 
3211c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3212ee26a228SAndrew Lunn 	err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
3213c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3214e57e5e77SVivien Didelot 
3215e57e5e77SVivien Didelot 	return err;
3216fad09c73SVivien Didelot }
3217fad09c73SVivien Didelot 
3218fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
3219a3c53be5SAndrew Lunn 				   struct device_node *np,
3220a3c53be5SAndrew Lunn 				   bool external)
3221fad09c73SVivien Didelot {
3222fad09c73SVivien Didelot 	static int index;
32230dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
3224fad09c73SVivien Didelot 	struct mii_bus *bus;
3225fad09c73SVivien Didelot 	int err;
3226fad09c73SVivien Didelot 
32272510babcSAndrew Lunn 	if (external) {
3228c9acece0SRasmus Villemoes 		mv88e6xxx_reg_lock(chip);
32292510babcSAndrew Lunn 		err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
3230c9acece0SRasmus Villemoes 		mv88e6xxx_reg_unlock(chip);
32312510babcSAndrew Lunn 
32322510babcSAndrew Lunn 		if (err)
32332510babcSAndrew Lunn 			return err;
32342510babcSAndrew Lunn 	}
32352510babcSAndrew Lunn 
32360dd12d54SAndrew Lunn 	bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
3237fad09c73SVivien Didelot 	if (!bus)
3238fad09c73SVivien Didelot 		return -ENOMEM;
3239fad09c73SVivien Didelot 
32400dd12d54SAndrew Lunn 	mdio_bus = bus->priv;
3241a3c53be5SAndrew Lunn 	mdio_bus->bus = bus;
32420dd12d54SAndrew Lunn 	mdio_bus->chip = chip;
3243a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&mdio_bus->list);
3244a3c53be5SAndrew Lunn 	mdio_bus->external = external;
32450dd12d54SAndrew Lunn 
3246fad09c73SVivien Didelot 	if (np) {
3247fad09c73SVivien Didelot 		bus->name = np->full_name;
3248f7ce9103SRob Herring 		snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np);
3249fad09c73SVivien Didelot 	} else {
3250fad09c73SVivien Didelot 		bus->name = "mv88e6xxx SMI";
3251fad09c73SVivien Didelot 		snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
3252fad09c73SVivien Didelot 	}
3253fad09c73SVivien Didelot 
3254fad09c73SVivien Didelot 	bus->read = mv88e6xxx_mdio_read;
3255fad09c73SVivien Didelot 	bus->write = mv88e6xxx_mdio_write;
3256fad09c73SVivien Didelot 	bus->parent = chip->dev;
3257fad09c73SVivien Didelot 
32586f88284fSAndrew Lunn 	if (!external) {
32596f88284fSAndrew Lunn 		err = mv88e6xxx_g2_irq_mdio_setup(chip, bus);
32606f88284fSAndrew Lunn 		if (err)
32616f88284fSAndrew Lunn 			return err;
32626f88284fSAndrew Lunn 	}
32636f88284fSAndrew Lunn 
3264a3c53be5SAndrew Lunn 	err = of_mdiobus_register(bus, np);
3265fad09c73SVivien Didelot 	if (err) {
3266fad09c73SVivien Didelot 		dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
32676f88284fSAndrew Lunn 		mv88e6xxx_g2_irq_mdio_free(chip, bus);
3268fad09c73SVivien Didelot 		return err;
3269fad09c73SVivien Didelot 	}
3270fad09c73SVivien Didelot 
3271a3c53be5SAndrew Lunn 	if (external)
3272a3c53be5SAndrew Lunn 		list_add_tail(&mdio_bus->list, &chip->mdios);
3273a3c53be5SAndrew Lunn 	else
3274a3c53be5SAndrew Lunn 		list_add(&mdio_bus->list, &chip->mdios);
3275a3c53be5SAndrew Lunn 
3276a3c53be5SAndrew Lunn 	return 0;
3277a3c53be5SAndrew Lunn }
3278a3c53be5SAndrew Lunn 
3279a3c53be5SAndrew Lunn static const struct of_device_id mv88e6xxx_mdio_external_match[] = {
3280a3c53be5SAndrew Lunn 	{ .compatible = "marvell,mv88e6xxx-mdio-external",
3281a3c53be5SAndrew Lunn 	  .data = (void *)true },
3282a3c53be5SAndrew Lunn 	{ },
3283a3c53be5SAndrew Lunn };
3284a3c53be5SAndrew Lunn 
32853126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
32863126aeecSAndrew Lunn 
32873126aeecSAndrew Lunn {
32883126aeecSAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
32893126aeecSAndrew Lunn 	struct mii_bus *bus;
32903126aeecSAndrew Lunn 
32913126aeecSAndrew Lunn 	list_for_each_entry(mdio_bus, &chip->mdios, list) {
32923126aeecSAndrew Lunn 		bus = mdio_bus->bus;
32933126aeecSAndrew Lunn 
32946f88284fSAndrew Lunn 		if (!mdio_bus->external)
32956f88284fSAndrew Lunn 			mv88e6xxx_g2_irq_mdio_free(chip, bus);
32966f88284fSAndrew Lunn 
32973126aeecSAndrew Lunn 		mdiobus_unregister(bus);
32983126aeecSAndrew Lunn 	}
32993126aeecSAndrew Lunn }
33003126aeecSAndrew Lunn 
3301a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
3302a3c53be5SAndrew Lunn 				    struct device_node *np)
3303a3c53be5SAndrew Lunn {
3304a3c53be5SAndrew Lunn 	const struct of_device_id *match;
3305a3c53be5SAndrew Lunn 	struct device_node *child;
3306a3c53be5SAndrew Lunn 	int err;
3307a3c53be5SAndrew Lunn 
3308a3c53be5SAndrew Lunn 	/* Always register one mdio bus for the internal/default mdio
3309a3c53be5SAndrew Lunn 	 * bus. This maybe represented in the device tree, but is
3310a3c53be5SAndrew Lunn 	 * optional.
3311a3c53be5SAndrew Lunn 	 */
3312a3c53be5SAndrew Lunn 	child = of_get_child_by_name(np, "mdio");
3313a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdio_register(chip, child, false);
3314a3c53be5SAndrew Lunn 	if (err)
3315a3c53be5SAndrew Lunn 		return err;
3316a3c53be5SAndrew Lunn 
3317a3c53be5SAndrew Lunn 	/* Walk the device tree, and see if there are any other nodes
3318a3c53be5SAndrew Lunn 	 * which say they are compatible with the external mdio
3319a3c53be5SAndrew Lunn 	 * bus.
3320a3c53be5SAndrew Lunn 	 */
3321a3c53be5SAndrew Lunn 	for_each_available_child_of_node(np, child) {
3322a3c53be5SAndrew Lunn 		match = of_match_node(mv88e6xxx_mdio_external_match, child);
3323a3c53be5SAndrew Lunn 		if (match) {
3324a3c53be5SAndrew Lunn 			err = mv88e6xxx_mdio_register(chip, child, true);
33253126aeecSAndrew Lunn 			if (err) {
33263126aeecSAndrew Lunn 				mv88e6xxx_mdios_unregister(chip);
332778e42040SNishka Dasgupta 				of_node_put(child);
3328a3c53be5SAndrew Lunn 				return err;
3329a3c53be5SAndrew Lunn 			}
3330a3c53be5SAndrew Lunn 		}
33313126aeecSAndrew Lunn 	}
3332a3c53be5SAndrew Lunn 
3333a3c53be5SAndrew Lunn 	return 0;
3334a3c53be5SAndrew Lunn }
3335a3c53be5SAndrew Lunn 
3336855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
3337855b1932SVivien Didelot {
333804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3339855b1932SVivien Didelot 
3340855b1932SVivien Didelot 	return chip->eeprom_len;
3341855b1932SVivien Didelot }
3342855b1932SVivien Didelot 
3343855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
3344855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
3345855b1932SVivien Didelot {
334604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3347855b1932SVivien Didelot 	int err;
3348855b1932SVivien Didelot 
3349ee4dc2e7SVivien Didelot 	if (!chip->info->ops->get_eeprom)
3350ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
3351ee4dc2e7SVivien Didelot 
3352c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3353ee4dc2e7SVivien Didelot 	err = chip->info->ops->get_eeprom(chip, eeprom, data);
3354c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3355855b1932SVivien Didelot 
3356855b1932SVivien Didelot 	if (err)
3357855b1932SVivien Didelot 		return err;
3358855b1932SVivien Didelot 
3359855b1932SVivien Didelot 	eeprom->magic = 0xc3ec4951;
3360855b1932SVivien Didelot 
3361855b1932SVivien Didelot 	return 0;
3362855b1932SVivien Didelot }
3363855b1932SVivien Didelot 
3364855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
3365855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
3366855b1932SVivien Didelot {
336704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3368855b1932SVivien Didelot 	int err;
3369855b1932SVivien Didelot 
3370ee4dc2e7SVivien Didelot 	if (!chip->info->ops->set_eeprom)
3371ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
3372ee4dc2e7SVivien Didelot 
3373855b1932SVivien Didelot 	if (eeprom->magic != 0xc3ec4951)
3374855b1932SVivien Didelot 		return -EINVAL;
3375855b1932SVivien Didelot 
3376c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3377ee4dc2e7SVivien Didelot 	err = chip->info->ops->set_eeprom(chip, eeprom, data);
3378c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3379855b1932SVivien Didelot 
3380855b1932SVivien Didelot 	return err;
3381855b1932SVivien Didelot }
3382855b1932SVivien Didelot 
3383b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = {
33844b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6097 */
338593e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
338693e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3387cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3388b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
33897e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
33907e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
339108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3392f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3393ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
339456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3395601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
339656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3397ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
33980898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3399c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
34009dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34012d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3402121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3403a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
340440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3405dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3406dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3407052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3408fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3409fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3410fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
341151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
34129e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
3413a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3414a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
341517e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
34169e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
3417f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
34180ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
34196c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3420b3469dd8SVivien Didelot };
3421b3469dd8SVivien Didelot 
3422b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = {
34234b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6095 */
342493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
342593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3426b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
34277e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
34287e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
342908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3430f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
343156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3432601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
3433a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
34342d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3435121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3436a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
343740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3438dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3439dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3440052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
344151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3442a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3443a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
344417e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3445f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
34460ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
34476c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3448b3469dd8SVivien Didelot };
3449b3469dd8SVivien Didelot 
34507d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = {
345115da3cc8SStefan Eichenberger 	/* MV88E6XXX_FAMILY_6097 */
345293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
345393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3454cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
34557d381a02SStefan Eichenberger 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
34567d381a02SStefan Eichenberger 	.phy_read = mv88e6xxx_g2_smi_phy_read,
34577d381a02SStefan Eichenberger 	.phy_write = mv88e6xxx_g2_smi_phy_write,
34587d381a02SStefan Eichenberger 	.port_set_link = mv88e6xxx_port_set_link,
3459f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3460ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
346156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3462601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
346356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3464cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3465ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
34660898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3467c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
34689dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34692d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3470121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
34717d381a02SStefan Eichenberger 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
347240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
34737d381a02SStefan Eichenberger 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
34747d381a02SStefan Eichenberger 	.stats_get_strings = mv88e6095_stats_get_strings,
34757d381a02SStefan Eichenberger 	.stats_get_stats = mv88e6095_stats_get_stats,
3476fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3477fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
347891eaa475SVolodymyr Bendiuga 	.watchdog_ops = &mv88e6097_watchdog_ops,
347951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
34809e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
348117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
34829e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
3483f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
34840ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
34856c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
34867d381a02SStefan Eichenberger };
34877d381a02SStefan Eichenberger 
3488b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = {
34894b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
349093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
349193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3492cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3493b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3494ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3495ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
349608ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3497f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
349856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3499601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3500c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
35019dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35022d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3503121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
35040ac64c39SAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
350540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3506dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3507dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3508052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3509fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3510fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3511fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
351251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
35139e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
351417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
351523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
351623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3517f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
35180ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
35196c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3520b3469dd8SVivien Didelot };
3521b3469dd8SVivien Didelot 
3522b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = {
35234b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
352493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
352593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3526b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
35277e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
35287e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
352908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3530f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3531ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
353256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3533601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
353456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3535a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
3536cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3537ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
35380898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
353954186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
35402d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3541121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3542a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
354340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3544dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3545dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3546052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3547fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3548fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3549fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
355051c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3551a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
355202317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3553a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
355417e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3555f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
35560ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
35576c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3558b3469dd8SVivien Didelot };
3559b3469dd8SVivien Didelot 
3560990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = {
3561990e27b0SVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
356293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
356393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3564cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3565990e27b0SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
3566990e27b0SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3567990e27b0SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3568990e27b0SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3569990e27b0SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
3570990e27b0SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3571990e27b0SVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3572f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
35737cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
3574990e27b0SVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
3575990e27b0SVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3576990e27b0SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3577990e27b0SVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3578cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3579990e27b0SVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
35800898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3581990e27b0SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3582990e27b0SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35832d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
35847a3007d2SMarek Behún 	.port_set_cmode = mv88e6341_port_set_cmode,
3585121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3586990e27b0SVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
358740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3588990e27b0SVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3589990e27b0SVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
3590990e27b0SVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
3591fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3592fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
3593990e27b0SVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
3594990e27b0SVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
35959e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
3596990e27b0SVivien Didelot 	.reset = mv88e6352_g1_reset,
3597f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
35980ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3599d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
3600d3cf7d8fSMarek Behún 	.serdes_get_lane = mv88e6341_serdes_get_lane,
3601a5a6858bSRussell King 	/* Check status register pause & lpa register */
3602a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
3603a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
3604a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
3605a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
36064241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
360761a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3608907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
3609a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
3610e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
3611990e27b0SVivien Didelot };
3612990e27b0SVivien Didelot 
3613b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = {
36144b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
361593e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
361693e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3617cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3618b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3619ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3620ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
362108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3622f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3623ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
362456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3625601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
362656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3627cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3628ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36290898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3630c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36319dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36322d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3633121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3634a6da21bbSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
363540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3636dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3637dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3638052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3639fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3640fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3641fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
364251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
36439e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
364417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
364523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
364623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3647f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
36480ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3649a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3650dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
36516c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3652b3469dd8SVivien Didelot };
3653b3469dd8SVivien Didelot 
3654b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = {
36554b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
365693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
365793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3658cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3659b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3660efb3e74dSAndrew Lunn 	.phy_read = mv88e6165_phy_read,
3661efb3e74dSAndrew Lunn 	.phy_write = mv88e6165_phy_write,
366208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3663f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3664c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36659dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36662d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3667121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3668a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
366940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3670dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3671dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3672052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3673fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3674fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3675fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
367651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
36779e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
367817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
367923e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
368023e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3681f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
36820ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3683a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3684dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
36856c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3686b3469dd8SVivien Didelot };
3687b3469dd8SVivien Didelot 
3688b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = {
36894b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
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,
3693b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3694b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3695b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
369608ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
369794d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3698f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3699ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
370056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3701601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
370256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3703cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3704ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37050898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3706c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
37079dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37082d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3709121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3710a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
371140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3712dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3713dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3714052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3715fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3716fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3717fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
371851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
37199e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
372017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
372123e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
372223e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3723f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37240ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37256c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3726b3469dd8SVivien Didelot };
3727b3469dd8SVivien Didelot 
3728b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = {
37294b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
373093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
373193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3732cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3733ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3734ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3735b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3736b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3737b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
373808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3739a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3740f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
3741ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
3742f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
374356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3744601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
374556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3746cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3747ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37480898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3749c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
37509dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37512d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3752121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3753a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
375440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3755dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3756dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3757052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3758fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3759fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3760fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
376151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
37629e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
376317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
37649e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
376523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
376623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3767f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37680ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37699db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
3770a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
3771a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
3772a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
3773a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
37746d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
3775d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
3776d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
3777a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
37786c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3779b3469dd8SVivien Didelot };
3780b3469dd8SVivien Didelot 
3781b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = {
37824b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
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,
3786b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3787b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3788b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
378908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
379094d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3791f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3792ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
379356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3794601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
379556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3796cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3797ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37980898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3799c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38009dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38012d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3802121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3803a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
380440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3805dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3806dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3807052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3808fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3809fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3810fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
381151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
38129e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
381317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
381423e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
381523e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3816f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
38170ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
38186c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3819b3469dd8SVivien Didelot };
3820b3469dd8SVivien Didelot 
3821b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = {
38224b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
382393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
382493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3825cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3826ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3827ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3828b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3829b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3830b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
383108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3832a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3833f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
3834ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
3835f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
383656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3837601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
383856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3839cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3840ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
38410898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3842c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38439dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38442d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3845121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3846a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
384740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3848dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3849dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3850052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3851fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3852fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3853fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
385451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
38559e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
385617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
38579e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
385823e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
385923e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3860f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
38610ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
38629db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
3863a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
3864a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
3865a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
3866a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
38676d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
38684241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
386961a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
3870907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
3871d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
3872d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
3873a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
38746c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3875b3469dd8SVivien Didelot };
3876b3469dd8SVivien Didelot 
3877b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = {
38784b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
387993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
388093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3881b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
38827e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
38837e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
388408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3885f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
388656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3887601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
3888ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
3889a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
389054186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
38912d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3892121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3893a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
389440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3895dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3896dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3897052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3898fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3899fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3900fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
390151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
390202317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3903a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3904a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
390517e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3906f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
39070ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
39086c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3909b3469dd8SVivien Didelot };
3910b3469dd8SVivien Didelot 
39111a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = {
39124b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3913ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3914cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
391598fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
391698fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
39171a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
39181a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
39191a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
39201a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
39211a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3922f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
39237cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
3924ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
3925f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
392656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3927601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
392856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
39290898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3930c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
39319dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
39322d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3933fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
3934121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
393579523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3936de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3937dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3938dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3939e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3940fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3941fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
394261303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
39436e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
39449e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
394517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
39469e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
394723e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
394823e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3949931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3950931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
39516335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
395217deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
3953a5a6858bSRussell King 	/* Check status register pause & lpa register */
3954a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
3955a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
3956a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
3957a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
39584241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
395961a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3960907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
39614262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
39624262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
3963bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
3964bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
39654262c38dSAndrew Lunn 	.phylink_validate = mv88e6390_phylink_validate,
3966a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
39676c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
39681a3b39ecSAndrew Lunn };
39691a3b39ecSAndrew Lunn 
39701a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = {
39714b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3972ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3973cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
397498fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
397598fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
39761a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
39771a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
39781a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
39791a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
39801a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3981f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
39827cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
3983ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
3984f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
398556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3986601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
398756995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
39880898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3989c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
39909dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
39912d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3992fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
3993121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
399479523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3995de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3996dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3997dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3998e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3999fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4000fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
400161303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
40026e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
40039e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
400417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
40059e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
400623e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
400723e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4008931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4009931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4010d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
401117deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390x_serdes_get_lane,
4012a5a6858bSRussell King 	/* Check status register pause & lpa register */
4013a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4014a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4015a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4016a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
40174241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
401861a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4019907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
40204262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
40214262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4022bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4023bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
40244262c38dSAndrew Lunn 	.phylink_validate = mv88e6390_phylink_validate,
4025a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
40266c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
40271a3b39ecSAndrew Lunn };
40281a3b39ecSAndrew Lunn 
40291a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = {
40304b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4031ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4032cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
403398fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
403498fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
40351a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
40361a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
40371a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
40381a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
40391a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4040f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
40417cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4042ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
404356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4044601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
404556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
40460898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4047c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
40489dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
40492d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4050fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4051121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
405279523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4053de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4054dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4055dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4056e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4057fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4058fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
405961303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
40606e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
40619e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
406217e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
40639e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
406423e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
406523e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4066931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4067931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
40686335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
406917deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
4070a5a6858bSRussell King 	/* Check status register pause & lpa register */
4071a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4072a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4073a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4074a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
40754241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
407661a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4077907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
40784262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
40794262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4080bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4081bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
40824262c38dSAndrew Lunn 	.phylink_validate = mv88e6390_phylink_validate,
40836d2ac8eeSAndrew Lunn 	.avb_ops = &mv88e6390_avb_ops,
40846d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
40856c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
40861a3b39ecSAndrew Lunn };
40871a3b39ecSAndrew Lunn 
4088b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = {
40894b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
409093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
409193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4092cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4093ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4094ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4095b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4096b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4097b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
409808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
4099a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4100f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
4101ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
4102f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
410356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4104601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
410556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4106cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4107ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
41080898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4109c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
41109dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
41112d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4112121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4113a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
411440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4115dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4116dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4117052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4118fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4119fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4120fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
412151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
41229e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
412317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
41249e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
412523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
412623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4127f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
41280ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
41299db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
4130a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
4131a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
4132a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
4133a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
41346d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
41354241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
413661a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4137907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
4138d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
4139d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
4140a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
41410d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
41426d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
41436c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
4144b3469dd8SVivien Didelot };
4145b3469dd8SVivien Didelot 
41461f71836fSRasmus Villemoes static const struct mv88e6xxx_ops mv88e6250_ops = {
41471f71836fSRasmus Villemoes 	/* MV88E6XXX_FAMILY_6250 */
41481f71836fSRasmus Villemoes 	.ieee_pri_map = mv88e6250_g1_ieee_pri_map,
41491f71836fSRasmus Villemoes 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
41501f71836fSRasmus Villemoes 	.irl_init_all = mv88e6352_g2_irl_init_all,
41511f71836fSRasmus Villemoes 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
41521f71836fSRasmus Villemoes 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
41531f71836fSRasmus Villemoes 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
41541f71836fSRasmus Villemoes 	.phy_read = mv88e6xxx_g2_smi_phy_read,
41551f71836fSRasmus Villemoes 	.phy_write = mv88e6xxx_g2_smi_phy_write,
41561f71836fSRasmus Villemoes 	.port_set_link = mv88e6xxx_port_set_link,
41571f71836fSRasmus Villemoes 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4158f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6250_port_set_speed_duplex,
41591f71836fSRasmus Villemoes 	.port_tag_remap = mv88e6095_port_tag_remap,
41601f71836fSRasmus Villemoes 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
41611f71836fSRasmus Villemoes 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
41621f71836fSRasmus Villemoes 	.port_set_ether_type = mv88e6351_port_set_ether_type,
41631f71836fSRasmus Villemoes 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
41641f71836fSRasmus Villemoes 	.port_pause_limit = mv88e6097_port_pause_limit,
41651f71836fSRasmus Villemoes 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
41661f71836fSRasmus Villemoes 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
41671f71836fSRasmus Villemoes 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
41681f71836fSRasmus Villemoes 	.stats_get_sset_count = mv88e6250_stats_get_sset_count,
41691f71836fSRasmus Villemoes 	.stats_get_strings = mv88e6250_stats_get_strings,
41701f71836fSRasmus Villemoes 	.stats_get_stats = mv88e6250_stats_get_stats,
41711f71836fSRasmus Villemoes 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
41721f71836fSRasmus Villemoes 	.set_egress_port = mv88e6095_g1_set_egress_port,
41731f71836fSRasmus Villemoes 	.watchdog_ops = &mv88e6250_watchdog_ops,
41741f71836fSRasmus Villemoes 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
41751f71836fSRasmus Villemoes 	.pot_clear = mv88e6xxx_g2_pot_clear,
41761f71836fSRasmus Villemoes 	.reset = mv88e6250_g1_reset,
41771f71836fSRasmus Villemoes 	.vtu_getnext = mv88e6250_g1_vtu_getnext,
41781f71836fSRasmus Villemoes 	.vtu_loadpurge = mv88e6250_g1_vtu_loadpurge,
417971509614SHubert Feurstein 	.avb_ops = &mv88e6352_avb_ops,
418071509614SHubert Feurstein 	.ptp_ops = &mv88e6250_ptp_ops,
41811f71836fSRasmus Villemoes 	.phylink_validate = mv88e6065_phylink_validate,
41821f71836fSRasmus Villemoes };
41831f71836fSRasmus Villemoes 
41841a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = {
41854b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4186ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4187cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
418898fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
418998fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
41901a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
41911a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
41921a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
41931a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
41941a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4195f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
41967cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4197ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4198f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
419956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4200601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
420156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
42020898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4203c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
42049dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
42052d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4206fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4207121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
420879523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4209de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4210dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4211dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4212e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4213fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4214fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
421561303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
42166e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
42179e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
421817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
42199e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
422023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
422123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4222931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4223931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
42246335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
422517deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
4226a5a6858bSRussell King 	/* Check status register pause & lpa register */
4227a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4228a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4229a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4230a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
42314241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
423261a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4233907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
42344262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
42354262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4236bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4237bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
42384262c38dSAndrew Lunn 	.phylink_validate = mv88e6390_phylink_validate,
4239a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
42400d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
42416d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
42426c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
42431a3b39ecSAndrew Lunn };
42441a3b39ecSAndrew Lunn 
4245b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = {
42464b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6320 */
424793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
424893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4249cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4250ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4251ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4252b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4253b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4254b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
425508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
4256f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4257ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
425856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4259601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
426056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4261cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4262ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
42630898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4264c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
42659dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
42662d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4267121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4268a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
426940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4270dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4271dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4272052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
4273fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4274fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
42759c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
427651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
42779e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
427817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
4279f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
42800ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4281a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
42820d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
42836d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
42846c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4285b3469dd8SVivien Didelot };
4286b3469dd8SVivien Didelot 
4287b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = {
4288bd807204SVivien Didelot 	/* MV88E6XXX_FAMILY_6320 */
428993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
429093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4291cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4292ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4293ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4294b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4295b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4296b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
429708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
4298f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4299ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
430056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4301601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
430256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4303cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4304ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
43050898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4306c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
43079dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
43082d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4309121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4310a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
431140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4312dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4313dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4314052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
4315fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4316fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
43179c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
431817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
4319f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
43200ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4321a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
43220d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
43236d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
43246c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4325b3469dd8SVivien Didelot };
4326b3469dd8SVivien Didelot 
432716e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = {
432816e329aeSVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
432993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
433093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4331cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
433216e329aeSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
433316e329aeSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
433416e329aeSVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
433516e329aeSVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
433616e329aeSVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
433716e329aeSVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
433816e329aeSVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4339f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
43407cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
434116e329aeSVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
434216e329aeSVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
434316e329aeSVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
434416e329aeSVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4345cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
434616e329aeSVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
43470898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
434816e329aeSVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
434916e329aeSVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
43502d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
43517a3007d2SMarek Behún 	.port_set_cmode = mv88e6341_port_set_cmode,
4352121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
435316e329aeSVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
435440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
435516e329aeSVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
435616e329aeSVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
435716e329aeSVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
4358fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4359fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
436016e329aeSVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
436116e329aeSVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
43629e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
436316e329aeSVivien Didelot 	.reset = mv88e6352_g1_reset,
4364f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
43650ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4366d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
4367d3cf7d8fSMarek Behún 	.serdes_get_lane = mv88e6341_serdes_get_lane,
4368a5a6858bSRussell King 	/* Check status register pause & lpa register */
4369a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4370a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4371a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4372a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
43734241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
437461a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4375907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
4376a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
43770d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
43786d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
4379e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
438016e329aeSVivien Didelot };
438116e329aeSVivien Didelot 
4382b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = {
43834b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
438493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
438593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4386cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4387b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4388b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4389b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
439008ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
439194d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4392f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4393ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
439456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4395601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
439656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4397cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4398ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
43990898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4400c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
44019dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
44022d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4403121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4404a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
440540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4406dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4407dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4408052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4409fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4410fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4411fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
441251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
44139e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
441417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
441523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
441623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4417f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
44180ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
44196c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4420b3469dd8SVivien Didelot };
4421b3469dd8SVivien Didelot 
4422b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = {
44234b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
442493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
442593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4426cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4427b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4428b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4429b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
443008ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
443194d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4432f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4433ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
443456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4435601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
443656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4437cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4438ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
44390898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4440c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
44419dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
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,
445523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
445623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4457f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
44580ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
44590d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
44606d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
44616c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4462b3469dd8SVivien Didelot };
4463b3469dd8SVivien Didelot 
4464b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = {
44654b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
446693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
446793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4468cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4469ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4470ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4471b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4472b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4473b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
447408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
4475a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4476f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
4477ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
4478f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
447956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4480601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
448156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4482cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4483ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
44840898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4485c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
44869dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
44872d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4488121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4489a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
449040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4491dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4492dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4493052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4494fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4495fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4496fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
449751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
44989e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
449917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
45009e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
450123e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
450223e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4503f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
45040ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
45059db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
4506a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
4507a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
4508a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
4509a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
45106d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
45114241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
451261a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4513907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
4514a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
45150d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
45166d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
4517cda9f4aaSAndrew Lunn 	.serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
4518cda9f4aaSAndrew Lunn 	.serdes_get_strings = mv88e6352_serdes_get_strings,
4519cda9f4aaSAndrew Lunn 	.serdes_get_stats = mv88e6352_serdes_get_stats,
4520d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
4521d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
45226c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
4523b3469dd8SVivien Didelot };
4524b3469dd8SVivien Didelot 
45251a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = {
45264b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4527ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4528cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
452998fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
453098fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
45311a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
45321a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
45331a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
45341a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
45351a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4536f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
45377cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4538ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4539f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
454056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4541601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
454256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4543cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4544ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
45450898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4546c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
45479dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
45482d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4549fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4550121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
455179523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4552de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4553dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4554dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4555e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4556fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4557fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
455861303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
45596e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
45609e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
456117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
45629e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
456323e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
456423e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4565931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4566931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
45676335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
456817deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
4569a5a6858bSRussell King 	/* Check status register pause & lpa register */
4570a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4571a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4572a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4573a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
45744241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
457561a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4576907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
4577a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
45780d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
45796d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
45800df95287SNikita Yushchenko 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
45810df95287SNikita Yushchenko 	.serdes_get_strings = mv88e6390_serdes_get_strings,
45820df95287SNikita Yushchenko 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4583bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4584bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
45856c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
45861a3b39ecSAndrew Lunn };
45871a3b39ecSAndrew Lunn 
45881a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = {
45894b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4590ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4591cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
459298fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
459398fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
45941a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
45951a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
45961a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
45971a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
45981a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4599f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
46007cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
4601ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4602f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
460356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4604601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
460556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4606cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4607ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
46080898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4609c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
46109dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
46112d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4612b3dce4daSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
4613121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
461479523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4615de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4616dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4617dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4618e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4619fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4620fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
462161303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
46226e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
46239e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
462417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
46259e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
462623e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
462723e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4628931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4629931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4630d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
463117deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390x_serdes_get_lane,
4632a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4633a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4634a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4635a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
46364241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
463761a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4638907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
46394262c38dSAndrew Lunn 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
46404262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
46414262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4642bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4643bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
4644a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
46450d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
46466d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
46476c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
46481a3b39ecSAndrew Lunn };
46491a3b39ecSAndrew Lunn 
4650fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = {
4651fad09c73SVivien Didelot 	[MV88E6085] = {
4652107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
4653fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6097,
4654fad09c73SVivien Didelot 		.name = "Marvell 88E6085",
4655fad09c73SVivien Didelot 		.num_databases = 4096,
4656d9ea5620SAndrew Lunn 		.num_macs = 8192,
4657fad09c73SVivien Didelot 		.num_ports = 10,
4658bc393155SAndrew Lunn 		.num_internal_phys = 5,
46593cf3c846SVivien Didelot 		.max_vid = 4095,
4660fad09c73SVivien Didelot 		.port_base_addr = 0x10,
46619255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4662a935c052SVivien Didelot 		.global1_addr = 0x1b,
46639069c13aSVivien Didelot 		.global2_addr = 0x1c,
4664acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4665dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4666d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4667e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4668f3645652SVivien Didelot 		.pvt = true,
4669b3e05aa1SVivien Didelot 		.multi_chip = true,
4670443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4671b3469dd8SVivien Didelot 		.ops = &mv88e6085_ops,
4672fad09c73SVivien Didelot 	},
4673fad09c73SVivien Didelot 
4674fad09c73SVivien Didelot 	[MV88E6095] = {
4675107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095,
4676fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6095,
4677fad09c73SVivien Didelot 		.name = "Marvell 88E6095/88E6095F",
4678fad09c73SVivien Didelot 		.num_databases = 256,
4679d9ea5620SAndrew Lunn 		.num_macs = 8192,
4680fad09c73SVivien Didelot 		.num_ports = 11,
4681bc393155SAndrew Lunn 		.num_internal_phys = 0,
46823cf3c846SVivien Didelot 		.max_vid = 4095,
4683fad09c73SVivien Didelot 		.port_base_addr = 0x10,
46849255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4685a935c052SVivien Didelot 		.global1_addr = 0x1b,
46869069c13aSVivien Didelot 		.global2_addr = 0x1c,
4687acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4688dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4689e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4690b3e05aa1SVivien Didelot 		.multi_chip = true,
4691443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4692b3469dd8SVivien Didelot 		.ops = &mv88e6095_ops,
4693fad09c73SVivien Didelot 	},
4694fad09c73SVivien Didelot 
46957d381a02SStefan Eichenberger 	[MV88E6097] = {
4696107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097,
46977d381a02SStefan Eichenberger 		.family = MV88E6XXX_FAMILY_6097,
46987d381a02SStefan Eichenberger 		.name = "Marvell 88E6097/88E6097F",
46997d381a02SStefan Eichenberger 		.num_databases = 4096,
4700d9ea5620SAndrew Lunn 		.num_macs = 8192,
47017d381a02SStefan Eichenberger 		.num_ports = 11,
4702bc393155SAndrew Lunn 		.num_internal_phys = 8,
47033cf3c846SVivien Didelot 		.max_vid = 4095,
47047d381a02SStefan Eichenberger 		.port_base_addr = 0x10,
47059255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
47067d381a02SStefan Eichenberger 		.global1_addr = 0x1b,
47079069c13aSVivien Didelot 		.global2_addr = 0x1c,
47087d381a02SStefan Eichenberger 		.age_time_coeff = 15000,
4709c534178bSStefan Eichenberger 		.g1_irqs = 8,
4710d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4711e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4712f3645652SVivien Didelot 		.pvt = true,
4713b3e05aa1SVivien Didelot 		.multi_chip = true,
47142bfcfcd3SStefan Eichenberger 		.tag_protocol = DSA_TAG_PROTO_EDSA,
47157d381a02SStefan Eichenberger 		.ops = &mv88e6097_ops,
47167d381a02SStefan Eichenberger 	},
47177d381a02SStefan Eichenberger 
4718fad09c73SVivien Didelot 	[MV88E6123] = {
4719107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123,
4720fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4721fad09c73SVivien Didelot 		.name = "Marvell 88E6123",
4722fad09c73SVivien Didelot 		.num_databases = 4096,
4723d9ea5620SAndrew Lunn 		.num_macs = 1024,
4724fad09c73SVivien Didelot 		.num_ports = 3,
4725bc393155SAndrew Lunn 		.num_internal_phys = 5,
47263cf3c846SVivien Didelot 		.max_vid = 4095,
4727fad09c73SVivien Didelot 		.port_base_addr = 0x10,
47289255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4729a935c052SVivien Didelot 		.global1_addr = 0x1b,
47309069c13aSVivien Didelot 		.global2_addr = 0x1c,
4731acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4732dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4733d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4734e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4735f3645652SVivien Didelot 		.pvt = true,
4736b3e05aa1SVivien Didelot 		.multi_chip = true,
47375ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4738b3469dd8SVivien Didelot 		.ops = &mv88e6123_ops,
4739fad09c73SVivien Didelot 	},
4740fad09c73SVivien Didelot 
4741fad09c73SVivien Didelot 	[MV88E6131] = {
4742107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131,
4743fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
4744fad09c73SVivien Didelot 		.name = "Marvell 88E6131",
4745fad09c73SVivien Didelot 		.num_databases = 256,
4746d9ea5620SAndrew Lunn 		.num_macs = 8192,
4747fad09c73SVivien Didelot 		.num_ports = 8,
4748bc393155SAndrew Lunn 		.num_internal_phys = 0,
47493cf3c846SVivien Didelot 		.max_vid = 4095,
4750fad09c73SVivien Didelot 		.port_base_addr = 0x10,
47519255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4752a935c052SVivien Didelot 		.global1_addr = 0x1b,
47539069c13aSVivien Didelot 		.global2_addr = 0x1c,
4754acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4755dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4756e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4757b3e05aa1SVivien Didelot 		.multi_chip = true,
4758443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4759b3469dd8SVivien Didelot 		.ops = &mv88e6131_ops,
4760fad09c73SVivien Didelot 	},
4761fad09c73SVivien Didelot 
4762990e27b0SVivien Didelot 	[MV88E6141] = {
4763107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141,
4764990e27b0SVivien Didelot 		.family = MV88E6XXX_FAMILY_6341,
476579a68b26SUwe Kleine-König 		.name = "Marvell 88E6141",
4766990e27b0SVivien Didelot 		.num_databases = 4096,
4767d9ea5620SAndrew Lunn 		.num_macs = 2048,
4768990e27b0SVivien Didelot 		.num_ports = 6,
4769bc393155SAndrew Lunn 		.num_internal_phys = 5,
4770a73ccd61SBrandon Streiff 		.num_gpio = 11,
47713cf3c846SVivien Didelot 		.max_vid = 4095,
4772990e27b0SVivien Didelot 		.port_base_addr = 0x10,
47739255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
4774990e27b0SVivien Didelot 		.global1_addr = 0x1b,
47759069c13aSVivien Didelot 		.global2_addr = 0x1c,
4776990e27b0SVivien Didelot 		.age_time_coeff = 3750,
4777990e27b0SVivien Didelot 		.atu_move_port_mask = 0x1f,
4778adfccf11SAndrew Lunn 		.g1_irqs = 9,
4779d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4780f3645652SVivien Didelot 		.pvt = true,
4781b3e05aa1SVivien Didelot 		.multi_chip = true,
4782990e27b0SVivien Didelot 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4783990e27b0SVivien Didelot 		.ops = &mv88e6141_ops,
4784990e27b0SVivien Didelot 	},
4785990e27b0SVivien Didelot 
4786fad09c73SVivien Didelot 	[MV88E6161] = {
4787107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161,
4788fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4789fad09c73SVivien Didelot 		.name = "Marvell 88E6161",
4790fad09c73SVivien Didelot 		.num_databases = 4096,
4791d9ea5620SAndrew Lunn 		.num_macs = 1024,
4792fad09c73SVivien Didelot 		.num_ports = 6,
4793bc393155SAndrew Lunn 		.num_internal_phys = 5,
47943cf3c846SVivien Didelot 		.max_vid = 4095,
4795fad09c73SVivien Didelot 		.port_base_addr = 0x10,
47969255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4797a935c052SVivien Didelot 		.global1_addr = 0x1b,
47989069c13aSVivien Didelot 		.global2_addr = 0x1c,
4799acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4800dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4801d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4802e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4803f3645652SVivien Didelot 		.pvt = true,
4804b3e05aa1SVivien Didelot 		.multi_chip = true,
48055ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4806dfa54348SAndrew Lunn 		.ptp_support = true,
4807b3469dd8SVivien Didelot 		.ops = &mv88e6161_ops,
4808fad09c73SVivien Didelot 	},
4809fad09c73SVivien Didelot 
4810fad09c73SVivien Didelot 	[MV88E6165] = {
4811107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165,
4812fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4813fad09c73SVivien Didelot 		.name = "Marvell 88E6165",
4814fad09c73SVivien Didelot 		.num_databases = 4096,
4815d9ea5620SAndrew Lunn 		.num_macs = 8192,
4816fad09c73SVivien Didelot 		.num_ports = 6,
4817bc393155SAndrew Lunn 		.num_internal_phys = 0,
48183cf3c846SVivien Didelot 		.max_vid = 4095,
4819fad09c73SVivien Didelot 		.port_base_addr = 0x10,
48209255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4821a935c052SVivien Didelot 		.global1_addr = 0x1b,
48229069c13aSVivien Didelot 		.global2_addr = 0x1c,
4823acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4824dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4825d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4826e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4827f3645652SVivien Didelot 		.pvt = true,
4828b3e05aa1SVivien Didelot 		.multi_chip = true,
4829443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4830dfa54348SAndrew Lunn 		.ptp_support = true,
4831b3469dd8SVivien Didelot 		.ops = &mv88e6165_ops,
4832fad09c73SVivien Didelot 	},
4833fad09c73SVivien Didelot 
4834fad09c73SVivien Didelot 	[MV88E6171] = {
4835107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171,
4836fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4837fad09c73SVivien Didelot 		.name = "Marvell 88E6171",
4838fad09c73SVivien Didelot 		.num_databases = 4096,
4839d9ea5620SAndrew Lunn 		.num_macs = 8192,
4840fad09c73SVivien Didelot 		.num_ports = 7,
4841bc393155SAndrew Lunn 		.num_internal_phys = 5,
48423cf3c846SVivien Didelot 		.max_vid = 4095,
4843fad09c73SVivien Didelot 		.port_base_addr = 0x10,
48449255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4845a935c052SVivien Didelot 		.global1_addr = 0x1b,
48469069c13aSVivien Didelot 		.global2_addr = 0x1c,
4847acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4848dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4849d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4850e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4851f3645652SVivien Didelot 		.pvt = true,
4852b3e05aa1SVivien Didelot 		.multi_chip = true,
4853443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4854b3469dd8SVivien Didelot 		.ops = &mv88e6171_ops,
4855fad09c73SVivien Didelot 	},
4856fad09c73SVivien Didelot 
4857fad09c73SVivien Didelot 	[MV88E6172] = {
4858107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172,
4859fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4860fad09c73SVivien Didelot 		.name = "Marvell 88E6172",
4861fad09c73SVivien Didelot 		.num_databases = 4096,
4862d9ea5620SAndrew Lunn 		.num_macs = 8192,
4863fad09c73SVivien Didelot 		.num_ports = 7,
4864bc393155SAndrew Lunn 		.num_internal_phys = 5,
4865a73ccd61SBrandon Streiff 		.num_gpio = 15,
48663cf3c846SVivien Didelot 		.max_vid = 4095,
4867fad09c73SVivien Didelot 		.port_base_addr = 0x10,
48689255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4869a935c052SVivien Didelot 		.global1_addr = 0x1b,
48709069c13aSVivien Didelot 		.global2_addr = 0x1c,
4871acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4872dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4873d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4874e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4875f3645652SVivien Didelot 		.pvt = true,
4876b3e05aa1SVivien Didelot 		.multi_chip = true,
4877443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4878b3469dd8SVivien Didelot 		.ops = &mv88e6172_ops,
4879fad09c73SVivien Didelot 	},
4880fad09c73SVivien Didelot 
4881fad09c73SVivien Didelot 	[MV88E6175] = {
4882107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175,
4883fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4884fad09c73SVivien Didelot 		.name = "Marvell 88E6175",
4885fad09c73SVivien Didelot 		.num_databases = 4096,
4886d9ea5620SAndrew Lunn 		.num_macs = 8192,
4887fad09c73SVivien Didelot 		.num_ports = 7,
4888bc393155SAndrew Lunn 		.num_internal_phys = 5,
48893cf3c846SVivien Didelot 		.max_vid = 4095,
4890fad09c73SVivien Didelot 		.port_base_addr = 0x10,
48919255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4892a935c052SVivien Didelot 		.global1_addr = 0x1b,
48939069c13aSVivien Didelot 		.global2_addr = 0x1c,
4894acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4895dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4896d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4897e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4898f3645652SVivien Didelot 		.pvt = true,
4899b3e05aa1SVivien Didelot 		.multi_chip = true,
4900443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4901b3469dd8SVivien Didelot 		.ops = &mv88e6175_ops,
4902fad09c73SVivien Didelot 	},
4903fad09c73SVivien Didelot 
4904fad09c73SVivien Didelot 	[MV88E6176] = {
4905107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176,
4906fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4907fad09c73SVivien Didelot 		.name = "Marvell 88E6176",
4908fad09c73SVivien Didelot 		.num_databases = 4096,
4909d9ea5620SAndrew Lunn 		.num_macs = 8192,
4910fad09c73SVivien Didelot 		.num_ports = 7,
4911bc393155SAndrew Lunn 		.num_internal_phys = 5,
4912a73ccd61SBrandon Streiff 		.num_gpio = 15,
49133cf3c846SVivien Didelot 		.max_vid = 4095,
4914fad09c73SVivien Didelot 		.port_base_addr = 0x10,
49159255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4916a935c052SVivien Didelot 		.global1_addr = 0x1b,
49179069c13aSVivien Didelot 		.global2_addr = 0x1c,
4918acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4919dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4920d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4921e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4922f3645652SVivien Didelot 		.pvt = true,
4923b3e05aa1SVivien Didelot 		.multi_chip = true,
4924443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4925b3469dd8SVivien Didelot 		.ops = &mv88e6176_ops,
4926fad09c73SVivien Didelot 	},
4927fad09c73SVivien Didelot 
4928fad09c73SVivien Didelot 	[MV88E6185] = {
4929107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185,
4930fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
4931fad09c73SVivien Didelot 		.name = "Marvell 88E6185",
4932fad09c73SVivien Didelot 		.num_databases = 256,
4933d9ea5620SAndrew Lunn 		.num_macs = 8192,
4934fad09c73SVivien Didelot 		.num_ports = 10,
4935bc393155SAndrew Lunn 		.num_internal_phys = 0,
49363cf3c846SVivien Didelot 		.max_vid = 4095,
4937fad09c73SVivien Didelot 		.port_base_addr = 0x10,
49389255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4939a935c052SVivien Didelot 		.global1_addr = 0x1b,
49409069c13aSVivien Didelot 		.global2_addr = 0x1c,
4941acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4942dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4943e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4944b3e05aa1SVivien Didelot 		.multi_chip = true,
4945443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4946b3469dd8SVivien Didelot 		.ops = &mv88e6185_ops,
4947fad09c73SVivien Didelot 	},
4948fad09c73SVivien Didelot 
49491a3b39ecSAndrew Lunn 	[MV88E6190] = {
4950107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190,
49511a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
49521a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190",
49531a3b39ecSAndrew Lunn 		.num_databases = 4096,
4954d9ea5620SAndrew Lunn 		.num_macs = 16384,
49551a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
495695150f29SHeiner Kallweit 		.num_internal_phys = 9,
4957a73ccd61SBrandon Streiff 		.num_gpio = 16,
4958931d1822SVivien Didelot 		.max_vid = 8191,
49591a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
49609255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
49611a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
49629069c13aSVivien Didelot 		.global2_addr = 0x1c,
4963443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4964b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
49651a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4966d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4967f3645652SVivien Didelot 		.pvt = true,
4968b3e05aa1SVivien Didelot 		.multi_chip = true,
4969e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
49701a3b39ecSAndrew Lunn 		.ops = &mv88e6190_ops,
49711a3b39ecSAndrew Lunn 	},
49721a3b39ecSAndrew Lunn 
49731a3b39ecSAndrew Lunn 	[MV88E6190X] = {
4974107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X,
49751a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
49761a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190X",
49771a3b39ecSAndrew Lunn 		.num_databases = 4096,
4978d9ea5620SAndrew Lunn 		.num_macs = 16384,
49791a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
498095150f29SHeiner Kallweit 		.num_internal_phys = 9,
4981a73ccd61SBrandon Streiff 		.num_gpio = 16,
4982931d1822SVivien Didelot 		.max_vid = 8191,
49831a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
49849255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
49851a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
49869069c13aSVivien Didelot 		.global2_addr = 0x1c,
4987b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
49881a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4989d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4990e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4991f3645652SVivien Didelot 		.pvt = true,
4992b3e05aa1SVivien Didelot 		.multi_chip = true,
4993443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
49941a3b39ecSAndrew Lunn 		.ops = &mv88e6190x_ops,
49951a3b39ecSAndrew Lunn 	},
49961a3b39ecSAndrew Lunn 
49971a3b39ecSAndrew Lunn 	[MV88E6191] = {
4998107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191,
49991a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
50001a3b39ecSAndrew Lunn 		.name = "Marvell 88E6191",
50011a3b39ecSAndrew Lunn 		.num_databases = 4096,
5002d9ea5620SAndrew Lunn 		.num_macs = 16384,
50031a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
500495150f29SHeiner Kallweit 		.num_internal_phys = 9,
5005931d1822SVivien Didelot 		.max_vid = 8191,
50061a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
50079255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
50081a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
50099069c13aSVivien Didelot 		.global2_addr = 0x1c,
5010b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
5011443d5a1bSAndrew Lunn 		.g1_irqs = 9,
5012d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5013e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5014f3645652SVivien Didelot 		.pvt = true,
5015b3e05aa1SVivien Didelot 		.multi_chip = true,
5016443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
50172fa8d3afSBrandon Streiff 		.ptp_support = true,
50182cf4cefbSVivien Didelot 		.ops = &mv88e6191_ops,
50191a3b39ecSAndrew Lunn 	},
50201a3b39ecSAndrew Lunn 
502149022647SHubert Feurstein 	[MV88E6220] = {
502249022647SHubert Feurstein 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
502349022647SHubert Feurstein 		.family = MV88E6XXX_FAMILY_6250,
502449022647SHubert Feurstein 		.name = "Marvell 88E6220",
502549022647SHubert Feurstein 		.num_databases = 64,
502649022647SHubert Feurstein 
502749022647SHubert Feurstein 		/* Ports 2-4 are not routed to pins
502849022647SHubert Feurstein 		 * => usable ports 0, 1, 5, 6
502949022647SHubert Feurstein 		 */
503049022647SHubert Feurstein 		.num_ports = 7,
503149022647SHubert Feurstein 		.num_internal_phys = 2,
5032c857486aSHubert Feurstein 		.invalid_port_mask = BIT(2) | BIT(3) | BIT(4),
503349022647SHubert Feurstein 		.max_vid = 4095,
503449022647SHubert Feurstein 		.port_base_addr = 0x08,
503549022647SHubert Feurstein 		.phy_base_addr = 0x00,
503649022647SHubert Feurstein 		.global1_addr = 0x0f,
503749022647SHubert Feurstein 		.global2_addr = 0x07,
503849022647SHubert Feurstein 		.age_time_coeff = 15000,
503949022647SHubert Feurstein 		.g1_irqs = 9,
504049022647SHubert Feurstein 		.g2_irqs = 10,
504149022647SHubert Feurstein 		.atu_move_port_mask = 0xf,
504249022647SHubert Feurstein 		.dual_chip = true,
504349022647SHubert Feurstein 		.tag_protocol = DSA_TAG_PROTO_DSA,
504471509614SHubert Feurstein 		.ptp_support = true,
504549022647SHubert Feurstein 		.ops = &mv88e6250_ops,
504649022647SHubert Feurstein 	},
504749022647SHubert Feurstein 
5048fad09c73SVivien Didelot 	[MV88E6240] = {
5049107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240,
5050fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
5051fad09c73SVivien Didelot 		.name = "Marvell 88E6240",
5052fad09c73SVivien Didelot 		.num_databases = 4096,
5053d9ea5620SAndrew Lunn 		.num_macs = 8192,
5054fad09c73SVivien Didelot 		.num_ports = 7,
5055bc393155SAndrew Lunn 		.num_internal_phys = 5,
5056a73ccd61SBrandon Streiff 		.num_gpio = 15,
50573cf3c846SVivien Didelot 		.max_vid = 4095,
5058fad09c73SVivien Didelot 		.port_base_addr = 0x10,
50599255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5060a935c052SVivien Didelot 		.global1_addr = 0x1b,
50619069c13aSVivien Didelot 		.global2_addr = 0x1c,
5062acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5063dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5064d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5065e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5066f3645652SVivien Didelot 		.pvt = true,
5067b3e05aa1SVivien Didelot 		.multi_chip = true,
5068443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
50692fa8d3afSBrandon Streiff 		.ptp_support = true,
5070b3469dd8SVivien Didelot 		.ops = &mv88e6240_ops,
5071fad09c73SVivien Didelot 	},
5072fad09c73SVivien Didelot 
50731f71836fSRasmus Villemoes 	[MV88E6250] = {
50741f71836fSRasmus Villemoes 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250,
50751f71836fSRasmus Villemoes 		.family = MV88E6XXX_FAMILY_6250,
50761f71836fSRasmus Villemoes 		.name = "Marvell 88E6250",
50771f71836fSRasmus Villemoes 		.num_databases = 64,
50781f71836fSRasmus Villemoes 		.num_ports = 7,
50791f71836fSRasmus Villemoes 		.num_internal_phys = 5,
50801f71836fSRasmus Villemoes 		.max_vid = 4095,
50811f71836fSRasmus Villemoes 		.port_base_addr = 0x08,
50821f71836fSRasmus Villemoes 		.phy_base_addr = 0x00,
50831f71836fSRasmus Villemoes 		.global1_addr = 0x0f,
50841f71836fSRasmus Villemoes 		.global2_addr = 0x07,
50851f71836fSRasmus Villemoes 		.age_time_coeff = 15000,
50861f71836fSRasmus Villemoes 		.g1_irqs = 9,
50871f71836fSRasmus Villemoes 		.g2_irqs = 10,
50881f71836fSRasmus Villemoes 		.atu_move_port_mask = 0xf,
50891f71836fSRasmus Villemoes 		.dual_chip = true,
50901f71836fSRasmus Villemoes 		.tag_protocol = DSA_TAG_PROTO_DSA,
509171509614SHubert Feurstein 		.ptp_support = true,
50921f71836fSRasmus Villemoes 		.ops = &mv88e6250_ops,
50931f71836fSRasmus Villemoes 	},
50941f71836fSRasmus Villemoes 
50951a3b39ecSAndrew Lunn 	[MV88E6290] = {
5096107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
50971a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
50981a3b39ecSAndrew Lunn 		.name = "Marvell 88E6290",
50991a3b39ecSAndrew Lunn 		.num_databases = 4096,
51001a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
510195150f29SHeiner Kallweit 		.num_internal_phys = 9,
5102a73ccd61SBrandon Streiff 		.num_gpio = 16,
5103931d1822SVivien Didelot 		.max_vid = 8191,
51041a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
51059255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
51061a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
51079069c13aSVivien Didelot 		.global2_addr = 0x1c,
5108b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
51091a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5110d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5111e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5112f3645652SVivien Didelot 		.pvt = true,
5113b3e05aa1SVivien Didelot 		.multi_chip = true,
5114443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
51152fa8d3afSBrandon Streiff 		.ptp_support = true,
51161a3b39ecSAndrew Lunn 		.ops = &mv88e6290_ops,
51171a3b39ecSAndrew Lunn 	},
51181a3b39ecSAndrew Lunn 
5119fad09c73SVivien Didelot 	[MV88E6320] = {
5120107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320,
5121fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
5122fad09c73SVivien Didelot 		.name = "Marvell 88E6320",
5123fad09c73SVivien Didelot 		.num_databases = 4096,
5124d9ea5620SAndrew Lunn 		.num_macs = 8192,
5125fad09c73SVivien Didelot 		.num_ports = 7,
5126bc393155SAndrew Lunn 		.num_internal_phys = 5,
5127a73ccd61SBrandon Streiff 		.num_gpio = 15,
51283cf3c846SVivien Didelot 		.max_vid = 4095,
5129fad09c73SVivien Didelot 		.port_base_addr = 0x10,
51309255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5131a935c052SVivien Didelot 		.global1_addr = 0x1b,
51329069c13aSVivien Didelot 		.global2_addr = 0x1c,
5133acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5134dc30c35bSAndrew Lunn 		.g1_irqs = 8,
5135bc393155SAndrew Lunn 		.g2_irqs = 10,
5136e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5137f3645652SVivien Didelot 		.pvt = true,
5138b3e05aa1SVivien Didelot 		.multi_chip = true,
5139443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
51402fa8d3afSBrandon Streiff 		.ptp_support = true,
5141b3469dd8SVivien Didelot 		.ops = &mv88e6320_ops,
5142fad09c73SVivien Didelot 	},
5143fad09c73SVivien Didelot 
5144fad09c73SVivien Didelot 	[MV88E6321] = {
5145107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321,
5146fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
5147fad09c73SVivien Didelot 		.name = "Marvell 88E6321",
5148fad09c73SVivien Didelot 		.num_databases = 4096,
5149d9ea5620SAndrew Lunn 		.num_macs = 8192,
5150fad09c73SVivien Didelot 		.num_ports = 7,
5151bc393155SAndrew Lunn 		.num_internal_phys = 5,
5152a73ccd61SBrandon Streiff 		.num_gpio = 15,
51533cf3c846SVivien Didelot 		.max_vid = 4095,
5154fad09c73SVivien Didelot 		.port_base_addr = 0x10,
51559255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5156a935c052SVivien Didelot 		.global1_addr = 0x1b,
51579069c13aSVivien Didelot 		.global2_addr = 0x1c,
5158acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5159dc30c35bSAndrew Lunn 		.g1_irqs = 8,
5160bc393155SAndrew Lunn 		.g2_irqs = 10,
5161e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5162b3e05aa1SVivien Didelot 		.multi_chip = true,
5163443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
51642fa8d3afSBrandon Streiff 		.ptp_support = true,
5165b3469dd8SVivien Didelot 		.ops = &mv88e6321_ops,
5166fad09c73SVivien Didelot 	},
5167fad09c73SVivien Didelot 
5168a75961d0SGregory CLEMENT 	[MV88E6341] = {
5169107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
5170a75961d0SGregory CLEMENT 		.family = MV88E6XXX_FAMILY_6341,
5171a75961d0SGregory CLEMENT 		.name = "Marvell 88E6341",
5172a75961d0SGregory CLEMENT 		.num_databases = 4096,
5173d9ea5620SAndrew Lunn 		.num_macs = 2048,
5174bc393155SAndrew Lunn 		.num_internal_phys = 5,
5175a75961d0SGregory CLEMENT 		.num_ports = 6,
5176a73ccd61SBrandon Streiff 		.num_gpio = 11,
51773cf3c846SVivien Didelot 		.max_vid = 4095,
5178a75961d0SGregory CLEMENT 		.port_base_addr = 0x10,
51799255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
5180a75961d0SGregory CLEMENT 		.global1_addr = 0x1b,
51819069c13aSVivien Didelot 		.global2_addr = 0x1c,
5182a75961d0SGregory CLEMENT 		.age_time_coeff = 3750,
5183e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5184adfccf11SAndrew Lunn 		.g1_irqs = 9,
5185d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5186f3645652SVivien Didelot 		.pvt = true,
5187b3e05aa1SVivien Didelot 		.multi_chip = true,
5188a75961d0SGregory CLEMENT 		.tag_protocol = DSA_TAG_PROTO_EDSA,
51892fa8d3afSBrandon Streiff 		.ptp_support = true,
5190a75961d0SGregory CLEMENT 		.ops = &mv88e6341_ops,
5191a75961d0SGregory CLEMENT 	},
5192a75961d0SGregory CLEMENT 
5193fad09c73SVivien Didelot 	[MV88E6350] = {
5194107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350,
5195fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5196fad09c73SVivien Didelot 		.name = "Marvell 88E6350",
5197fad09c73SVivien Didelot 		.num_databases = 4096,
5198d9ea5620SAndrew Lunn 		.num_macs = 8192,
5199fad09c73SVivien Didelot 		.num_ports = 7,
5200bc393155SAndrew Lunn 		.num_internal_phys = 5,
52013cf3c846SVivien Didelot 		.max_vid = 4095,
5202fad09c73SVivien Didelot 		.port_base_addr = 0x10,
52039255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5204a935c052SVivien Didelot 		.global1_addr = 0x1b,
52059069c13aSVivien Didelot 		.global2_addr = 0x1c,
5206acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5207dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5208d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5209e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5210f3645652SVivien Didelot 		.pvt = true,
5211b3e05aa1SVivien Didelot 		.multi_chip = true,
5212443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
5213b3469dd8SVivien Didelot 		.ops = &mv88e6350_ops,
5214fad09c73SVivien Didelot 	},
5215fad09c73SVivien Didelot 
5216fad09c73SVivien Didelot 	[MV88E6351] = {
5217107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351,
5218fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5219fad09c73SVivien Didelot 		.name = "Marvell 88E6351",
5220fad09c73SVivien Didelot 		.num_databases = 4096,
5221d9ea5620SAndrew Lunn 		.num_macs = 8192,
5222fad09c73SVivien Didelot 		.num_ports = 7,
5223bc393155SAndrew Lunn 		.num_internal_phys = 5,
52243cf3c846SVivien Didelot 		.max_vid = 4095,
5225fad09c73SVivien Didelot 		.port_base_addr = 0x10,
52269255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5227a935c052SVivien Didelot 		.global1_addr = 0x1b,
52289069c13aSVivien Didelot 		.global2_addr = 0x1c,
5229acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5230dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5231d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5232e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5233f3645652SVivien Didelot 		.pvt = true,
5234b3e05aa1SVivien Didelot 		.multi_chip = true,
5235443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
5236b3469dd8SVivien Didelot 		.ops = &mv88e6351_ops,
5237fad09c73SVivien Didelot 	},
5238fad09c73SVivien Didelot 
5239fad09c73SVivien Didelot 	[MV88E6352] = {
5240107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352,
5241fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
5242fad09c73SVivien Didelot 		.name = "Marvell 88E6352",
5243fad09c73SVivien Didelot 		.num_databases = 4096,
5244d9ea5620SAndrew Lunn 		.num_macs = 8192,
5245fad09c73SVivien Didelot 		.num_ports = 7,
5246bc393155SAndrew Lunn 		.num_internal_phys = 5,
5247a73ccd61SBrandon Streiff 		.num_gpio = 15,
52483cf3c846SVivien Didelot 		.max_vid = 4095,
5249fad09c73SVivien Didelot 		.port_base_addr = 0x10,
52509255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5251a935c052SVivien Didelot 		.global1_addr = 0x1b,
52529069c13aSVivien Didelot 		.global2_addr = 0x1c,
5253acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5254dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5255d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5256e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5257f3645652SVivien Didelot 		.pvt = true,
5258b3e05aa1SVivien Didelot 		.multi_chip = true,
5259443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
52602fa8d3afSBrandon Streiff 		.ptp_support = true,
5261b3469dd8SVivien Didelot 		.ops = &mv88e6352_ops,
5262fad09c73SVivien Didelot 	},
52631a3b39ecSAndrew Lunn 	[MV88E6390] = {
5264107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
52651a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
52661a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390",
52671a3b39ecSAndrew Lunn 		.num_databases = 4096,
5268d9ea5620SAndrew Lunn 		.num_macs = 16384,
52691a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
527095150f29SHeiner Kallweit 		.num_internal_phys = 9,
5271a73ccd61SBrandon Streiff 		.num_gpio = 16,
5272931d1822SVivien Didelot 		.max_vid = 8191,
52731a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
52749255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
52751a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
52769069c13aSVivien Didelot 		.global2_addr = 0x1c,
5277b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
52781a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5279d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5280e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5281f3645652SVivien Didelot 		.pvt = true,
5282b3e05aa1SVivien Didelot 		.multi_chip = true,
5283443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
52842fa8d3afSBrandon Streiff 		.ptp_support = true,
52851a3b39ecSAndrew Lunn 		.ops = &mv88e6390_ops,
52861a3b39ecSAndrew Lunn 	},
52871a3b39ecSAndrew Lunn 	[MV88E6390X] = {
5288107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X,
52891a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
52901a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390X",
52911a3b39ecSAndrew Lunn 		.num_databases = 4096,
5292d9ea5620SAndrew Lunn 		.num_macs = 16384,
52931a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
529495150f29SHeiner Kallweit 		.num_internal_phys = 9,
5295a73ccd61SBrandon Streiff 		.num_gpio = 16,
5296931d1822SVivien Didelot 		.max_vid = 8191,
52971a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
52989255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
52991a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
53009069c13aSVivien Didelot 		.global2_addr = 0x1c,
5301b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
53021a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5303d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5304e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5305f3645652SVivien Didelot 		.pvt = true,
5306b3e05aa1SVivien Didelot 		.multi_chip = true,
5307443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
53082fa8d3afSBrandon Streiff 		.ptp_support = true,
53091a3b39ecSAndrew Lunn 		.ops = &mv88e6390x_ops,
53101a3b39ecSAndrew Lunn 	},
5311fad09c73SVivien Didelot };
5312fad09c73SVivien Didelot 
5313fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
5314fad09c73SVivien Didelot {
5315fad09c73SVivien Didelot 	int i;
5316fad09c73SVivien Didelot 
5317fad09c73SVivien Didelot 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
5318fad09c73SVivien Didelot 		if (mv88e6xxx_table[i].prod_num == prod_num)
5319fad09c73SVivien Didelot 			return &mv88e6xxx_table[i];
5320fad09c73SVivien Didelot 
5321fad09c73SVivien Didelot 	return NULL;
5322fad09c73SVivien Didelot }
5323fad09c73SVivien Didelot 
5324fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
5325fad09c73SVivien Didelot {
5326fad09c73SVivien Didelot 	const struct mv88e6xxx_info *info;
53278f6345b2SVivien Didelot 	unsigned int prod_num, rev;
53288f6345b2SVivien Didelot 	u16 id;
53298f6345b2SVivien Didelot 	int err;
5330fad09c73SVivien Didelot 
5331c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5332107fcc10SVivien Didelot 	err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
5333c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
53348f6345b2SVivien Didelot 	if (err)
53358f6345b2SVivien Didelot 		return err;
5336fad09c73SVivien Didelot 
5337107fcc10SVivien Didelot 	prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK;
5338107fcc10SVivien Didelot 	rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK;
5339fad09c73SVivien Didelot 
5340fad09c73SVivien Didelot 	info = mv88e6xxx_lookup_info(prod_num);
5341fad09c73SVivien Didelot 	if (!info)
5342fad09c73SVivien Didelot 		return -ENODEV;
5343fad09c73SVivien Didelot 
5344fad09c73SVivien Didelot 	/* Update the compatible info with the probed one */
5345fad09c73SVivien Didelot 	chip->info = info;
5346fad09c73SVivien Didelot 
5347ca070c10SVivien Didelot 	err = mv88e6xxx_g2_require(chip);
5348ca070c10SVivien Didelot 	if (err)
5349ca070c10SVivien Didelot 		return err;
5350ca070c10SVivien Didelot 
5351fad09c73SVivien Didelot 	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
5352fad09c73SVivien Didelot 		 chip->info->prod_num, chip->info->name, rev);
5353fad09c73SVivien Didelot 
5354fad09c73SVivien Didelot 	return 0;
5355fad09c73SVivien Didelot }
5356fad09c73SVivien Didelot 
5357fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
5358fad09c73SVivien Didelot {
5359fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
5360fad09c73SVivien Didelot 
5361fad09c73SVivien Didelot 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
5362fad09c73SVivien Didelot 	if (!chip)
5363fad09c73SVivien Didelot 		return NULL;
5364fad09c73SVivien Didelot 
5365fad09c73SVivien Didelot 	chip->dev = dev;
5366fad09c73SVivien Didelot 
5367fad09c73SVivien Didelot 	mutex_init(&chip->reg_lock);
5368a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&chip->mdios);
5369da7dc875SVivien Didelot 	idr_init(&chip->policies);
5370fad09c73SVivien Didelot 
5371fad09c73SVivien Didelot 	return chip;
5372fad09c73SVivien Didelot }
5373fad09c73SVivien Didelot 
53745ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
53754d776482SFlorian Fainelli 							int port,
53764d776482SFlorian Fainelli 							enum dsa_tag_protocol m)
53777b314362SAndrew Lunn {
537804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
53792bbb33beSAndrew Lunn 
5380443d5a1bSAndrew Lunn 	return chip->info->tag_protocol;
53817b314362SAndrew Lunn }
53827b314362SAndrew Lunn 
53837df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port,
53843709aadcSVivien Didelot 				      const struct switchdev_obj_port_mdb *mdb)
53857df8fbddSVivien Didelot {
53867df8fbddSVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
53877df8fbddSVivien Didelot 	 * so skip the prepare phase.
53887df8fbddSVivien Didelot 	 */
53897df8fbddSVivien Didelot 
53907df8fbddSVivien Didelot 	return 0;
53917df8fbddSVivien Didelot }
53927df8fbddSVivien Didelot 
53937df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
53943709aadcSVivien Didelot 				   const struct switchdev_obj_port_mdb *mdb)
53957df8fbddSVivien Didelot {
539604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
53977df8fbddSVivien Didelot 
5398c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
53997df8fbddSVivien Didelot 	if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
540027c0e600SVivien Didelot 					 MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC))
5401774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to load multicast MAC address\n",
5402774439e5SVivien Didelot 			port);
5403c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
54047df8fbddSVivien Didelot }
54057df8fbddSVivien Didelot 
54067df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
54077df8fbddSVivien Didelot 				  const struct switchdev_obj_port_mdb *mdb)
54087df8fbddSVivien Didelot {
540904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
54107df8fbddSVivien Didelot 	int err;
54117df8fbddSVivien Didelot 
5412c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5413d8291a95SVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0);
5414c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
54157df8fbddSVivien Didelot 
54167df8fbddSVivien Didelot 	return err;
54177df8fbddSVivien Didelot }
54187df8fbddSVivien Didelot 
5419f0942e00SIwan R Timmer static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
5420f0942e00SIwan R Timmer 				     struct dsa_mall_mirror_tc_entry *mirror,
5421f0942e00SIwan R Timmer 				     bool ingress)
5422f0942e00SIwan R Timmer {
5423f0942e00SIwan R Timmer 	enum mv88e6xxx_egress_direction direction = ingress ?
5424f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS :
5425f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS;
5426f0942e00SIwan R Timmer 	struct mv88e6xxx_chip *chip = ds->priv;
5427f0942e00SIwan R Timmer 	bool other_mirrors = false;
5428f0942e00SIwan R Timmer 	int i;
5429f0942e00SIwan R Timmer 	int err;
5430f0942e00SIwan R Timmer 
5431f0942e00SIwan R Timmer 	if (!chip->info->ops->set_egress_port)
5432f0942e00SIwan R Timmer 		return -EOPNOTSUPP;
5433f0942e00SIwan R Timmer 
5434f0942e00SIwan R Timmer 	mutex_lock(&chip->reg_lock);
5435f0942e00SIwan R Timmer 	if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
5436f0942e00SIwan R Timmer 	    mirror->to_local_port) {
5437f0942e00SIwan R Timmer 		for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
5438f0942e00SIwan R Timmer 			other_mirrors |= ingress ?
5439f0942e00SIwan R Timmer 					 chip->ports[i].mirror_ingress :
5440f0942e00SIwan R Timmer 					 chip->ports[i].mirror_egress;
5441f0942e00SIwan R Timmer 
5442f0942e00SIwan R Timmer 		/* Can't change egress port when other mirror is active */
5443f0942e00SIwan R Timmer 		if (other_mirrors) {
5444f0942e00SIwan R Timmer 			err = -EBUSY;
5445f0942e00SIwan R Timmer 			goto out;
5446f0942e00SIwan R Timmer 		}
5447f0942e00SIwan R Timmer 
5448f0942e00SIwan R Timmer 		err = chip->info->ops->set_egress_port(chip,
5449f0942e00SIwan R Timmer 						       direction,
5450f0942e00SIwan R Timmer 						       mirror->to_local_port);
5451f0942e00SIwan R Timmer 		if (err)
5452f0942e00SIwan R Timmer 			goto out;
5453f0942e00SIwan R Timmer 	}
5454f0942e00SIwan R Timmer 
5455f0942e00SIwan R Timmer 	err = mv88e6xxx_port_set_mirror(chip, port, direction, true);
5456f0942e00SIwan R Timmer out:
5457f0942e00SIwan R Timmer 	mutex_unlock(&chip->reg_lock);
5458f0942e00SIwan R Timmer 
5459f0942e00SIwan R Timmer 	return err;
5460f0942e00SIwan R Timmer }
5461f0942e00SIwan R Timmer 
5462f0942e00SIwan R Timmer static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
5463f0942e00SIwan R Timmer 				      struct dsa_mall_mirror_tc_entry *mirror)
5464f0942e00SIwan R Timmer {
5465f0942e00SIwan R Timmer 	enum mv88e6xxx_egress_direction direction = mirror->ingress ?
5466f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS :
5467f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS;
5468f0942e00SIwan R Timmer 	struct mv88e6xxx_chip *chip = ds->priv;
5469f0942e00SIwan R Timmer 	bool other_mirrors = false;
5470f0942e00SIwan R Timmer 	int i;
5471f0942e00SIwan R Timmer 
5472f0942e00SIwan R Timmer 	mutex_lock(&chip->reg_lock);
5473f0942e00SIwan R Timmer 	if (mv88e6xxx_port_set_mirror(chip, port, direction, false))
5474f0942e00SIwan R Timmer 		dev_err(ds->dev, "p%d: failed to disable mirroring\n", port);
5475f0942e00SIwan R Timmer 
5476f0942e00SIwan R Timmer 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
5477f0942e00SIwan R Timmer 		other_mirrors |= mirror->ingress ?
5478f0942e00SIwan R Timmer 				 chip->ports[i].mirror_ingress :
5479f0942e00SIwan R Timmer 				 chip->ports[i].mirror_egress;
5480f0942e00SIwan R Timmer 
5481f0942e00SIwan R Timmer 	/* Reset egress port when no other mirror is active */
5482f0942e00SIwan R Timmer 	if (!other_mirrors) {
5483f0942e00SIwan R Timmer 		if (chip->info->ops->set_egress_port(chip,
5484f0942e00SIwan R Timmer 						     direction,
5485f0942e00SIwan R Timmer 						     dsa_upstream_port(ds,
54864e4637b1SColin Ian King 								       port)))
5487f0942e00SIwan R Timmer 			dev_err(ds->dev, "failed to set egress port\n");
5488f0942e00SIwan R Timmer 	}
5489f0942e00SIwan R Timmer 
5490f0942e00SIwan R Timmer 	mutex_unlock(&chip->reg_lock);
5491f0942e00SIwan R Timmer }
5492f0942e00SIwan R Timmer 
54934f85901fSRussell King static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
54944f85901fSRussell King 					 bool unicast, bool multicast)
54954f85901fSRussell King {
54964f85901fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
54974f85901fSRussell King 	int err = -EOPNOTSUPP;
54984f85901fSRussell King 
5499c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
55004f85901fSRussell King 	if (chip->info->ops->port_set_egress_floods)
55014f85901fSRussell King 		err = chip->info->ops->port_set_egress_floods(chip, port,
55024f85901fSRussell King 							      unicast,
55034f85901fSRussell King 							      multicast);
5504c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
55054f85901fSRussell King 
55064f85901fSRussell King 	return err;
55074f85901fSRussell King }
55084f85901fSRussell King 
5509a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
55107b314362SAndrew Lunn 	.get_tag_protocol	= mv88e6xxx_get_tag_protocol,
5511fad09c73SVivien Didelot 	.setup			= mv88e6xxx_setup,
551223e8b470SAndrew Lunn 	.teardown		= mv88e6xxx_teardown,
5513c9a2356fSRussell King 	.phylink_validate	= mv88e6xxx_validate,
5514a5a6858bSRussell King 	.phylink_mac_link_state	= mv88e6xxx_serdes_pcs_get_state,
5515c9a2356fSRussell King 	.phylink_mac_config	= mv88e6xxx_mac_config,
5516a5a6858bSRussell King 	.phylink_mac_an_restart	= mv88e6xxx_serdes_pcs_an_restart,
5517c9a2356fSRussell King 	.phylink_mac_link_down	= mv88e6xxx_mac_link_down,
5518c9a2356fSRussell King 	.phylink_mac_link_up	= mv88e6xxx_mac_link_up,
5519fad09c73SVivien Didelot 	.get_strings		= mv88e6xxx_get_strings,
5520fad09c73SVivien Didelot 	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
5521fad09c73SVivien Didelot 	.get_sset_count		= mv88e6xxx_get_sset_count,
552204aca993SAndrew Lunn 	.port_enable		= mv88e6xxx_port_enable,
552304aca993SAndrew Lunn 	.port_disable		= mv88e6xxx_port_disable,
552408f50061SVivien Didelot 	.get_mac_eee		= mv88e6xxx_get_mac_eee,
552508f50061SVivien Didelot 	.set_mac_eee		= mv88e6xxx_set_mac_eee,
5526fad09c73SVivien Didelot 	.get_eeprom_len		= mv88e6xxx_get_eeprom_len,
5527fad09c73SVivien Didelot 	.get_eeprom		= mv88e6xxx_get_eeprom,
5528fad09c73SVivien Didelot 	.set_eeprom		= mv88e6xxx_set_eeprom,
5529fad09c73SVivien Didelot 	.get_regs_len		= mv88e6xxx_get_regs_len,
5530fad09c73SVivien Didelot 	.get_regs		= mv88e6xxx_get_regs,
5531da7dc875SVivien Didelot 	.get_rxnfc		= mv88e6xxx_get_rxnfc,
5532da7dc875SVivien Didelot 	.set_rxnfc		= mv88e6xxx_set_rxnfc,
55332cfcd964SVivien Didelot 	.set_ageing_time	= mv88e6xxx_set_ageing_time,
5534fad09c73SVivien Didelot 	.port_bridge_join	= mv88e6xxx_port_bridge_join,
5535fad09c73SVivien Didelot 	.port_bridge_leave	= mv88e6xxx_port_bridge_leave,
55364f85901fSRussell King 	.port_egress_floods	= mv88e6xxx_port_egress_floods,
5537fad09c73SVivien Didelot 	.port_stp_state_set	= mv88e6xxx_port_stp_state_set,
5538749efcb8SVivien Didelot 	.port_fast_age		= mv88e6xxx_port_fast_age,
5539fad09c73SVivien Didelot 	.port_vlan_filtering	= mv88e6xxx_port_vlan_filtering,
5540fad09c73SVivien Didelot 	.port_vlan_prepare	= mv88e6xxx_port_vlan_prepare,
5541fad09c73SVivien Didelot 	.port_vlan_add		= mv88e6xxx_port_vlan_add,
5542fad09c73SVivien Didelot 	.port_vlan_del		= mv88e6xxx_port_vlan_del,
5543fad09c73SVivien Didelot 	.port_fdb_add           = mv88e6xxx_port_fdb_add,
5544fad09c73SVivien Didelot 	.port_fdb_del           = mv88e6xxx_port_fdb_del,
5545fad09c73SVivien Didelot 	.port_fdb_dump          = mv88e6xxx_port_fdb_dump,
55467df8fbddSVivien Didelot 	.port_mdb_prepare       = mv88e6xxx_port_mdb_prepare,
55477df8fbddSVivien Didelot 	.port_mdb_add           = mv88e6xxx_port_mdb_add,
55487df8fbddSVivien Didelot 	.port_mdb_del           = mv88e6xxx_port_mdb_del,
5549f0942e00SIwan R Timmer 	.port_mirror_add	= mv88e6xxx_port_mirror_add,
5550f0942e00SIwan R Timmer 	.port_mirror_del	= mv88e6xxx_port_mirror_del,
5551aec5ac88SVivien Didelot 	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
5552aec5ac88SVivien Didelot 	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
5553c6fe0ad2SBrandon Streiff 	.port_hwtstamp_set	= mv88e6xxx_port_hwtstamp_set,
5554c6fe0ad2SBrandon Streiff 	.port_hwtstamp_get	= mv88e6xxx_port_hwtstamp_get,
5555c6fe0ad2SBrandon Streiff 	.port_txtstamp		= mv88e6xxx_port_txtstamp,
5556c6fe0ad2SBrandon Streiff 	.port_rxtstamp		= mv88e6xxx_port_rxtstamp,
5557c6fe0ad2SBrandon Streiff 	.get_ts_info		= mv88e6xxx_get_ts_info,
555823e8b470SAndrew Lunn 	.devlink_param_get	= mv88e6xxx_devlink_param_get,
555923e8b470SAndrew Lunn 	.devlink_param_set	= mv88e6xxx_devlink_param_set,
5560fad09c73SVivien Didelot };
5561fad09c73SVivien Didelot 
556255ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
5563fad09c73SVivien Didelot {
5564fad09c73SVivien Didelot 	struct device *dev = chip->dev;
5565fad09c73SVivien Didelot 	struct dsa_switch *ds;
5566fad09c73SVivien Didelot 
55677e99e347SVivien Didelot 	ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
5568fad09c73SVivien Didelot 	if (!ds)
5569fad09c73SVivien Didelot 		return -ENOMEM;
5570fad09c73SVivien Didelot 
55717e99e347SVivien Didelot 	ds->dev = dev;
55727e99e347SVivien Didelot 	ds->num_ports = mv88e6xxx_num_ports(chip);
5573fad09c73SVivien Didelot 	ds->priv = chip;
5574877b7cb0SAndrew Lunn 	ds->dev = dev;
55759d490b4eSVivien Didelot 	ds->ops = &mv88e6xxx_switch_ops;
55769ff74f24SVivien Didelot 	ds->ageing_time_min = chip->info->age_time_coeff;
55779ff74f24SVivien Didelot 	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
5578fad09c73SVivien Didelot 
5579fad09c73SVivien Didelot 	dev_set_drvdata(dev, ds);
5580fad09c73SVivien Didelot 
558123c9ee49SVivien Didelot 	return dsa_register_switch(ds);
5582fad09c73SVivien Didelot }
5583fad09c73SVivien Didelot 
5584fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
5585fad09c73SVivien Didelot {
5586fad09c73SVivien Didelot 	dsa_unregister_switch(chip->ds);
5587fad09c73SVivien Didelot }
5588fad09c73SVivien Didelot 
5589877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev)
5590877b7cb0SAndrew Lunn {
5591877b7cb0SAndrew Lunn 	const struct of_device_id *matches = dev->driver->of_match_table;
5592877b7cb0SAndrew Lunn 	const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data;
5593877b7cb0SAndrew Lunn 
5594877b7cb0SAndrew Lunn 	for (; matches->name[0] || matches->type[0] || matches->compatible[0];
5595877b7cb0SAndrew Lunn 	     matches++) {
5596877b7cb0SAndrew Lunn 		if (!strcmp(pdata->compatible, matches->compatible))
5597877b7cb0SAndrew Lunn 			return matches->data;
5598877b7cb0SAndrew Lunn 	}
5599877b7cb0SAndrew Lunn 	return NULL;
5600877b7cb0SAndrew Lunn }
5601877b7cb0SAndrew Lunn 
5602bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration
5603bcd3d9d9SMiquel Raynal  * would be lost after a power cycle so prevent it to be suspended.
5604bcd3d9d9SMiquel Raynal  */
5605bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev)
5606bcd3d9d9SMiquel Raynal {
5607bcd3d9d9SMiquel Raynal 	return -EOPNOTSUPP;
5608bcd3d9d9SMiquel Raynal }
5609bcd3d9d9SMiquel Raynal 
5610bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev)
5611bcd3d9d9SMiquel Raynal {
5612bcd3d9d9SMiquel Raynal 	return 0;
5613bcd3d9d9SMiquel Raynal }
5614bcd3d9d9SMiquel Raynal 
5615bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume);
5616bcd3d9d9SMiquel Raynal 
5617fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev)
5618fad09c73SVivien Didelot {
5619877b7cb0SAndrew Lunn 	struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data;
56207ddae24fSDavid S. Miller 	const struct mv88e6xxx_info *compat_info = NULL;
5621fad09c73SVivien Didelot 	struct device *dev = &mdiodev->dev;
5622fad09c73SVivien Didelot 	struct device_node *np = dev->of_node;
5623fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
5624877b7cb0SAndrew Lunn 	int port;
5625fad09c73SVivien Didelot 	int err;
5626fad09c73SVivien Didelot 
56277bb8c996SAndrew Lunn 	if (!np && !pdata)
56287bb8c996SAndrew Lunn 		return -EINVAL;
56297bb8c996SAndrew Lunn 
5630877b7cb0SAndrew Lunn 	if (np)
5631fad09c73SVivien Didelot 		compat_info = of_device_get_match_data(dev);
5632877b7cb0SAndrew Lunn 
5633877b7cb0SAndrew Lunn 	if (pdata) {
5634877b7cb0SAndrew Lunn 		compat_info = pdata_device_get_match_data(dev);
5635877b7cb0SAndrew Lunn 
5636877b7cb0SAndrew Lunn 		if (!pdata->netdev)
5637877b7cb0SAndrew Lunn 			return -EINVAL;
5638877b7cb0SAndrew Lunn 
5639877b7cb0SAndrew Lunn 		for (port = 0; port < DSA_MAX_PORTS; port++) {
5640877b7cb0SAndrew Lunn 			if (!(pdata->enabled_ports & (1 << port)))
5641877b7cb0SAndrew Lunn 				continue;
5642877b7cb0SAndrew Lunn 			if (strcmp(pdata->cd.port_names[port], "cpu"))
5643877b7cb0SAndrew Lunn 				continue;
5644877b7cb0SAndrew Lunn 			pdata->cd.netdev[port] = &pdata->netdev->dev;
5645877b7cb0SAndrew Lunn 			break;
5646877b7cb0SAndrew Lunn 		}
5647877b7cb0SAndrew Lunn 	}
5648877b7cb0SAndrew Lunn 
5649fad09c73SVivien Didelot 	if (!compat_info)
5650fad09c73SVivien Didelot 		return -EINVAL;
5651fad09c73SVivien Didelot 
5652fad09c73SVivien Didelot 	chip = mv88e6xxx_alloc_chip(dev);
5653877b7cb0SAndrew Lunn 	if (!chip) {
5654877b7cb0SAndrew Lunn 		err = -ENOMEM;
5655877b7cb0SAndrew Lunn 		goto out;
5656877b7cb0SAndrew Lunn 	}
5657fad09c73SVivien Didelot 
5658fad09c73SVivien Didelot 	chip->info = compat_info;
5659fad09c73SVivien Didelot 
5660fad09c73SVivien Didelot 	err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
5661fad09c73SVivien Didelot 	if (err)
5662877b7cb0SAndrew Lunn 		goto out;
5663fad09c73SVivien Didelot 
5664b4308f04SAndrew Lunn 	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
5665877b7cb0SAndrew Lunn 	if (IS_ERR(chip->reset)) {
5666877b7cb0SAndrew Lunn 		err = PTR_ERR(chip->reset);
5667877b7cb0SAndrew Lunn 		goto out;
5668877b7cb0SAndrew Lunn 	}
56697b75e49dSBaruch Siach 	if (chip->reset)
56707b75e49dSBaruch Siach 		usleep_range(1000, 2000);
5671b4308f04SAndrew Lunn 
5672fad09c73SVivien Didelot 	err = mv88e6xxx_detect(chip);
5673fad09c73SVivien Didelot 	if (err)
5674877b7cb0SAndrew Lunn 		goto out;
5675fad09c73SVivien Didelot 
5676e57e5e77SVivien Didelot 	mv88e6xxx_phy_init(chip);
5677e57e5e77SVivien Didelot 
567800baabe5SAndrew Lunn 	if (chip->info->ops->get_eeprom) {
567900baabe5SAndrew Lunn 		if (np)
568000baabe5SAndrew Lunn 			of_property_read_u32(np, "eeprom-length",
568100baabe5SAndrew Lunn 					     &chip->eeprom_len);
568200baabe5SAndrew Lunn 		else
568300baabe5SAndrew Lunn 			chip->eeprom_len = pdata->eeprom_len;
568400baabe5SAndrew Lunn 	}
5685fad09c73SVivien Didelot 
5686c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5687dc30c35bSAndrew Lunn 	err = mv88e6xxx_switch_reset(chip);
5688c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
5689fad09c73SVivien Didelot 	if (err)
5690dc30c35bSAndrew Lunn 		goto out;
5691fad09c73SVivien Didelot 
5692a27415deSAndrew Lunn 	if (np) {
5693dc30c35bSAndrew Lunn 		chip->irq = of_irq_get(np, 0);
5694dc30c35bSAndrew Lunn 		if (chip->irq == -EPROBE_DEFER) {
5695dc30c35bSAndrew Lunn 			err = chip->irq;
5696dc30c35bSAndrew Lunn 			goto out;
5697fad09c73SVivien Didelot 		}
5698a27415deSAndrew Lunn 	}
5699a27415deSAndrew Lunn 
5700a27415deSAndrew Lunn 	if (pdata)
5701a27415deSAndrew Lunn 		chip->irq = pdata->irq;
5702fad09c73SVivien Didelot 
5703294d711eSAndrew Lunn 	/* Has to be performed before the MDIO bus is created, because
5704a708767eSUwe Kleine-König 	 * the PHYs will link their interrupts to these interrupt
5705294d711eSAndrew Lunn 	 * controllers
5706dc30c35bSAndrew Lunn 	 */
5707c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5708294d711eSAndrew Lunn 	if (chip->irq > 0)
5709dc30c35bSAndrew Lunn 		err = mv88e6xxx_g1_irq_setup(chip);
5710294d711eSAndrew Lunn 	else
5711294d711eSAndrew Lunn 		err = mv88e6xxx_irq_poll_setup(chip);
5712c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
5713dc30c35bSAndrew Lunn 
5714dc30c35bSAndrew Lunn 	if (err)
5715dc30c35bSAndrew Lunn 		goto out;
5716dc30c35bSAndrew Lunn 
5717d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0) {
5718dc30c35bSAndrew Lunn 		err = mv88e6xxx_g2_irq_setup(chip);
5719dc30c35bSAndrew Lunn 		if (err)
5720dc30c35bSAndrew Lunn 			goto out_g1_irq;
5721dc30c35bSAndrew Lunn 	}
57220977644cSAndrew Lunn 
57230977644cSAndrew Lunn 	err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
57240977644cSAndrew Lunn 	if (err)
57250977644cSAndrew Lunn 		goto out_g2_irq;
572662eb1162SAndrew Lunn 
572762eb1162SAndrew Lunn 	err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
572862eb1162SAndrew Lunn 	if (err)
572962eb1162SAndrew Lunn 		goto out_g1_atu_prob_irq;
5730dc30c35bSAndrew Lunn 
5731a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdios_register(chip, np);
5732dc30c35bSAndrew Lunn 	if (err)
573362eb1162SAndrew Lunn 		goto out_g1_vtu_prob_irq;
5734dc30c35bSAndrew Lunn 
573555ed0ce0SFlorian Fainelli 	err = mv88e6xxx_register_switch(chip);
5736dc30c35bSAndrew Lunn 	if (err)
5737dc30c35bSAndrew Lunn 		goto out_mdio;
5738dc30c35bSAndrew Lunn 
5739fad09c73SVivien Didelot 	return 0;
5740dc30c35bSAndrew Lunn 
5741dc30c35bSAndrew Lunn out_mdio:
5742a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
574362eb1162SAndrew Lunn out_g1_vtu_prob_irq:
574462eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
57450977644cSAndrew Lunn out_g1_atu_prob_irq:
57460977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
5747dc30c35bSAndrew Lunn out_g2_irq:
5748294d711eSAndrew Lunn 	if (chip->info->g2_irqs > 0)
5749dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
5750dc30c35bSAndrew Lunn out_g1_irq:
5751294d711eSAndrew Lunn 	if (chip->irq > 0)
5752dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
5753294d711eSAndrew Lunn 	else
5754294d711eSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
5755dc30c35bSAndrew Lunn out:
5756877b7cb0SAndrew Lunn 	if (pdata)
5757877b7cb0SAndrew Lunn 		dev_put(pdata->netdev);
5758877b7cb0SAndrew Lunn 
5759dc30c35bSAndrew Lunn 	return err;
5760fad09c73SVivien Didelot }
5761fad09c73SVivien Didelot 
5762fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev)
5763fad09c73SVivien Didelot {
5764fad09c73SVivien Didelot 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
576504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
5766fad09c73SVivien Didelot 
5767c6fe0ad2SBrandon Streiff 	if (chip->info->ptp_support) {
5768c6fe0ad2SBrandon Streiff 		mv88e6xxx_hwtstamp_free(chip);
57692fa8d3afSBrandon Streiff 		mv88e6xxx_ptp_free(chip);
5770c6fe0ad2SBrandon Streiff 	}
57712fa8d3afSBrandon Streiff 
5772930188ceSAndrew Lunn 	mv88e6xxx_phy_destroy(chip);
5773fad09c73SVivien Didelot 	mv88e6xxx_unregister_switch(chip);
5774a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
5775dc30c35bSAndrew Lunn 
577662eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
57770977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
577876f38f1fSAndrew Lunn 
5779d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0)
5780dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
578176f38f1fSAndrew Lunn 
578276f38f1fSAndrew Lunn 	if (chip->irq > 0)
5783dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
578476f38f1fSAndrew Lunn 	else
578576f38f1fSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
5786fad09c73SVivien Didelot }
5787fad09c73SVivien Didelot 
5788fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = {
5789fad09c73SVivien Didelot 	{
5790fad09c73SVivien Didelot 		.compatible = "marvell,mv88e6085",
5791fad09c73SVivien Didelot 		.data = &mv88e6xxx_table[MV88E6085],
5792fad09c73SVivien Didelot 	},
57931a3b39ecSAndrew Lunn 	{
57941a3b39ecSAndrew Lunn 		.compatible = "marvell,mv88e6190",
57951a3b39ecSAndrew Lunn 		.data = &mv88e6xxx_table[MV88E6190],
57961a3b39ecSAndrew Lunn 	},
57971f71836fSRasmus Villemoes 	{
57981f71836fSRasmus Villemoes 		.compatible = "marvell,mv88e6250",
57991f71836fSRasmus Villemoes 		.data = &mv88e6xxx_table[MV88E6250],
58001f71836fSRasmus Villemoes 	},
5801fad09c73SVivien Didelot 	{ /* sentinel */ },
5802fad09c73SVivien Didelot };
5803fad09c73SVivien Didelot 
5804fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);
5805fad09c73SVivien Didelot 
5806fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = {
5807fad09c73SVivien Didelot 	.probe	= mv88e6xxx_probe,
5808fad09c73SVivien Didelot 	.remove = mv88e6xxx_remove,
5809fad09c73SVivien Didelot 	.mdiodrv.driver = {
5810fad09c73SVivien Didelot 		.name = "mv88e6085",
5811fad09c73SVivien Didelot 		.of_match_table = mv88e6xxx_of_match,
5812bcd3d9d9SMiquel Raynal 		.pm = &mv88e6xxx_pm_ops,
5813fad09c73SVivien Didelot 	},
5814fad09c73SVivien Didelot };
5815fad09c73SVivien Didelot 
58167324d50eSAndrew Lunn mdio_module_driver(mv88e6xxx_driver);
5817fad09c73SVivien Didelot 
5818fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
5819fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
5820fad09c73SVivien Didelot MODULE_LICENSE("GPL");
5821