xref: /openbmc/linux/drivers/net/dsa/mv88e6xxx/chip.c (revision e6f2f6b8)
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 
40072d8b4fdSHeiner Kallweit int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
40172d8b4fdSHeiner Kallweit 			     int speed, int duplex, int pause,
402d78343d2SVivien Didelot 			     phy_interface_t mode)
403d78343d2SVivien Didelot {
404a26deec6SAndrew Lunn 	struct phylink_link_state state;
405d78343d2SVivien Didelot 	int err;
406d78343d2SVivien Didelot 
407d78343d2SVivien Didelot 	if (!chip->info->ops->port_set_link)
408d78343d2SVivien Didelot 		return 0;
409d78343d2SVivien Didelot 
410a26deec6SAndrew Lunn 	if (!chip->info->ops->port_link_state)
411a26deec6SAndrew Lunn 		return 0;
412a26deec6SAndrew Lunn 
413a26deec6SAndrew Lunn 	err = chip->info->ops->port_link_state(chip, port, &state);
414a26deec6SAndrew Lunn 	if (err)
415a26deec6SAndrew Lunn 		return err;
416a26deec6SAndrew Lunn 
417a26deec6SAndrew Lunn 	/* Has anything actually changed? We don't expect the
418a26deec6SAndrew Lunn 	 * interface mode to change without one of the other
419a26deec6SAndrew Lunn 	 * parameters also changing
420a26deec6SAndrew Lunn 	 */
421a26deec6SAndrew Lunn 	if (state.link == link &&
422a26deec6SAndrew Lunn 	    state.speed == speed &&
423927441adSMarek Behún 	    state.duplex == duplex &&
424927441adSMarek Behún 	    (state.interface == mode ||
425927441adSMarek Behún 	     state.interface == PHY_INTERFACE_MODE_NA))
426a26deec6SAndrew Lunn 		return 0;
427a26deec6SAndrew Lunn 
428d78343d2SVivien Didelot 	/* Port's MAC control must not be changed unless the link is down */
42943c8e0aeSHubert Feurstein 	err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN);
430d78343d2SVivien Didelot 	if (err)
431d78343d2SVivien Didelot 		return err;
432d78343d2SVivien Didelot 
433d78343d2SVivien Didelot 	if (chip->info->ops->port_set_speed) {
434d78343d2SVivien Didelot 		err = chip->info->ops->port_set_speed(chip, port, speed);
435d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
436d78343d2SVivien Didelot 			goto restore_link;
437d78343d2SVivien Didelot 	}
438d78343d2SVivien Didelot 
4397cbbee05SAndrew Lunn 	if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode)
4407cbbee05SAndrew Lunn 		mode = chip->info->ops->port_max_speed_mode(port);
4417cbbee05SAndrew Lunn 
44254186b91SAndrew Lunn 	if (chip->info->ops->port_set_pause) {
44354186b91SAndrew Lunn 		err = chip->info->ops->port_set_pause(chip, port, pause);
44454186b91SAndrew Lunn 		if (err)
44554186b91SAndrew Lunn 			goto restore_link;
44654186b91SAndrew Lunn 	}
44754186b91SAndrew Lunn 
448d78343d2SVivien Didelot 	if (chip->info->ops->port_set_duplex) {
449d78343d2SVivien Didelot 		err = chip->info->ops->port_set_duplex(chip, port, duplex);
450d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
451d78343d2SVivien Didelot 			goto restore_link;
452d78343d2SVivien Didelot 	}
453d78343d2SVivien Didelot 
454d78343d2SVivien Didelot 	if (chip->info->ops->port_set_rgmii_delay) {
455d78343d2SVivien Didelot 		err = chip->info->ops->port_set_rgmii_delay(chip, port, mode);
456d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
457d78343d2SVivien Didelot 			goto restore_link;
458d78343d2SVivien Didelot 	}
459d78343d2SVivien Didelot 
460f39908d3SAndrew Lunn 	if (chip->info->ops->port_set_cmode) {
461f39908d3SAndrew Lunn 		err = chip->info->ops->port_set_cmode(chip, port, mode);
462f39908d3SAndrew Lunn 		if (err && err != -EOPNOTSUPP)
463f39908d3SAndrew Lunn 			goto restore_link;
464f39908d3SAndrew Lunn 	}
465f39908d3SAndrew Lunn 
466d78343d2SVivien Didelot 	err = 0;
467d78343d2SVivien Didelot restore_link:
468d78343d2SVivien Didelot 	if (chip->info->ops->port_set_link(chip, port, link))
469774439e5SVivien Didelot 		dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
470d78343d2SVivien Didelot 
471d78343d2SVivien Didelot 	return err;
472d78343d2SVivien Didelot }
473d78343d2SVivien Didelot 
474d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
475d700ec41SMarek Vasut {
476d700ec41SMarek Vasut 	struct mv88e6xxx_chip *chip = ds->priv;
477d700ec41SMarek Vasut 
478d700ec41SMarek Vasut 	return port < chip->info->num_internal_phys;
479d700ec41SMarek Vasut }
480d700ec41SMarek Vasut 
4816c422e34SRussell King static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port,
4826c422e34SRussell King 				       unsigned long *mask,
4836c422e34SRussell King 				       struct phylink_link_state *state)
4846c422e34SRussell King {
4856c422e34SRussell King 	if (!phy_interface_mode_is_8023z(state->interface)) {
4866c422e34SRussell King 		/* 10M and 100M are only supported in non-802.3z mode */
4876c422e34SRussell King 		phylink_set(mask, 10baseT_Half);
4886c422e34SRussell King 		phylink_set(mask, 10baseT_Full);
4896c422e34SRussell King 		phylink_set(mask, 100baseT_Half);
4906c422e34SRussell King 		phylink_set(mask, 100baseT_Full);
4916c422e34SRussell King 	}
4926c422e34SRussell King }
4936c422e34SRussell King 
4946c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port,
4956c422e34SRussell King 				       unsigned long *mask,
4966c422e34SRussell King 				       struct phylink_link_state *state)
4976c422e34SRussell King {
4986c422e34SRussell King 	/* FIXME: if the port is in 1000Base-X mode, then it only supports
4996c422e34SRussell King 	 * 1000M FD speeds.  In this case, CMODE will indicate 5.
5006c422e34SRussell King 	 */
5016c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
5026c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
5036c422e34SRussell King 
5046c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
5056c422e34SRussell King }
5066c422e34SRussell King 
507e3af71a3SMarek Behún static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port,
508e3af71a3SMarek Behún 				       unsigned long *mask,
509e3af71a3SMarek Behún 				       struct phylink_link_state *state)
510e3af71a3SMarek Behún {
511e3af71a3SMarek Behún 	if (port >= 5)
512e3af71a3SMarek Behún 		phylink_set(mask, 2500baseX_Full);
513e3af71a3SMarek Behún 
514e3af71a3SMarek Behún 	/* No ethtool bits for 200Mbps */
515e3af71a3SMarek Behún 	phylink_set(mask, 1000baseT_Full);
516e3af71a3SMarek Behún 	phylink_set(mask, 1000baseX_Full);
517e3af71a3SMarek Behún 
518e3af71a3SMarek Behún 	mv88e6065_phylink_validate(chip, port, mask, state);
519e3af71a3SMarek Behún }
520e3af71a3SMarek Behún 
5216c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5226c422e34SRussell King 				       unsigned long *mask,
5236c422e34SRussell King 				       struct phylink_link_state *state)
5246c422e34SRussell King {
5256c422e34SRussell King 	/* No ethtool bits for 200Mbps */
5266c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
5276c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
5286c422e34SRussell King 
5296c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
5306c422e34SRussell King }
5316c422e34SRussell King 
5326c422e34SRussell King static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5336c422e34SRussell King 				       unsigned long *mask,
5346c422e34SRussell King 				       struct phylink_link_state *state)
5356c422e34SRussell King {
536ec26016bSAndrew Lunn 	if (port >= 9) {
5376c422e34SRussell King 		phylink_set(mask, 2500baseX_Full);
538ec26016bSAndrew Lunn 		phylink_set(mask, 2500baseT_Full);
539ec26016bSAndrew Lunn 	}
5406c422e34SRussell King 
5416c422e34SRussell King 	/* No ethtool bits for 200Mbps */
5426c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
5436c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
5446c422e34SRussell King 
5456c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
5466c422e34SRussell King }
5476c422e34SRussell King 
5486c422e34SRussell King static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5496c422e34SRussell King 					unsigned long *mask,
5506c422e34SRussell King 					struct phylink_link_state *state)
5516c422e34SRussell King {
5526c422e34SRussell King 	if (port >= 9) {
5536c422e34SRussell King 		phylink_set(mask, 10000baseT_Full);
5546c422e34SRussell King 		phylink_set(mask, 10000baseKR_Full);
5556c422e34SRussell King 	}
5566c422e34SRussell King 
5576c422e34SRussell King 	mv88e6390_phylink_validate(chip, port, mask, state);
5586c422e34SRussell King }
5596c422e34SRussell King 
560c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
561c9a2356fSRussell King 			       unsigned long *supported,
562c9a2356fSRussell King 			       struct phylink_link_state *state)
563c9a2356fSRussell King {
5646c422e34SRussell King 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
5656c422e34SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
5666c422e34SRussell King 
5676c422e34SRussell King 	/* Allow all the expected bits */
5686c422e34SRussell King 	phylink_set(mask, Autoneg);
5696c422e34SRussell King 	phylink_set(mask, Pause);
5706c422e34SRussell King 	phylink_set_port_modes(mask);
5716c422e34SRussell King 
5726c422e34SRussell King 	if (chip->info->ops->phylink_validate)
5736c422e34SRussell King 		chip->info->ops->phylink_validate(chip, port, mask, state);
5746c422e34SRussell King 
5756c422e34SRussell King 	bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
5766c422e34SRussell King 	bitmap_and(state->advertising, state->advertising, mask,
5776c422e34SRussell King 		   __ETHTOOL_LINK_MODE_MASK_NBITS);
5786c422e34SRussell King 
5796c422e34SRussell King 	/* We can only operate at 2500BaseX or 1000BaseX.  If requested
5806c422e34SRussell King 	 * to advertise both, only report advertising at 2500BaseX.
5816c422e34SRussell King 	 */
5826c422e34SRussell King 	phylink_helper_basex_speed(state);
583c9a2356fSRussell King }
584c9a2356fSRussell King 
585c9a2356fSRussell King static int mv88e6xxx_link_state(struct dsa_switch *ds, int port,
586c9a2356fSRussell King 				struct phylink_link_state *state)
587c9a2356fSRussell King {
588c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
589c9a2356fSRussell King 	int err;
590c9a2356fSRussell King 
591c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5926c422e34SRussell King 	if (chip->info->ops->port_link_state)
5936c422e34SRussell King 		err = chip->info->ops->port_link_state(chip, port, state);
5946c422e34SRussell King 	else
5956c422e34SRussell King 		err = -EOPNOTSUPP;
596c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
597c9a2356fSRussell King 
598c9a2356fSRussell King 	return err;
599c9a2356fSRussell King }
600c9a2356fSRussell King 
601c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
602c9a2356fSRussell King 				 unsigned int mode,
603c9a2356fSRussell King 				 const struct phylink_link_state *state)
604c9a2356fSRussell King {
605c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
60654186b91SAndrew Lunn 	int speed, duplex, link, pause, err;
607c9a2356fSRussell King 
608d700ec41SMarek Vasut 	if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port))
609c9a2356fSRussell King 		return;
610c9a2356fSRussell King 
611c9a2356fSRussell King 	if (mode == MLO_AN_FIXED) {
612c9a2356fSRussell King 		link = LINK_FORCED_UP;
613c9a2356fSRussell King 		speed = state->speed;
614c9a2356fSRussell King 		duplex = state->duplex;
615d700ec41SMarek Vasut 	} else if (!mv88e6xxx_phy_is_internal(ds, port)) {
616d700ec41SMarek Vasut 		link = state->link;
617d700ec41SMarek Vasut 		speed = state->speed;
618d700ec41SMarek Vasut 		duplex = state->duplex;
619c9a2356fSRussell King 	} else {
620c9a2356fSRussell King 		speed = SPEED_UNFORCED;
621c9a2356fSRussell King 		duplex = DUPLEX_UNFORCED;
622c9a2356fSRussell King 		link = LINK_UNFORCED;
623c9a2356fSRussell King 	}
62454186b91SAndrew Lunn 	pause = !!phylink_test(state->advertising, Pause);
625c9a2356fSRussell King 
626c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
62754186b91SAndrew Lunn 	err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, pause,
628c9a2356fSRussell King 				       state->interface);
629c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
630c9a2356fSRussell King 
631c9a2356fSRussell King 	if (err && err != -EOPNOTSUPP)
632c9a2356fSRussell King 		dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
633c9a2356fSRussell King }
634c9a2356fSRussell King 
635c9a2356fSRussell King static void mv88e6xxx_mac_link_force(struct dsa_switch *ds, int port, int link)
636c9a2356fSRussell King {
637c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
638c9a2356fSRussell King 	int err;
639c9a2356fSRussell King 
640c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
641c9a2356fSRussell King 	err = chip->info->ops->port_set_link(chip, port, link);
642c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
643c9a2356fSRussell King 
644c9a2356fSRussell King 	if (err)
645c9a2356fSRussell King 		dev_err(chip->dev, "p%d: failed to force MAC link\n", port);
646c9a2356fSRussell King }
647c9a2356fSRussell King 
648c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
649c9a2356fSRussell King 				    unsigned int mode,
650c9a2356fSRussell King 				    phy_interface_t interface)
651c9a2356fSRussell King {
652c9a2356fSRussell King 	if (mode == MLO_AN_FIXED)
653c9a2356fSRussell King 		mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_DOWN);
654c9a2356fSRussell King }
655c9a2356fSRussell King 
656c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
657c9a2356fSRussell King 				  unsigned int mode, phy_interface_t interface,
658c9a2356fSRussell King 				  struct phy_device *phydev)
659c9a2356fSRussell King {
660c9a2356fSRussell King 	if (mode == MLO_AN_FIXED)
661c9a2356fSRussell King 		mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_UP);
662c9a2356fSRussell King }
663c9a2356fSRussell King 
664a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
665fad09c73SVivien Didelot {
666a605a0feSAndrew Lunn 	if (!chip->info->ops->stats_snapshot)
667a605a0feSAndrew Lunn 		return -EOPNOTSUPP;
668fad09c73SVivien Didelot 
669a605a0feSAndrew Lunn 	return chip->info->ops->stats_snapshot(chip, port);
670fad09c73SVivien Didelot }
671fad09c73SVivien Didelot 
672fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
673dfafe449SAndrew Lunn 	{ "in_good_octets",		8, 0x00, STATS_TYPE_BANK0, },
674dfafe449SAndrew Lunn 	{ "in_bad_octets",		4, 0x02, STATS_TYPE_BANK0, },
675dfafe449SAndrew Lunn 	{ "in_unicast",			4, 0x04, STATS_TYPE_BANK0, },
676dfafe449SAndrew Lunn 	{ "in_broadcasts",		4, 0x06, STATS_TYPE_BANK0, },
677dfafe449SAndrew Lunn 	{ "in_multicasts",		4, 0x07, STATS_TYPE_BANK0, },
678dfafe449SAndrew Lunn 	{ "in_pause",			4, 0x16, STATS_TYPE_BANK0, },
679dfafe449SAndrew Lunn 	{ "in_undersize",		4, 0x18, STATS_TYPE_BANK0, },
680dfafe449SAndrew Lunn 	{ "in_fragments",		4, 0x19, STATS_TYPE_BANK0, },
681dfafe449SAndrew Lunn 	{ "in_oversize",		4, 0x1a, STATS_TYPE_BANK0, },
682dfafe449SAndrew Lunn 	{ "in_jabber",			4, 0x1b, STATS_TYPE_BANK0, },
683dfafe449SAndrew Lunn 	{ "in_rx_error",		4, 0x1c, STATS_TYPE_BANK0, },
684dfafe449SAndrew Lunn 	{ "in_fcs_error",		4, 0x1d, STATS_TYPE_BANK0, },
685dfafe449SAndrew Lunn 	{ "out_octets",			8, 0x0e, STATS_TYPE_BANK0, },
686dfafe449SAndrew Lunn 	{ "out_unicast",		4, 0x10, STATS_TYPE_BANK0, },
687dfafe449SAndrew Lunn 	{ "out_broadcasts",		4, 0x13, STATS_TYPE_BANK0, },
688dfafe449SAndrew Lunn 	{ "out_multicasts",		4, 0x12, STATS_TYPE_BANK0, },
689dfafe449SAndrew Lunn 	{ "out_pause",			4, 0x15, STATS_TYPE_BANK0, },
690dfafe449SAndrew Lunn 	{ "excessive",			4, 0x11, STATS_TYPE_BANK0, },
691dfafe449SAndrew Lunn 	{ "collisions",			4, 0x1e, STATS_TYPE_BANK0, },
692dfafe449SAndrew Lunn 	{ "deferred",			4, 0x05, STATS_TYPE_BANK0, },
693dfafe449SAndrew Lunn 	{ "single",			4, 0x14, STATS_TYPE_BANK0, },
694dfafe449SAndrew Lunn 	{ "multiple",			4, 0x17, STATS_TYPE_BANK0, },
695dfafe449SAndrew Lunn 	{ "out_fcs_error",		4, 0x03, STATS_TYPE_BANK0, },
696dfafe449SAndrew Lunn 	{ "late",			4, 0x1f, STATS_TYPE_BANK0, },
697dfafe449SAndrew Lunn 	{ "hist_64bytes",		4, 0x08, STATS_TYPE_BANK0, },
698dfafe449SAndrew Lunn 	{ "hist_65_127bytes",		4, 0x09, STATS_TYPE_BANK0, },
699dfafe449SAndrew Lunn 	{ "hist_128_255bytes",		4, 0x0a, STATS_TYPE_BANK0, },
700dfafe449SAndrew Lunn 	{ "hist_256_511bytes",		4, 0x0b, STATS_TYPE_BANK0, },
701dfafe449SAndrew Lunn 	{ "hist_512_1023bytes",		4, 0x0c, STATS_TYPE_BANK0, },
702dfafe449SAndrew Lunn 	{ "hist_1024_max_bytes",	4, 0x0d, STATS_TYPE_BANK0, },
703dfafe449SAndrew Lunn 	{ "sw_in_discards",		4, 0x10, STATS_TYPE_PORT, },
704dfafe449SAndrew Lunn 	{ "sw_in_filtered",		2, 0x12, STATS_TYPE_PORT, },
705dfafe449SAndrew Lunn 	{ "sw_out_filtered",		2, 0x13, STATS_TYPE_PORT, },
706dfafe449SAndrew Lunn 	{ "in_discards",		4, 0x00, STATS_TYPE_BANK1, },
707dfafe449SAndrew Lunn 	{ "in_filtered",		4, 0x01, STATS_TYPE_BANK1, },
708dfafe449SAndrew Lunn 	{ "in_accepted",		4, 0x02, STATS_TYPE_BANK1, },
709dfafe449SAndrew Lunn 	{ "in_bad_accepted",		4, 0x03, STATS_TYPE_BANK1, },
710dfafe449SAndrew Lunn 	{ "in_good_avb_class_a",	4, 0x04, STATS_TYPE_BANK1, },
711dfafe449SAndrew Lunn 	{ "in_good_avb_class_b",	4, 0x05, STATS_TYPE_BANK1, },
712dfafe449SAndrew Lunn 	{ "in_bad_avb_class_a",		4, 0x06, STATS_TYPE_BANK1, },
713dfafe449SAndrew Lunn 	{ "in_bad_avb_class_b",		4, 0x07, STATS_TYPE_BANK1, },
714dfafe449SAndrew Lunn 	{ "tcam_counter_0",		4, 0x08, STATS_TYPE_BANK1, },
715dfafe449SAndrew Lunn 	{ "tcam_counter_1",		4, 0x09, STATS_TYPE_BANK1, },
716dfafe449SAndrew Lunn 	{ "tcam_counter_2",		4, 0x0a, STATS_TYPE_BANK1, },
717dfafe449SAndrew Lunn 	{ "tcam_counter_3",		4, 0x0b, STATS_TYPE_BANK1, },
718dfafe449SAndrew Lunn 	{ "in_da_unknown",		4, 0x0e, STATS_TYPE_BANK1, },
719dfafe449SAndrew Lunn 	{ "in_management",		4, 0x0f, STATS_TYPE_BANK1, },
720dfafe449SAndrew Lunn 	{ "out_queue_0",		4, 0x10, STATS_TYPE_BANK1, },
721dfafe449SAndrew Lunn 	{ "out_queue_1",		4, 0x11, STATS_TYPE_BANK1, },
722dfafe449SAndrew Lunn 	{ "out_queue_2",		4, 0x12, STATS_TYPE_BANK1, },
723dfafe449SAndrew Lunn 	{ "out_queue_3",		4, 0x13, STATS_TYPE_BANK1, },
724dfafe449SAndrew Lunn 	{ "out_queue_4",		4, 0x14, STATS_TYPE_BANK1, },
725dfafe449SAndrew Lunn 	{ "out_queue_5",		4, 0x15, STATS_TYPE_BANK1, },
726dfafe449SAndrew Lunn 	{ "out_queue_6",		4, 0x16, STATS_TYPE_BANK1, },
727dfafe449SAndrew Lunn 	{ "out_queue_7",		4, 0x17, STATS_TYPE_BANK1, },
728dfafe449SAndrew Lunn 	{ "out_cut_through",		4, 0x18, STATS_TYPE_BANK1, },
729dfafe449SAndrew Lunn 	{ "out_octets_a",		4, 0x1a, STATS_TYPE_BANK1, },
730dfafe449SAndrew Lunn 	{ "out_octets_b",		4, 0x1b, STATS_TYPE_BANK1, },
731dfafe449SAndrew Lunn 	{ "out_management",		4, 0x1f, STATS_TYPE_BANK1, },
732fad09c73SVivien Didelot };
733fad09c73SVivien Didelot 
734fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
735fad09c73SVivien Didelot 					    struct mv88e6xxx_hw_stat *s,
736e0d8b615SAndrew Lunn 					    int port, u16 bank1_select,
737e0d8b615SAndrew Lunn 					    u16 histogram)
738fad09c73SVivien Didelot {
739fad09c73SVivien Didelot 	u32 low;
740fad09c73SVivien Didelot 	u32 high = 0;
741dfafe449SAndrew Lunn 	u16 reg = 0;
7420e7b9925SAndrew Lunn 	int err;
743fad09c73SVivien Didelot 	u64 value;
744fad09c73SVivien Didelot 
745fad09c73SVivien Didelot 	switch (s->type) {
746dfafe449SAndrew Lunn 	case STATS_TYPE_PORT:
7470e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
7480e7b9925SAndrew Lunn 		if (err)
7496c3442f5SJisheng Zhang 			return U64_MAX;
750fad09c73SVivien Didelot 
7510e7b9925SAndrew Lunn 		low = reg;
752cda9f4aaSAndrew Lunn 		if (s->size == 4) {
7530e7b9925SAndrew Lunn 			err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
7540e7b9925SAndrew Lunn 			if (err)
7556c3442f5SJisheng Zhang 				return U64_MAX;
75684b3fd1fSRasmus Villemoes 			low |= ((u32)reg) << 16;
757fad09c73SVivien Didelot 		}
758fad09c73SVivien Didelot 		break;
759dfafe449SAndrew Lunn 	case STATS_TYPE_BANK1:
760e0d8b615SAndrew Lunn 		reg = bank1_select;
761dfafe449SAndrew Lunn 		/* fall through */
762dfafe449SAndrew Lunn 	case STATS_TYPE_BANK0:
763e0d8b615SAndrew Lunn 		reg |= s->reg | histogram;
7647f9ef3afSAndrew Lunn 		mv88e6xxx_g1_stats_read(chip, reg, &low);
765cda9f4aaSAndrew Lunn 		if (s->size == 8)
7667f9ef3afSAndrew Lunn 			mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
7679fc3e4dcSGustavo A. R. Silva 		break;
7689fc3e4dcSGustavo A. R. Silva 	default:
7696c3442f5SJisheng Zhang 		return U64_MAX;
770fad09c73SVivien Didelot 	}
7716e46e2d8SAndrew Lunn 	value = (((u64)high) << 32) | low;
772fad09c73SVivien Didelot 	return value;
773fad09c73SVivien Didelot }
774fad09c73SVivien Didelot 
775436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
776dfafe449SAndrew Lunn 				       uint8_t *data, int types)
777fad09c73SVivien Didelot {
778fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
779fad09c73SVivien Didelot 	int i, j;
780fad09c73SVivien Didelot 
781fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
782fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
783dfafe449SAndrew Lunn 		if (stat->type & types) {
784fad09c73SVivien Didelot 			memcpy(data + j * ETH_GSTRING_LEN, stat->string,
785fad09c73SVivien Didelot 			       ETH_GSTRING_LEN);
786fad09c73SVivien Didelot 			j++;
787fad09c73SVivien Didelot 		}
788fad09c73SVivien Didelot 	}
789436fe17dSAndrew Lunn 
790436fe17dSAndrew Lunn 	return j;
791fad09c73SVivien Didelot }
792fad09c73SVivien Didelot 
793436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
794dfafe449SAndrew Lunn 				       uint8_t *data)
795dfafe449SAndrew Lunn {
796436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
797dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_PORT);
798dfafe449SAndrew Lunn }
799dfafe449SAndrew Lunn 
8001f71836fSRasmus Villemoes static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip,
8011f71836fSRasmus Villemoes 				       uint8_t *data)
8021f71836fSRasmus Villemoes {
8031f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0);
8041f71836fSRasmus Villemoes }
8051f71836fSRasmus Villemoes 
806436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
807dfafe449SAndrew Lunn 				       uint8_t *data)
808dfafe449SAndrew Lunn {
809436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
810dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
811dfafe449SAndrew Lunn }
812dfafe449SAndrew Lunn 
81365f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = {
81465f60e45SAndrew Lunn 	"atu_member_violation",
81565f60e45SAndrew Lunn 	"atu_miss_violation",
81665f60e45SAndrew Lunn 	"atu_full_violation",
81765f60e45SAndrew Lunn 	"vtu_member_violation",
81865f60e45SAndrew Lunn 	"vtu_miss_violation",
81965f60e45SAndrew Lunn };
82065f60e45SAndrew Lunn 
82165f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data)
82265f60e45SAndrew Lunn {
82365f60e45SAndrew Lunn 	unsigned int i;
82465f60e45SAndrew Lunn 
82565f60e45SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++)
82665f60e45SAndrew Lunn 		strlcpy(data + i * ETH_GSTRING_LEN,
82765f60e45SAndrew Lunn 			mv88e6xxx_atu_vtu_stats_strings[i],
82865f60e45SAndrew Lunn 			ETH_GSTRING_LEN);
82965f60e45SAndrew Lunn }
83065f60e45SAndrew Lunn 
831dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
83289f09048SFlorian Fainelli 				  u32 stringset, uint8_t *data)
833fad09c73SVivien Didelot {
83404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
835436fe17dSAndrew Lunn 	int count = 0;
836dfafe449SAndrew Lunn 
83789f09048SFlorian Fainelli 	if (stringset != ETH_SS_STATS)
83889f09048SFlorian Fainelli 		return;
83989f09048SFlorian Fainelli 
840c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
841c6c8cd5eSAndrew Lunn 
842dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_strings)
843436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_strings(chip, data);
844436fe17dSAndrew Lunn 
845436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_strings) {
846436fe17dSAndrew Lunn 		data += count * ETH_GSTRING_LEN;
84765f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_strings(chip, port, data);
848436fe17dSAndrew Lunn 	}
849c6c8cd5eSAndrew Lunn 
85065f60e45SAndrew Lunn 	data += count * ETH_GSTRING_LEN;
85165f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_strings(data);
85265f60e45SAndrew Lunn 
853c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
854dfafe449SAndrew Lunn }
855dfafe449SAndrew Lunn 
856dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
857dfafe449SAndrew Lunn 					  int types)
858dfafe449SAndrew Lunn {
859fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
860fad09c73SVivien Didelot 	int i, j;
861fad09c73SVivien Didelot 
862fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
863fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
864dfafe449SAndrew Lunn 		if (stat->type & types)
865fad09c73SVivien Didelot 			j++;
866fad09c73SVivien Didelot 	}
867fad09c73SVivien Didelot 	return j;
868fad09c73SVivien Didelot }
869fad09c73SVivien Didelot 
870dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
871dfafe449SAndrew Lunn {
872dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
873dfafe449SAndrew Lunn 					      STATS_TYPE_PORT);
874dfafe449SAndrew Lunn }
875dfafe449SAndrew Lunn 
8761f71836fSRasmus Villemoes static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip)
8771f71836fSRasmus Villemoes {
8781f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0);
8791f71836fSRasmus Villemoes }
8801f71836fSRasmus Villemoes 
881dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
882dfafe449SAndrew Lunn {
883dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
884dfafe449SAndrew Lunn 					      STATS_TYPE_BANK1);
885dfafe449SAndrew Lunn }
886dfafe449SAndrew Lunn 
88789f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
888dfafe449SAndrew Lunn {
889dfafe449SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
890436fe17dSAndrew Lunn 	int serdes_count = 0;
891436fe17dSAndrew Lunn 	int count = 0;
892dfafe449SAndrew Lunn 
89389f09048SFlorian Fainelli 	if (sset != ETH_SS_STATS)
89489f09048SFlorian Fainelli 		return 0;
89589f09048SFlorian Fainelli 
896c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
897dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_sset_count)
898436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_sset_count(chip);
899436fe17dSAndrew Lunn 	if (count < 0)
900436fe17dSAndrew Lunn 		goto out;
901436fe17dSAndrew Lunn 
902436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_sset_count)
903436fe17dSAndrew Lunn 		serdes_count = chip->info->ops->serdes_get_sset_count(chip,
904436fe17dSAndrew Lunn 								      port);
90565f60e45SAndrew Lunn 	if (serdes_count < 0) {
906436fe17dSAndrew Lunn 		count = serdes_count;
90765f60e45SAndrew Lunn 		goto out;
90865f60e45SAndrew Lunn 	}
909436fe17dSAndrew Lunn 	count += serdes_count;
91065f60e45SAndrew Lunn 	count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings);
91165f60e45SAndrew Lunn 
912436fe17dSAndrew Lunn out:
913c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
914dfafe449SAndrew Lunn 
915436fe17dSAndrew Lunn 	return count;
916dfafe449SAndrew Lunn }
917dfafe449SAndrew Lunn 
918436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
919e0d8b615SAndrew Lunn 				     uint64_t *data, int types,
920e0d8b615SAndrew Lunn 				     u16 bank1_select, u16 histogram)
921052f947fSAndrew Lunn {
922052f947fSAndrew Lunn 	struct mv88e6xxx_hw_stat *stat;
923052f947fSAndrew Lunn 	int i, j;
924052f947fSAndrew Lunn 
925052f947fSAndrew Lunn 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
926052f947fSAndrew Lunn 		stat = &mv88e6xxx_hw_stats[i];
927052f947fSAndrew Lunn 		if (stat->type & types) {
928c9acece0SRasmus Villemoes 			mv88e6xxx_reg_lock(chip);
929e0d8b615SAndrew Lunn 			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
930e0d8b615SAndrew Lunn 							      bank1_select,
931e0d8b615SAndrew Lunn 							      histogram);
932c9acece0SRasmus Villemoes 			mv88e6xxx_reg_unlock(chip);
933377cda13SAndrew Lunn 
934052f947fSAndrew Lunn 			j++;
935052f947fSAndrew Lunn 		}
936052f947fSAndrew Lunn 	}
937436fe17dSAndrew Lunn 	return j;
938052f947fSAndrew Lunn }
939052f947fSAndrew Lunn 
940436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
941052f947fSAndrew Lunn 				     uint64_t *data)
942052f947fSAndrew Lunn {
943052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
944e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
94557d1ef38SVivien Didelot 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
946052f947fSAndrew Lunn }
947052f947fSAndrew Lunn 
9481f71836fSRasmus Villemoes static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
9491f71836fSRasmus Villemoes 				     uint64_t *data)
9501f71836fSRasmus Villemoes {
9511f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0,
9521f71836fSRasmus Villemoes 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
9531f71836fSRasmus Villemoes }
9541f71836fSRasmus Villemoes 
955436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
956052f947fSAndrew Lunn 				     uint64_t *data)
957052f947fSAndrew Lunn {
958052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
959e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
96057d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
96157d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
962e0d8b615SAndrew Lunn }
963e0d8b615SAndrew Lunn 
964436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
965e0d8b615SAndrew Lunn 				     uint64_t *data)
966e0d8b615SAndrew Lunn {
967e0d8b615SAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
968e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
96957d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
97057d1ef38SVivien Didelot 					 0);
971052f947fSAndrew Lunn }
972052f947fSAndrew Lunn 
97365f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
97465f60e45SAndrew Lunn 					uint64_t *data)
97565f60e45SAndrew Lunn {
97665f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_member_violation;
97765f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_miss_violation;
97865f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_full_violation;
97965f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_member_violation;
98065f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_miss_violation;
98165f60e45SAndrew Lunn }
98265f60e45SAndrew Lunn 
983052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
984052f947fSAndrew Lunn 				uint64_t *data)
985052f947fSAndrew Lunn {
986436fe17dSAndrew Lunn 	int count = 0;
987436fe17dSAndrew Lunn 
988052f947fSAndrew Lunn 	if (chip->info->ops->stats_get_stats)
989436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_stats(chip, port, data);
990436fe17dSAndrew Lunn 
991c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
992436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_stats) {
993436fe17dSAndrew Lunn 		data += count;
99465f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_stats(chip, port, data);
995436fe17dSAndrew Lunn 	}
99665f60e45SAndrew Lunn 	data += count;
99765f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_stats(chip, port, data);
998c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
999052f947fSAndrew Lunn }
1000052f947fSAndrew Lunn 
1001fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
1002fad09c73SVivien Didelot 					uint64_t *data)
1003fad09c73SVivien Didelot {
100404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1005fad09c73SVivien Didelot 	int ret;
1006fad09c73SVivien Didelot 
1007c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1008fad09c73SVivien Didelot 
1009a605a0feSAndrew Lunn 	ret = mv88e6xxx_stats_snapshot(chip, port);
1010c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1011377cda13SAndrew Lunn 
1012377cda13SAndrew Lunn 	if (ret < 0)
1013fad09c73SVivien Didelot 		return;
1014052f947fSAndrew Lunn 
1015052f947fSAndrew Lunn 	mv88e6xxx_get_stats(chip, port, data);
1016fad09c73SVivien Didelot 
1017fad09c73SVivien Didelot }
1018fad09c73SVivien Didelot 
1019fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
1020fad09c73SVivien Didelot {
1021fad09c73SVivien Didelot 	return 32 * sizeof(u16);
1022fad09c73SVivien Didelot }
1023fad09c73SVivien Didelot 
1024fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
1025fad09c73SVivien Didelot 			       struct ethtool_regs *regs, void *_p)
1026fad09c73SVivien Didelot {
102704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
10280e7b9925SAndrew Lunn 	int err;
10290e7b9925SAndrew Lunn 	u16 reg;
1030fad09c73SVivien Didelot 	u16 *p = _p;
1031fad09c73SVivien Didelot 	int i;
1032fad09c73SVivien Didelot 
1033a5f39326SVivien Didelot 	regs->version = chip->info->prod_num;
1034fad09c73SVivien Didelot 
1035fad09c73SVivien Didelot 	memset(p, 0xff, 32 * sizeof(u16));
1036fad09c73SVivien Didelot 
1037c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1038fad09c73SVivien Didelot 
1039fad09c73SVivien Didelot 	for (i = 0; i < 32; i++) {
1040fad09c73SVivien Didelot 
10410e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, i, &reg);
10420e7b9925SAndrew Lunn 		if (!err)
10430e7b9925SAndrew Lunn 			p[i] = reg;
1044fad09c73SVivien Didelot 	}
1045fad09c73SVivien Didelot 
1046c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1047fad09c73SVivien Didelot }
1048fad09c73SVivien Didelot 
104908f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
1050fad09c73SVivien Didelot 				 struct ethtool_eee *e)
1051fad09c73SVivien Didelot {
10525480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
10535480db69SVivien Didelot 	return 0;
1054fad09c73SVivien Didelot }
1055fad09c73SVivien Didelot 
105608f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port,
105746587e4aSVivien Didelot 				 struct ethtool_eee *e)
1058fad09c73SVivien Didelot {
10595480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
10605480db69SVivien Didelot 	return 0;
1061fad09c73SVivien Didelot }
1062fad09c73SVivien Didelot 
10639dc8b13eSVivien Didelot /* Mask of the local ports allowed to receive frames from a given fabric port */
1064e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
1065fad09c73SVivien Didelot {
10669dc8b13eSVivien Didelot 	struct dsa_switch *ds = chip->ds;
10679dc8b13eSVivien Didelot 	struct dsa_switch_tree *dst = ds->dst;
1068e5887a2aSVivien Didelot 	struct net_device *br;
10699dc8b13eSVivien Didelot 	struct dsa_port *dp;
10709dc8b13eSVivien Didelot 	bool found = false;
1071e5887a2aSVivien Didelot 	u16 pvlan;
1072fad09c73SVivien Didelot 
10739dc8b13eSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list) {
10749dc8b13eSVivien Didelot 		if (dp->ds->index == dev && dp->index == port) {
10759dc8b13eSVivien Didelot 			found = true;
10769dc8b13eSVivien Didelot 			break;
10779dc8b13eSVivien Didelot 		}
10789dc8b13eSVivien Didelot 	}
1079fad09c73SVivien Didelot 
1080e5887a2aSVivien Didelot 	/* Prevent frames from unknown switch or port */
10819dc8b13eSVivien Didelot 	if (!found)
1082e5887a2aSVivien Didelot 		return 0;
1083e5887a2aSVivien Didelot 
1084e5887a2aSVivien Didelot 	/* Frames from DSA links and CPU ports can egress any local port */
10859dc8b13eSVivien Didelot 	if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA)
1086e5887a2aSVivien Didelot 		return mv88e6xxx_port_mask(chip);
1087e5887a2aSVivien Didelot 
10889dc8b13eSVivien Didelot 	br = dp->bridge_dev;
1089e5887a2aSVivien Didelot 	pvlan = 0;
1090e5887a2aSVivien Didelot 
1091e5887a2aSVivien Didelot 	/* Frames from user ports can egress any local DSA links and CPU ports,
1092e5887a2aSVivien Didelot 	 * as well as any local member of their bridge group.
1093e5887a2aSVivien Didelot 	 */
10949dc8b13eSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list)
10959dc8b13eSVivien Didelot 		if (dp->ds == ds &&
10969dc8b13eSVivien Didelot 		    (dp->type == DSA_PORT_TYPE_CPU ||
10979dc8b13eSVivien Didelot 		     dp->type == DSA_PORT_TYPE_DSA ||
10989dc8b13eSVivien Didelot 		     (br && dp->bridge_dev == br)))
10999dc8b13eSVivien Didelot 			pvlan |= BIT(dp->index);
1100e5887a2aSVivien Didelot 
1101e5887a2aSVivien Didelot 	return pvlan;
1102fad09c73SVivien Didelot }
1103e5887a2aSVivien Didelot 
1104240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port)
1105e5887a2aSVivien Didelot {
1106e5887a2aSVivien Didelot 	u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port);
1107fad09c73SVivien Didelot 
1108fad09c73SVivien Didelot 	/* prevent frames from going back out of the port they came in on */
1109fad09c73SVivien Didelot 	output_ports &= ~BIT(port);
1110fad09c73SVivien Didelot 
11115a7921f4SVivien Didelot 	return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
1112fad09c73SVivien Didelot }
1113fad09c73SVivien Didelot 
1114fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
1115fad09c73SVivien Didelot 					 u8 state)
1116fad09c73SVivien Didelot {
111704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1118fad09c73SVivien Didelot 	int err;
1119fad09c73SVivien Didelot 
1120c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1121f894c29cSVivien Didelot 	err = mv88e6xxx_port_set_state(chip, port, state);
1122c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1123fad09c73SVivien Didelot 
1124fad09c73SVivien Didelot 	if (err)
1125774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to update state\n", port);
1126fad09c73SVivien Didelot }
1127fad09c73SVivien Didelot 
112893e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip)
112993e18d61SVivien Didelot {
113093e18d61SVivien Didelot 	int err;
113193e18d61SVivien Didelot 
113293e18d61SVivien Didelot 	if (chip->info->ops->ieee_pri_map) {
113393e18d61SVivien Didelot 		err = chip->info->ops->ieee_pri_map(chip);
113493e18d61SVivien Didelot 		if (err)
113593e18d61SVivien Didelot 			return err;
113693e18d61SVivien Didelot 	}
113793e18d61SVivien Didelot 
113893e18d61SVivien Didelot 	if (chip->info->ops->ip_pri_map) {
113993e18d61SVivien Didelot 		err = chip->info->ops->ip_pri_map(chip);
114093e18d61SVivien Didelot 		if (err)
114193e18d61SVivien Didelot 			return err;
114293e18d61SVivien Didelot 	}
114393e18d61SVivien Didelot 
114493e18d61SVivien Didelot 	return 0;
114593e18d61SVivien Didelot }
114693e18d61SVivien Didelot 
1147c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
1148c7f047b6SVivien Didelot {
1149c5f51765SVivien Didelot 	struct dsa_switch *ds = chip->ds;
1150c7f047b6SVivien Didelot 	int target, port;
1151c7f047b6SVivien Didelot 	int err;
1152c7f047b6SVivien Didelot 
1153c7f047b6SVivien Didelot 	if (!chip->info->global2_addr)
1154c7f047b6SVivien Didelot 		return 0;
1155c7f047b6SVivien Didelot 
1156c7f047b6SVivien Didelot 	/* Initialize the routing port to the 32 possible target devices */
1157c7f047b6SVivien Didelot 	for (target = 0; target < 32; target++) {
1158c5f51765SVivien Didelot 		port = dsa_routing_port(ds, target);
1159c5f51765SVivien Didelot 		if (port == ds->num_ports)
1160c7f047b6SVivien Didelot 			port = 0x1f;
1161c7f047b6SVivien Didelot 
1162c7f047b6SVivien Didelot 		err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
1163c7f047b6SVivien Didelot 		if (err)
1164c7f047b6SVivien Didelot 			return err;
1165c7f047b6SVivien Didelot 	}
1166c7f047b6SVivien Didelot 
116702317e68SVivien Didelot 	if (chip->info->ops->set_cascade_port) {
116802317e68SVivien Didelot 		port = MV88E6XXX_CASCADE_PORT_MULTIPLE;
116902317e68SVivien Didelot 		err = chip->info->ops->set_cascade_port(chip, port);
117002317e68SVivien Didelot 		if (err)
117102317e68SVivien Didelot 			return err;
117202317e68SVivien Didelot 	}
117302317e68SVivien Didelot 
117423c98919SVivien Didelot 	err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index);
117523c98919SVivien Didelot 	if (err)
117623c98919SVivien Didelot 		return err;
117723c98919SVivien Didelot 
1178c7f047b6SVivien Didelot 	return 0;
1179c7f047b6SVivien Didelot }
1180c7f047b6SVivien Didelot 
1181b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip)
1182b28f872dSVivien Didelot {
1183b28f872dSVivien Didelot 	/* Clear all trunk masks and mapping */
1184b28f872dSVivien Didelot 	if (chip->info->global2_addr)
1185b28f872dSVivien Didelot 		return mv88e6xxx_g2_trunk_clear(chip);
1186b28f872dSVivien Didelot 
1187b28f872dSVivien Didelot 	return 0;
1188b28f872dSVivien Didelot }
1189b28f872dSVivien Didelot 
11909e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
11919e5baf9bSVivien Didelot {
11929e5baf9bSVivien Didelot 	if (chip->info->ops->rmu_disable)
11939e5baf9bSVivien Didelot 		return chip->info->ops->rmu_disable(chip);
11949e5baf9bSVivien Didelot 
11959e5baf9bSVivien Didelot 	return 0;
11969e5baf9bSVivien Didelot }
11979e5baf9bSVivien Didelot 
11989e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
11999e907d73SVivien Didelot {
12009e907d73SVivien Didelot 	if (chip->info->ops->pot_clear)
12019e907d73SVivien Didelot 		return chip->info->ops->pot_clear(chip);
12029e907d73SVivien Didelot 
12039e907d73SVivien Didelot 	return 0;
12049e907d73SVivien Didelot }
12059e907d73SVivien Didelot 
120651c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip)
120751c901a7SVivien Didelot {
120851c901a7SVivien Didelot 	if (chip->info->ops->mgmt_rsvd2cpu)
120951c901a7SVivien Didelot 		return chip->info->ops->mgmt_rsvd2cpu(chip);
121051c901a7SVivien Didelot 
121151c901a7SVivien Didelot 	return 0;
121251c901a7SVivien Didelot }
121351c901a7SVivien Didelot 
1214a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
1215a2ac29d2SVivien Didelot {
1216c3a7d4adSVivien Didelot 	int err;
1217c3a7d4adSVivien Didelot 
1218daefc943SVivien Didelot 	err = mv88e6xxx_g1_atu_flush(chip, 0, true);
1219daefc943SVivien Didelot 	if (err)
1220daefc943SVivien Didelot 		return err;
1221daefc943SVivien Didelot 
1222c3a7d4adSVivien Didelot 	err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
1223c3a7d4adSVivien Didelot 	if (err)
1224c3a7d4adSVivien Didelot 		return err;
1225c3a7d4adSVivien Didelot 
1226a2ac29d2SVivien Didelot 	return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
1227a2ac29d2SVivien Didelot }
1228a2ac29d2SVivien Didelot 
1229cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip)
1230cd8da8bbSVivien Didelot {
1231cd8da8bbSVivien Didelot 	int port;
1232cd8da8bbSVivien Didelot 	int err;
1233cd8da8bbSVivien Didelot 
1234cd8da8bbSVivien Didelot 	if (!chip->info->ops->irl_init_all)
1235cd8da8bbSVivien Didelot 		return 0;
1236cd8da8bbSVivien Didelot 
1237cd8da8bbSVivien Didelot 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
1238cd8da8bbSVivien Didelot 		/* Disable ingress rate limiting by resetting all per port
1239cd8da8bbSVivien Didelot 		 * ingress rate limit resources to their initial state.
1240cd8da8bbSVivien Didelot 		 */
1241cd8da8bbSVivien Didelot 		err = chip->info->ops->irl_init_all(chip, port);
1242cd8da8bbSVivien Didelot 		if (err)
1243cd8da8bbSVivien Didelot 			return err;
1244cd8da8bbSVivien Didelot 	}
1245cd8da8bbSVivien Didelot 
1246cd8da8bbSVivien Didelot 	return 0;
1247cd8da8bbSVivien Didelot }
1248cd8da8bbSVivien Didelot 
124904a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip)
125004a69a17SVivien Didelot {
125104a69a17SVivien Didelot 	if (chip->info->ops->set_switch_mac) {
125204a69a17SVivien Didelot 		u8 addr[ETH_ALEN];
125304a69a17SVivien Didelot 
125404a69a17SVivien Didelot 		eth_random_addr(addr);
125504a69a17SVivien Didelot 
125604a69a17SVivien Didelot 		return chip->info->ops->set_switch_mac(chip, addr);
125704a69a17SVivien Didelot 	}
125804a69a17SVivien Didelot 
125904a69a17SVivien Didelot 	return 0;
126004a69a17SVivien Didelot }
126104a69a17SVivien Didelot 
126217a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
126317a1594eSVivien Didelot {
126417a1594eSVivien Didelot 	u16 pvlan = 0;
126517a1594eSVivien Didelot 
126617a1594eSVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
1267d14939beSVivien Didelot 		return 0;
126817a1594eSVivien Didelot 
126917a1594eSVivien Didelot 	/* Skip the local source device, which uses in-chip port VLAN */
127017a1594eSVivien Didelot 	if (dev != chip->ds->index)
1271aec5ac88SVivien Didelot 		pvlan = mv88e6xxx_port_vlan(chip, dev, port);
127217a1594eSVivien Didelot 
127317a1594eSVivien Didelot 	return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
127417a1594eSVivien Didelot }
127517a1594eSVivien Didelot 
127681228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
127781228996SVivien Didelot {
127817a1594eSVivien Didelot 	int dev, port;
127917a1594eSVivien Didelot 	int err;
128017a1594eSVivien Didelot 
128181228996SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
128281228996SVivien Didelot 		return 0;
128381228996SVivien Didelot 
128481228996SVivien Didelot 	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
128581228996SVivien Didelot 	 * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
128681228996SVivien Didelot 	 */
128717a1594eSVivien Didelot 	err = mv88e6xxx_g2_misc_4_bit_port(chip);
128817a1594eSVivien Didelot 	if (err)
128917a1594eSVivien Didelot 		return err;
129017a1594eSVivien Didelot 
129117a1594eSVivien Didelot 	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) {
129217a1594eSVivien Didelot 		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) {
129317a1594eSVivien Didelot 			err = mv88e6xxx_pvt_map(chip, dev, port);
129417a1594eSVivien Didelot 			if (err)
129517a1594eSVivien Didelot 				return err;
129617a1594eSVivien Didelot 		}
129717a1594eSVivien Didelot 	}
129817a1594eSVivien Didelot 
129917a1594eSVivien Didelot 	return 0;
130081228996SVivien Didelot }
130181228996SVivien Didelot 
1302749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
1303749efcb8SVivien Didelot {
1304749efcb8SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1305749efcb8SVivien Didelot 	int err;
1306749efcb8SVivien Didelot 
1307c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1308e606ca36SVivien Didelot 	err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
1309c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1310749efcb8SVivien Didelot 
1311749efcb8SVivien Didelot 	if (err)
1312774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to flush ATU\n", port);
1313749efcb8SVivien Didelot }
1314749efcb8SVivien Didelot 
1315b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)
1316b486d7c9SVivien Didelot {
1317b486d7c9SVivien Didelot 	if (!chip->info->max_vid)
1318b486d7c9SVivien Didelot 		return 0;
1319b486d7c9SVivien Didelot 
1320b486d7c9SVivien Didelot 	return mv88e6xxx_g1_vtu_flush(chip);
1321b486d7c9SVivien Didelot }
1322b486d7c9SVivien Didelot 
1323f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,
1324f1394b78SVivien Didelot 				 struct mv88e6xxx_vtu_entry *entry)
1325f1394b78SVivien Didelot {
1326f1394b78SVivien Didelot 	if (!chip->info->ops->vtu_getnext)
1327f1394b78SVivien Didelot 		return -EOPNOTSUPP;
1328f1394b78SVivien Didelot 
1329f1394b78SVivien Didelot 	return chip->info->ops->vtu_getnext(chip, entry);
1330f1394b78SVivien Didelot }
1331f1394b78SVivien Didelot 
13320ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
13330ad5daf6SVivien Didelot 				   struct mv88e6xxx_vtu_entry *entry)
13340ad5daf6SVivien Didelot {
13350ad5daf6SVivien Didelot 	if (!chip->info->ops->vtu_loadpurge)
13360ad5daf6SVivien Didelot 		return -EOPNOTSUPP;
13370ad5daf6SVivien Didelot 
13380ad5daf6SVivien Didelot 	return chip->info->ops->vtu_loadpurge(chip, entry);
13390ad5daf6SVivien Didelot }
13400ad5daf6SVivien Didelot 
1341d7f435f9SVivien Didelot static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
1342fad09c73SVivien Didelot {
1343fad09c73SVivien Didelot 	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
1344425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1345fad09c73SVivien Didelot 	int i, err;
1346fad09c73SVivien Didelot 
1347fad09c73SVivien Didelot 	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
1348fad09c73SVivien Didelot 
1349fad09c73SVivien Didelot 	/* Set every FID bit used by the (un)bridged ports */
1350370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1351b4e48c50SVivien Didelot 		err = mv88e6xxx_port_get_fid(chip, i, fid);
1352fad09c73SVivien Didelot 		if (err)
1353fad09c73SVivien Didelot 			return err;
1354fad09c73SVivien Didelot 
1355fad09c73SVivien Didelot 		set_bit(*fid, fid_bitmap);
1356fad09c73SVivien Didelot 	}
1357fad09c73SVivien Didelot 
1358fad09c73SVivien Didelot 	/* Set every FID bit used by the VLAN entries */
1359425d2d37SVivien Didelot 	vlan.vid = chip->info->max_vid;
1360425d2d37SVivien Didelot 	vlan.valid = false;
1361425d2d37SVivien Didelot 
1362fad09c73SVivien Didelot 	do {
1363f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1364fad09c73SVivien Didelot 		if (err)
1365fad09c73SVivien Didelot 			return err;
1366fad09c73SVivien Didelot 
1367fad09c73SVivien Didelot 		if (!vlan.valid)
1368fad09c73SVivien Didelot 			break;
1369fad09c73SVivien Didelot 
1370fad09c73SVivien Didelot 		set_bit(vlan.fid, fid_bitmap);
13713cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
1372fad09c73SVivien Didelot 
1373fad09c73SVivien Didelot 	/* The reset value 0x000 is used to indicate that multiple address
1374fad09c73SVivien Didelot 	 * databases are not needed. Return the next positive available.
1375fad09c73SVivien Didelot 	 */
1376fad09c73SVivien Didelot 	*fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1);
1377fad09c73SVivien Didelot 	if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
1378fad09c73SVivien Didelot 		return -ENOSPC;
1379fad09c73SVivien Didelot 
1380fad09c73SVivien Didelot 	/* Clear the database */
1381daefc943SVivien Didelot 	return mv88e6xxx_g1_atu_flush(chip, *fid, true);
1382fad09c73SVivien Didelot }
1383fad09c73SVivien Didelot 
138423e8b470SAndrew Lunn static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
138523e8b470SAndrew Lunn {
138623e8b470SAndrew Lunn 	if (chip->info->ops->atu_get_hash)
138723e8b470SAndrew Lunn 		return chip->info->ops->atu_get_hash(chip, hash);
138823e8b470SAndrew Lunn 
138923e8b470SAndrew Lunn 	return -EOPNOTSUPP;
139023e8b470SAndrew Lunn }
139123e8b470SAndrew Lunn 
139223e8b470SAndrew Lunn static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash)
139323e8b470SAndrew Lunn {
139423e8b470SAndrew Lunn 	if (chip->info->ops->atu_set_hash)
139523e8b470SAndrew Lunn 		return chip->info->ops->atu_set_hash(chip, hash);
139623e8b470SAndrew Lunn 
139723e8b470SAndrew Lunn 	return -EOPNOTSUPP;
139823e8b470SAndrew Lunn }
139923e8b470SAndrew Lunn 
1400fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
1401fad09c73SVivien Didelot 					u16 vid_begin, u16 vid_end)
1402fad09c73SVivien Didelot {
140304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1404425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1405fad09c73SVivien Didelot 	int i, err;
1406fad09c73SVivien Didelot 
1407db06ae41SAndrew Lunn 	/* DSA and CPU ports have to be members of multiple vlans */
1408db06ae41SAndrew Lunn 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
1409db06ae41SAndrew Lunn 		return 0;
1410db06ae41SAndrew Lunn 
1411fad09c73SVivien Didelot 	if (!vid_begin)
1412fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1413fad09c73SVivien Didelot 
1414425d2d37SVivien Didelot 	vlan.vid = vid_begin - 1;
1415425d2d37SVivien Didelot 	vlan.valid = false;
1416425d2d37SVivien Didelot 
1417fad09c73SVivien Didelot 	do {
1418f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1419fad09c73SVivien Didelot 		if (err)
14207095a4c4SVivien Didelot 			return err;
1421fad09c73SVivien Didelot 
1422fad09c73SVivien Didelot 		if (!vlan.valid)
1423fad09c73SVivien Didelot 			break;
1424fad09c73SVivien Didelot 
1425fad09c73SVivien Didelot 		if (vlan.vid > vid_end)
1426fad09c73SVivien Didelot 			break;
1427fad09c73SVivien Didelot 
1428370b4ffbSVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1429fad09c73SVivien Didelot 			if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
1430fad09c73SVivien Didelot 				continue;
1431fad09c73SVivien Didelot 
143268bb8ea8SVivien Didelot 			if (!dsa_to_port(ds, i)->slave)
143366e2809dSAndrew Lunn 				continue;
143466e2809dSAndrew Lunn 
1435bd00e053SVivien Didelot 			if (vlan.member[i] ==
14367ec60d6eSVivien Didelot 			    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1437fad09c73SVivien Didelot 				continue;
1438fad09c73SVivien Didelot 
1439c8652c83SVivien Didelot 			if (dsa_to_port(ds, i)->bridge_dev ==
144068bb8ea8SVivien Didelot 			    dsa_to_port(ds, port)->bridge_dev)
1441fad09c73SVivien Didelot 				break; /* same bridge, check next VLAN */
1442fad09c73SVivien Didelot 
1443c8652c83SVivien Didelot 			if (!dsa_to_port(ds, i)->bridge_dev)
144466e2809dSAndrew Lunn 				continue;
144566e2809dSAndrew Lunn 
1446743fcc28SAndrew Lunn 			dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
1447743fcc28SAndrew Lunn 				port, vlan.vid, i,
1448c8652c83SVivien Didelot 				netdev_name(dsa_to_port(ds, i)->bridge_dev));
14497095a4c4SVivien Didelot 			return -EOPNOTSUPP;
1450fad09c73SVivien Didelot 		}
1451fad09c73SVivien Didelot 	} while (vlan.vid < vid_end);
1452fad09c73SVivien Didelot 
14537095a4c4SVivien Didelot 	return 0;
1454fad09c73SVivien Didelot }
1455fad09c73SVivien Didelot 
1456fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
1457fad09c73SVivien Didelot 					 bool vlan_filtering)
1458fad09c73SVivien Didelot {
145904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
146081c6edb2SVivien Didelot 	u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
146181c6edb2SVivien Didelot 		MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
14620e7b9925SAndrew Lunn 	int err;
1463fad09c73SVivien Didelot 
14643cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1465fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1466fad09c73SVivien Didelot 
1467c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1468385a0995SVivien Didelot 	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
1469c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1470fad09c73SVivien Didelot 
14710e7b9925SAndrew Lunn 	return err;
1472fad09c73SVivien Didelot }
1473fad09c73SVivien Didelot 
1474fad09c73SVivien Didelot static int
1475fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
147680e02360SVivien Didelot 			    const struct switchdev_obj_port_vlan *vlan)
1477fad09c73SVivien Didelot {
147804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1479fad09c73SVivien Didelot 	int err;
1480fad09c73SVivien Didelot 
14813cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1482fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1483fad09c73SVivien Didelot 
1484fad09c73SVivien Didelot 	/* If the requested port doesn't belong to the same bridge as the VLAN
1485fad09c73SVivien Didelot 	 * members, do not support it (yet) and fallback to software VLAN.
1486fad09c73SVivien Didelot 	 */
14877095a4c4SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1488fad09c73SVivien Didelot 	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
1489fad09c73SVivien Didelot 					   vlan->vid_end);
14907095a4c4SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1491fad09c73SVivien Didelot 
1492fad09c73SVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
1493fad09c73SVivien Didelot 	 * so skip the prepare phase.
1494fad09c73SVivien Didelot 	 */
14957095a4c4SVivien Didelot 	return err;
1496fad09c73SVivien Didelot }
1497fad09c73SVivien Didelot 
1498a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
1499a4c93ae1SAndrew Lunn 					const unsigned char *addr, u16 vid,
1500a4c93ae1SAndrew Lunn 					u8 state)
1501a4c93ae1SAndrew Lunn {
1502a4c93ae1SAndrew Lunn 	struct mv88e6xxx_atu_entry entry;
15035ef8d249SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
15045ef8d249SVivien Didelot 	u16 fid;
1505a4c93ae1SAndrew Lunn 	int err;
1506a4c93ae1SAndrew Lunn 
1507a4c93ae1SAndrew Lunn 	/* Null VLAN ID corresponds to the port private database */
15085ef8d249SVivien Didelot 	if (vid == 0) {
15095ef8d249SVivien Didelot 		err = mv88e6xxx_port_get_fid(chip, port, &fid);
1510a4c93ae1SAndrew Lunn 		if (err)
1511a4c93ae1SAndrew Lunn 			return err;
15125ef8d249SVivien Didelot 	} else {
15135ef8d249SVivien Didelot 		vlan.vid = vid - 1;
15145ef8d249SVivien Didelot 		vlan.valid = false;
15155ef8d249SVivien Didelot 
15165ef8d249SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
15175ef8d249SVivien Didelot 		if (err)
15185ef8d249SVivien Didelot 			return err;
15195ef8d249SVivien Didelot 
15205ef8d249SVivien Didelot 		/* switchdev expects -EOPNOTSUPP to honor software VLANs */
15215ef8d249SVivien Didelot 		if (vlan.vid != vid || !vlan.valid)
15225ef8d249SVivien Didelot 			return -EOPNOTSUPP;
15235ef8d249SVivien Didelot 
15245ef8d249SVivien Didelot 		fid = vlan.fid;
15255ef8d249SVivien Didelot 	}
1526a4c93ae1SAndrew Lunn 
1527d8291a95SVivien Didelot 	entry.state = 0;
1528a4c93ae1SAndrew Lunn 	ether_addr_copy(entry.mac, addr);
1529a4c93ae1SAndrew Lunn 	eth_addr_dec(entry.mac);
1530a4c93ae1SAndrew Lunn 
15315ef8d249SVivien Didelot 	err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry);
1532a4c93ae1SAndrew Lunn 	if (err)
1533a4c93ae1SAndrew Lunn 		return err;
1534a4c93ae1SAndrew Lunn 
1535a4c93ae1SAndrew Lunn 	/* Initialize a fresh ATU entry if it isn't found */
1536d8291a95SVivien Didelot 	if (!entry.state || !ether_addr_equal(entry.mac, addr)) {
1537a4c93ae1SAndrew Lunn 		memset(&entry, 0, sizeof(entry));
1538a4c93ae1SAndrew Lunn 		ether_addr_copy(entry.mac, addr);
1539a4c93ae1SAndrew Lunn 	}
1540a4c93ae1SAndrew Lunn 
1541a4c93ae1SAndrew Lunn 	/* Purge the ATU entry only if no port is using it anymore */
1542d8291a95SVivien Didelot 	if (!state) {
1543a4c93ae1SAndrew Lunn 		entry.portvec &= ~BIT(port);
1544a4c93ae1SAndrew Lunn 		if (!entry.portvec)
1545d8291a95SVivien Didelot 			entry.state = 0;
1546a4c93ae1SAndrew Lunn 	} else {
1547a4c93ae1SAndrew Lunn 		entry.portvec |= BIT(port);
1548a4c93ae1SAndrew Lunn 		entry.state = state;
1549a4c93ae1SAndrew Lunn 	}
1550a4c93ae1SAndrew Lunn 
15515ef8d249SVivien Didelot 	return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry);
1552a4c93ae1SAndrew Lunn }
1553a4c93ae1SAndrew Lunn 
1554da7dc875SVivien Didelot static int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port,
1555da7dc875SVivien Didelot 				  const struct mv88e6xxx_policy *policy)
1556da7dc875SVivien Didelot {
1557da7dc875SVivien Didelot 	enum mv88e6xxx_policy_mapping mapping = policy->mapping;
1558da7dc875SVivien Didelot 	enum mv88e6xxx_policy_action action = policy->action;
1559da7dc875SVivien Didelot 	const u8 *addr = policy->addr;
1560da7dc875SVivien Didelot 	u16 vid = policy->vid;
1561da7dc875SVivien Didelot 	u8 state;
1562da7dc875SVivien Didelot 	int err;
1563da7dc875SVivien Didelot 	int id;
1564da7dc875SVivien Didelot 
1565da7dc875SVivien Didelot 	if (!chip->info->ops->port_set_policy)
1566da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1567da7dc875SVivien Didelot 
1568da7dc875SVivien Didelot 	switch (mapping) {
1569da7dc875SVivien Didelot 	case MV88E6XXX_POLICY_MAPPING_DA:
1570da7dc875SVivien Didelot 	case MV88E6XXX_POLICY_MAPPING_SA:
1571da7dc875SVivien Didelot 		if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
1572da7dc875SVivien Didelot 			state = 0; /* Dissociate the port and address */
1573da7dc875SVivien Didelot 		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
1574da7dc875SVivien Didelot 			 is_multicast_ether_addr(addr))
1575da7dc875SVivien Didelot 			state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY;
1576da7dc875SVivien Didelot 		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
1577da7dc875SVivien Didelot 			 is_unicast_ether_addr(addr))
1578da7dc875SVivien Didelot 			state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY;
1579da7dc875SVivien Didelot 		else
1580da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1581da7dc875SVivien Didelot 
1582da7dc875SVivien Didelot 		err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
1583da7dc875SVivien Didelot 						   state);
1584da7dc875SVivien Didelot 		if (err)
1585da7dc875SVivien Didelot 			return err;
1586da7dc875SVivien Didelot 		break;
1587da7dc875SVivien Didelot 	default:
1588da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1589da7dc875SVivien Didelot 	}
1590da7dc875SVivien Didelot 
1591da7dc875SVivien Didelot 	/* Skip the port's policy clearing if the mapping is still in use */
1592da7dc875SVivien Didelot 	if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
1593da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1594da7dc875SVivien Didelot 			if (policy->port == port &&
1595da7dc875SVivien Didelot 			    policy->mapping == mapping &&
1596da7dc875SVivien Didelot 			    policy->action != action)
1597da7dc875SVivien Didelot 				return 0;
1598da7dc875SVivien Didelot 
1599da7dc875SVivien Didelot 	return chip->info->ops->port_set_policy(chip, port, mapping, action);
1600da7dc875SVivien Didelot }
1601da7dc875SVivien Didelot 
1602da7dc875SVivien Didelot static int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port,
1603da7dc875SVivien Didelot 				   struct ethtool_rx_flow_spec *fs)
1604da7dc875SVivien Didelot {
1605da7dc875SVivien Didelot 	struct ethhdr *mac_entry = &fs->h_u.ether_spec;
1606da7dc875SVivien Didelot 	struct ethhdr *mac_mask = &fs->m_u.ether_spec;
1607da7dc875SVivien Didelot 	enum mv88e6xxx_policy_mapping mapping;
1608da7dc875SVivien Didelot 	enum mv88e6xxx_policy_action action;
1609da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1610da7dc875SVivien Didelot 	u16 vid = 0;
1611da7dc875SVivien Didelot 	u8 *addr;
1612da7dc875SVivien Didelot 	int err;
1613da7dc875SVivien Didelot 	int id;
1614da7dc875SVivien Didelot 
1615da7dc875SVivien Didelot 	if (fs->location != RX_CLS_LOC_ANY)
1616da7dc875SVivien Didelot 		return -EINVAL;
1617da7dc875SVivien Didelot 
1618da7dc875SVivien Didelot 	if (fs->ring_cookie == RX_CLS_FLOW_DISC)
1619da7dc875SVivien Didelot 		action = MV88E6XXX_POLICY_ACTION_DISCARD;
1620da7dc875SVivien Didelot 	else
1621da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1622da7dc875SVivien Didelot 
1623da7dc875SVivien Didelot 	switch (fs->flow_type & ~FLOW_EXT) {
1624da7dc875SVivien Didelot 	case ETHER_FLOW:
1625da7dc875SVivien Didelot 		if (!is_zero_ether_addr(mac_mask->h_dest) &&
1626da7dc875SVivien Didelot 		    is_zero_ether_addr(mac_mask->h_source)) {
1627da7dc875SVivien Didelot 			mapping = MV88E6XXX_POLICY_MAPPING_DA;
1628da7dc875SVivien Didelot 			addr = mac_entry->h_dest;
1629da7dc875SVivien Didelot 		} else if (is_zero_ether_addr(mac_mask->h_dest) &&
1630da7dc875SVivien Didelot 		    !is_zero_ether_addr(mac_mask->h_source)) {
1631da7dc875SVivien Didelot 			mapping = MV88E6XXX_POLICY_MAPPING_SA;
1632da7dc875SVivien Didelot 			addr = mac_entry->h_source;
1633da7dc875SVivien Didelot 		} else {
1634da7dc875SVivien Didelot 			/* Cannot support DA and SA mapping in the same rule */
1635da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1636da7dc875SVivien Didelot 		}
1637da7dc875SVivien Didelot 		break;
1638da7dc875SVivien Didelot 	default:
1639da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1640da7dc875SVivien Didelot 	}
1641da7dc875SVivien Didelot 
1642da7dc875SVivien Didelot 	if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) {
1643da7dc875SVivien Didelot 		if (fs->m_ext.vlan_tci != 0xffff)
1644da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1645da7dc875SVivien Didelot 		vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK;
1646da7dc875SVivien Didelot 	}
1647da7dc875SVivien Didelot 
1648da7dc875SVivien Didelot 	idr_for_each_entry(&chip->policies, policy, id) {
1649da7dc875SVivien Didelot 		if (policy->port == port && policy->mapping == mapping &&
1650da7dc875SVivien Didelot 		    policy->action == action && policy->vid == vid &&
1651da7dc875SVivien Didelot 		    ether_addr_equal(policy->addr, addr))
1652da7dc875SVivien Didelot 			return -EEXIST;
1653da7dc875SVivien Didelot 	}
1654da7dc875SVivien Didelot 
1655da7dc875SVivien Didelot 	policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL);
1656da7dc875SVivien Didelot 	if (!policy)
1657da7dc875SVivien Didelot 		return -ENOMEM;
1658da7dc875SVivien Didelot 
1659da7dc875SVivien Didelot 	fs->location = 0;
1660da7dc875SVivien Didelot 	err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff,
1661da7dc875SVivien Didelot 			    GFP_KERNEL);
1662da7dc875SVivien Didelot 	if (err) {
1663da7dc875SVivien Didelot 		devm_kfree(chip->dev, policy);
1664da7dc875SVivien Didelot 		return err;
1665da7dc875SVivien Didelot 	}
1666da7dc875SVivien Didelot 
1667da7dc875SVivien Didelot 	memcpy(&policy->fs, fs, sizeof(*fs));
1668da7dc875SVivien Didelot 	ether_addr_copy(policy->addr, addr);
1669da7dc875SVivien Didelot 	policy->mapping = mapping;
1670da7dc875SVivien Didelot 	policy->action = action;
1671da7dc875SVivien Didelot 	policy->port = port;
1672da7dc875SVivien Didelot 	policy->vid = vid;
1673da7dc875SVivien Didelot 
1674da7dc875SVivien Didelot 	err = mv88e6xxx_policy_apply(chip, port, policy);
1675da7dc875SVivien Didelot 	if (err) {
1676da7dc875SVivien Didelot 		idr_remove(&chip->policies, fs->location);
1677da7dc875SVivien Didelot 		devm_kfree(chip->dev, policy);
1678da7dc875SVivien Didelot 		return err;
1679da7dc875SVivien Didelot 	}
1680da7dc875SVivien Didelot 
1681da7dc875SVivien Didelot 	return 0;
1682da7dc875SVivien Didelot }
1683da7dc875SVivien Didelot 
1684da7dc875SVivien Didelot static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,
1685da7dc875SVivien Didelot 			       struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
1686da7dc875SVivien Didelot {
1687da7dc875SVivien Didelot 	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
1688da7dc875SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1689da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1690da7dc875SVivien Didelot 	int err;
1691da7dc875SVivien Didelot 	int id;
1692da7dc875SVivien Didelot 
1693da7dc875SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1694da7dc875SVivien Didelot 
1695da7dc875SVivien Didelot 	switch (rxnfc->cmd) {
1696da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRLCNT:
1697da7dc875SVivien Didelot 		rxnfc->data = 0;
1698da7dc875SVivien Didelot 		rxnfc->data |= RX_CLS_LOC_SPECIAL;
1699da7dc875SVivien Didelot 		rxnfc->rule_cnt = 0;
1700da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1701da7dc875SVivien Didelot 			if (policy->port == port)
1702da7dc875SVivien Didelot 				rxnfc->rule_cnt++;
1703da7dc875SVivien Didelot 		err = 0;
1704da7dc875SVivien Didelot 		break;
1705da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRULE:
1706da7dc875SVivien Didelot 		err = -ENOENT;
1707da7dc875SVivien Didelot 		policy = idr_find(&chip->policies, fs->location);
1708da7dc875SVivien Didelot 		if (policy) {
1709da7dc875SVivien Didelot 			memcpy(fs, &policy->fs, sizeof(*fs));
1710da7dc875SVivien Didelot 			err = 0;
1711da7dc875SVivien Didelot 		}
1712da7dc875SVivien Didelot 		break;
1713da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRLALL:
1714da7dc875SVivien Didelot 		rxnfc->data = 0;
1715da7dc875SVivien Didelot 		rxnfc->rule_cnt = 0;
1716da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1717da7dc875SVivien Didelot 			if (policy->port == port)
1718da7dc875SVivien Didelot 				rule_locs[rxnfc->rule_cnt++] = id;
1719da7dc875SVivien Didelot 		err = 0;
1720da7dc875SVivien Didelot 		break;
1721da7dc875SVivien Didelot 	default:
1722da7dc875SVivien Didelot 		err = -EOPNOTSUPP;
1723da7dc875SVivien Didelot 		break;
1724da7dc875SVivien Didelot 	}
1725da7dc875SVivien Didelot 
1726da7dc875SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1727da7dc875SVivien Didelot 
1728da7dc875SVivien Didelot 	return err;
1729da7dc875SVivien Didelot }
1730da7dc875SVivien Didelot 
1731da7dc875SVivien Didelot static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port,
1732da7dc875SVivien Didelot 			       struct ethtool_rxnfc *rxnfc)
1733da7dc875SVivien Didelot {
1734da7dc875SVivien Didelot 	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
1735da7dc875SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1736da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1737da7dc875SVivien Didelot 	int err;
1738da7dc875SVivien Didelot 
1739da7dc875SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1740da7dc875SVivien Didelot 
1741da7dc875SVivien Didelot 	switch (rxnfc->cmd) {
1742da7dc875SVivien Didelot 	case ETHTOOL_SRXCLSRLINS:
1743da7dc875SVivien Didelot 		err = mv88e6xxx_policy_insert(chip, port, fs);
1744da7dc875SVivien Didelot 		break;
1745da7dc875SVivien Didelot 	case ETHTOOL_SRXCLSRLDEL:
1746da7dc875SVivien Didelot 		err = -ENOENT;
1747da7dc875SVivien Didelot 		policy = idr_remove(&chip->policies, fs->location);
1748da7dc875SVivien Didelot 		if (policy) {
1749da7dc875SVivien Didelot 			policy->action = MV88E6XXX_POLICY_ACTION_NORMAL;
1750da7dc875SVivien Didelot 			err = mv88e6xxx_policy_apply(chip, port, policy);
1751da7dc875SVivien Didelot 			devm_kfree(chip->dev, policy);
1752da7dc875SVivien Didelot 		}
1753da7dc875SVivien Didelot 		break;
1754da7dc875SVivien Didelot 	default:
1755da7dc875SVivien Didelot 		err = -EOPNOTSUPP;
1756da7dc875SVivien Didelot 		break;
1757da7dc875SVivien Didelot 	}
1758da7dc875SVivien Didelot 
1759da7dc875SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1760da7dc875SVivien Didelot 
1761da7dc875SVivien Didelot 	return err;
1762da7dc875SVivien Didelot }
1763da7dc875SVivien Didelot 
176487fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
176587fa886eSAndrew Lunn 					u16 vid)
176687fa886eSAndrew Lunn {
176787fa886eSAndrew Lunn 	const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
176887fa886eSAndrew Lunn 	u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
176987fa886eSAndrew Lunn 
177087fa886eSAndrew Lunn 	return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
177187fa886eSAndrew Lunn }
177287fa886eSAndrew Lunn 
177387fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
177487fa886eSAndrew Lunn {
177587fa886eSAndrew Lunn 	int port;
177687fa886eSAndrew Lunn 	int err;
177787fa886eSAndrew Lunn 
177887fa886eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
177987fa886eSAndrew Lunn 		err = mv88e6xxx_port_add_broadcast(chip, port, vid);
178087fa886eSAndrew Lunn 		if (err)
178187fa886eSAndrew Lunn 			return err;
178287fa886eSAndrew Lunn 	}
178387fa886eSAndrew Lunn 
178487fa886eSAndrew Lunn 	return 0;
178587fa886eSAndrew Lunn }
178687fa886eSAndrew Lunn 
1787b1ac6fb4SVivien Didelot static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port,
1788c91498e1SVivien Didelot 				    u16 vid, u8 member)
1789fad09c73SVivien Didelot {
1790b1ac6fb4SVivien Didelot 	const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1791b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1792b1ac6fb4SVivien Didelot 	int i, err;
1793fad09c73SVivien Didelot 
1794b1ac6fb4SVivien Didelot 	if (!vid)
1795b1ac6fb4SVivien Didelot 		return -EOPNOTSUPP;
1796b1ac6fb4SVivien Didelot 
1797b1ac6fb4SVivien Didelot 	vlan.vid = vid - 1;
1798b1ac6fb4SVivien Didelot 	vlan.valid = false;
1799b1ac6fb4SVivien Didelot 
1800b1ac6fb4SVivien Didelot 	err = mv88e6xxx_vtu_getnext(chip, &vlan);
1801fad09c73SVivien Didelot 	if (err)
1802fad09c73SVivien Didelot 		return err;
1803fad09c73SVivien Didelot 
1804b1ac6fb4SVivien Didelot 	if (vlan.vid != vid || !vlan.valid) {
1805b1ac6fb4SVivien Didelot 		memset(&vlan, 0, sizeof(vlan));
1806b1ac6fb4SVivien Didelot 
1807b1ac6fb4SVivien Didelot 		err = mv88e6xxx_atu_new(chip, &vlan.fid);
1808b1ac6fb4SVivien Didelot 		if (err)
1809b1ac6fb4SVivien Didelot 			return err;
1810b1ac6fb4SVivien Didelot 
1811b1ac6fb4SVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
1812b1ac6fb4SVivien Didelot 			if (i == port)
1813b1ac6fb4SVivien Didelot 				vlan.member[i] = member;
1814b1ac6fb4SVivien Didelot 			else
1815b1ac6fb4SVivien Didelot 				vlan.member[i] = non_member;
1816b1ac6fb4SVivien Didelot 
1817b1ac6fb4SVivien Didelot 		vlan.vid = vid;
18181cb9dfcaSRasmus Villemoes 		vlan.valid = true;
1819fad09c73SVivien Didelot 
182087fa886eSAndrew Lunn 		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
182187fa886eSAndrew Lunn 		if (err)
182287fa886eSAndrew Lunn 			return err;
182387fa886eSAndrew Lunn 
1824b1ac6fb4SVivien Didelot 		err = mv88e6xxx_broadcast_setup(chip, vlan.vid);
1825b1ac6fb4SVivien Didelot 		if (err)
1826b1ac6fb4SVivien Didelot 			return err;
1827b1ac6fb4SVivien Didelot 	} else if (vlan.member[port] != member) {
1828b1ac6fb4SVivien Didelot 		vlan.member[port] = member;
1829b1ac6fb4SVivien Didelot 
1830b1ac6fb4SVivien Didelot 		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
1831b1ac6fb4SVivien Didelot 		if (err)
1832b1ac6fb4SVivien Didelot 			return err;
1833b1ac6fb4SVivien Didelot 	} else {
1834b1ac6fb4SVivien Didelot 		dev_info(chip->dev, "p%d: already a member of VLAN %d\n",
1835b1ac6fb4SVivien Didelot 			 port, vid);
1836b1ac6fb4SVivien Didelot 	}
1837b1ac6fb4SVivien Didelot 
1838b1ac6fb4SVivien Didelot 	return 0;
1839fad09c73SVivien Didelot }
1840fad09c73SVivien Didelot 
1841fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
184280e02360SVivien Didelot 				    const struct switchdev_obj_port_vlan *vlan)
1843fad09c73SVivien Didelot {
184404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1845fad09c73SVivien Didelot 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1846fad09c73SVivien Didelot 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1847c91498e1SVivien Didelot 	u8 member;
1848fad09c73SVivien Didelot 	u16 vid;
1849fad09c73SVivien Didelot 
18503cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1851fad09c73SVivien Didelot 		return;
1852fad09c73SVivien Didelot 
1853c91498e1SVivien Didelot 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
18547ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED;
1855c91498e1SVivien Didelot 	else if (untagged)
18567ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED;
1857c91498e1SVivien Didelot 	else
18587ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
1859c91498e1SVivien Didelot 
1860c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1861fad09c73SVivien Didelot 
1862fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
1863b1ac6fb4SVivien Didelot 		if (mv88e6xxx_port_vlan_join(chip, port, vid, member))
1864774439e5SVivien Didelot 			dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
1865fad09c73SVivien Didelot 				vid, untagged ? 'u' : 't');
1866fad09c73SVivien Didelot 
186777064f37SVivien Didelot 	if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end))
1868774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to set PVID %d\n", port,
1869fad09c73SVivien Didelot 			vlan->vid_end);
1870fad09c73SVivien Didelot 
1871c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1872fad09c73SVivien Didelot }
1873fad09c73SVivien Didelot 
187452109892SVivien Didelot static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip,
1875fad09c73SVivien Didelot 				     int port, u16 vid)
1876fad09c73SVivien Didelot {
1877b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1878fad09c73SVivien Didelot 	int i, err;
1879fad09c73SVivien Didelot 
188052109892SVivien Didelot 	if (!vid)
188152109892SVivien Didelot 		return -EOPNOTSUPP;
188252109892SVivien Didelot 
188352109892SVivien Didelot 	vlan.vid = vid - 1;
188452109892SVivien Didelot 	vlan.valid = false;
188552109892SVivien Didelot 
188652109892SVivien Didelot 	err = mv88e6xxx_vtu_getnext(chip, &vlan);
1887fad09c73SVivien Didelot 	if (err)
1888fad09c73SVivien Didelot 		return err;
1889fad09c73SVivien Didelot 
189052109892SVivien Didelot 	/* If the VLAN doesn't exist in hardware or the port isn't a member,
189152109892SVivien Didelot 	 * tell switchdev that this VLAN is likely handled in software.
189252109892SVivien Didelot 	 */
189352109892SVivien Didelot 	if (vlan.vid != vid || !vlan.valid ||
189452109892SVivien Didelot 	    vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1895fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1896fad09c73SVivien Didelot 
18977ec60d6eSVivien Didelot 	vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1898fad09c73SVivien Didelot 
1899fad09c73SVivien Didelot 	/* keep the VLAN unless all ports are excluded */
1900fad09c73SVivien Didelot 	vlan.valid = false;
1901370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
19027ec60d6eSVivien Didelot 		if (vlan.member[i] !=
19037ec60d6eSVivien Didelot 		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
1904fad09c73SVivien Didelot 			vlan.valid = true;
1905fad09c73SVivien Didelot 			break;
1906fad09c73SVivien Didelot 		}
1907fad09c73SVivien Didelot 	}
1908fad09c73SVivien Didelot 
19090ad5daf6SVivien Didelot 	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
1910fad09c73SVivien Didelot 	if (err)
1911fad09c73SVivien Didelot 		return err;
1912fad09c73SVivien Didelot 
1913e606ca36SVivien Didelot 	return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
1914fad09c73SVivien Didelot }
1915fad09c73SVivien Didelot 
1916fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
1917fad09c73SVivien Didelot 				   const struct switchdev_obj_port_vlan *vlan)
1918fad09c73SVivien Didelot {
191904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1920fad09c73SVivien Didelot 	u16 pvid, vid;
1921fad09c73SVivien Didelot 	int err = 0;
1922fad09c73SVivien Didelot 
19233cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1924fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1925fad09c73SVivien Didelot 
1926c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1927fad09c73SVivien Didelot 
192877064f37SVivien Didelot 	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
1929fad09c73SVivien Didelot 	if (err)
1930fad09c73SVivien Didelot 		goto unlock;
1931fad09c73SVivien Didelot 
1932fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
193352109892SVivien Didelot 		err = mv88e6xxx_port_vlan_leave(chip, port, vid);
1934fad09c73SVivien Didelot 		if (err)
1935fad09c73SVivien Didelot 			goto unlock;
1936fad09c73SVivien Didelot 
1937fad09c73SVivien Didelot 		if (vid == pvid) {
193877064f37SVivien Didelot 			err = mv88e6xxx_port_set_pvid(chip, port, 0);
1939fad09c73SVivien Didelot 			if (err)
1940fad09c73SVivien Didelot 				goto unlock;
1941fad09c73SVivien Didelot 		}
1942fad09c73SVivien Didelot 	}
1943fad09c73SVivien Didelot 
1944fad09c73SVivien Didelot unlock:
1945c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1946fad09c73SVivien Didelot 
1947fad09c73SVivien Didelot 	return err;
1948fad09c73SVivien Didelot }
1949fad09c73SVivien Didelot 
19501b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
19516c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
1952fad09c73SVivien Didelot {
195304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
19541b6dd556SArkadi Sharshevsky 	int err;
1955fad09c73SVivien Didelot 
1956c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
19571b6dd556SArkadi Sharshevsky 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
19581b6dd556SArkadi Sharshevsky 					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
1959c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
19601b6dd556SArkadi Sharshevsky 
19611b6dd556SArkadi Sharshevsky 	return err;
1962fad09c73SVivien Didelot }
1963fad09c73SVivien Didelot 
1964fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
19656c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
1966fad09c73SVivien Didelot {
196704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
196883dabd1fSVivien Didelot 	int err;
1969fad09c73SVivien Didelot 
1970c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1971d8291a95SVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
1972c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1973fad09c73SVivien Didelot 
197483dabd1fSVivien Didelot 	return err;
1975fad09c73SVivien Didelot }
1976fad09c73SVivien Didelot 
197783dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
1978fad09c73SVivien Didelot 				      u16 fid, u16 vid, int port,
19792bedde1aSArkadi Sharshevsky 				      dsa_fdb_dump_cb_t *cb, void *data)
1980fad09c73SVivien Didelot {
1981dabc1a96SVivien Didelot 	struct mv88e6xxx_atu_entry addr;
19822bedde1aSArkadi Sharshevsky 	bool is_static;
1983fad09c73SVivien Didelot 	int err;
1984fad09c73SVivien Didelot 
1985d8291a95SVivien Didelot 	addr.state = 0;
1986dabc1a96SVivien Didelot 	eth_broadcast_addr(addr.mac);
1987fad09c73SVivien Didelot 
1988fad09c73SVivien Didelot 	do {
1989dabc1a96SVivien Didelot 		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
1990fad09c73SVivien Didelot 		if (err)
199183dabd1fSVivien Didelot 			return err;
1992fad09c73SVivien Didelot 
1993d8291a95SVivien Didelot 		if (!addr.state)
1994fad09c73SVivien Didelot 			break;
1995fad09c73SVivien Didelot 
199601bd96c8SVivien Didelot 		if (addr.trunk || (addr.portvec & BIT(port)) == 0)
199783dabd1fSVivien Didelot 			continue;
1998fad09c73SVivien Didelot 
199983dabd1fSVivien Didelot 		if (!is_unicast_ether_addr(addr.mac))
200083dabd1fSVivien Didelot 			continue;
200183dabd1fSVivien Didelot 
20022bedde1aSArkadi Sharshevsky 		is_static = (addr.state ==
20032bedde1aSArkadi Sharshevsky 			     MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
20042bedde1aSArkadi Sharshevsky 		err = cb(addr.mac, vid, is_static, data);
200583dabd1fSVivien Didelot 		if (err)
200683dabd1fSVivien Didelot 			return err;
2007fad09c73SVivien Didelot 	} while (!is_broadcast_ether_addr(addr.mac));
2008fad09c73SVivien Didelot 
2009fad09c73SVivien Didelot 	return err;
2010fad09c73SVivien Didelot }
2011fad09c73SVivien Didelot 
201283dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
20132bedde1aSArkadi Sharshevsky 				  dsa_fdb_dump_cb_t *cb, void *data)
201483dabd1fSVivien Didelot {
2015425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
201683dabd1fSVivien Didelot 	u16 fid;
201783dabd1fSVivien Didelot 	int err;
201883dabd1fSVivien Didelot 
201983dabd1fSVivien Didelot 	/* Dump port's default Filtering Information Database (VLAN ID 0) */
2020b4e48c50SVivien Didelot 	err = mv88e6xxx_port_get_fid(chip, port, &fid);
202183dabd1fSVivien Didelot 	if (err)
202283dabd1fSVivien Didelot 		return err;
202383dabd1fSVivien Didelot 
20242bedde1aSArkadi Sharshevsky 	err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data);
202583dabd1fSVivien Didelot 	if (err)
202683dabd1fSVivien Didelot 		return err;
202783dabd1fSVivien Didelot 
202883dabd1fSVivien Didelot 	/* Dump VLANs' Filtering Information Databases */
2029425d2d37SVivien Didelot 	vlan.vid = chip->info->max_vid;
2030425d2d37SVivien Didelot 	vlan.valid = false;
2031425d2d37SVivien Didelot 
203283dabd1fSVivien Didelot 	do {
2033f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
203483dabd1fSVivien Didelot 		if (err)
203583dabd1fSVivien Didelot 			return err;
203683dabd1fSVivien Didelot 
203783dabd1fSVivien Didelot 		if (!vlan.valid)
203883dabd1fSVivien Didelot 			break;
203983dabd1fSVivien Didelot 
204083dabd1fSVivien Didelot 		err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port,
20412bedde1aSArkadi Sharshevsky 						 cb, data);
204283dabd1fSVivien Didelot 		if (err)
204383dabd1fSVivien Didelot 			return err;
20443cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
204583dabd1fSVivien Didelot 
204683dabd1fSVivien Didelot 	return err;
204783dabd1fSVivien Didelot }
204883dabd1fSVivien Didelot 
2049fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
20502bedde1aSArkadi Sharshevsky 				   dsa_fdb_dump_cb_t *cb, void *data)
2051fad09c73SVivien Didelot {
205204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2053fcf15367SVivien Didelot 	int err;
2054fad09c73SVivien Didelot 
2055c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2056fcf15367SVivien Didelot 	err = mv88e6xxx_port_db_dump(chip, port, cb, data);
2057c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2058fcf15367SVivien Didelot 
2059fcf15367SVivien Didelot 	return err;
2060fad09c73SVivien Didelot }
2061fad09c73SVivien Didelot 
2062240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
2063240ea3efSVivien Didelot 				struct net_device *br)
2064240ea3efSVivien Didelot {
2065ef2025ecSVivien Didelot 	struct dsa_switch *ds = chip->ds;
2066ef2025ecSVivien Didelot 	struct dsa_switch_tree *dst = ds->dst;
2067ef2025ecSVivien Didelot 	struct dsa_port *dp;
2068240ea3efSVivien Didelot 	int err;
2069240ea3efSVivien Didelot 
2070ef2025ecSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list) {
2071ef2025ecSVivien Didelot 		if (dp->bridge_dev == br) {
2072ef2025ecSVivien Didelot 			if (dp->ds == ds) {
2073ef2025ecSVivien Didelot 				/* This is a local bridge group member,
2074ef2025ecSVivien Didelot 				 * remap its Port VLAN Map.
2075ef2025ecSVivien Didelot 				 */
2076ef2025ecSVivien Didelot 				err = mv88e6xxx_port_vlan_map(chip, dp->index);
2077240ea3efSVivien Didelot 				if (err)
2078240ea3efSVivien Didelot 					return err;
2079ef2025ecSVivien Didelot 			} else {
2080ef2025ecSVivien Didelot 				/* This is an external bridge group member,
2081ef2025ecSVivien Didelot 				 * remap its cross-chip Port VLAN Table entry.
2082ef2025ecSVivien Didelot 				 */
2083ef2025ecSVivien Didelot 				err = mv88e6xxx_pvt_map(chip, dp->ds->index,
2084ef2025ecSVivien Didelot 							dp->index);
2085e96a6e02SVivien Didelot 				if (err)
2086e96a6e02SVivien Didelot 					return err;
2087e96a6e02SVivien Didelot 			}
2088e96a6e02SVivien Didelot 		}
2089e96a6e02SVivien Didelot 	}
2090e96a6e02SVivien Didelot 
2091240ea3efSVivien Didelot 	return 0;
2092240ea3efSVivien Didelot }
2093240ea3efSVivien Didelot 
2094fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
2095fae8a25eSVivien Didelot 				      struct net_device *br)
2096fad09c73SVivien Didelot {
209704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2098240ea3efSVivien Didelot 	int err;
2099fad09c73SVivien Didelot 
2100c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2101240ea3efSVivien Didelot 	err = mv88e6xxx_bridge_map(chip, br);
2102c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2103fad09c73SVivien Didelot 
2104fad09c73SVivien Didelot 	return err;
2105fad09c73SVivien Didelot }
2106fad09c73SVivien Didelot 
2107f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
2108f123f2fbSVivien Didelot 					struct net_device *br)
2109fad09c73SVivien Didelot {
211004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2111fad09c73SVivien Didelot 
2112c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2113240ea3efSVivien Didelot 	if (mv88e6xxx_bridge_map(chip, br) ||
2114240ea3efSVivien Didelot 	    mv88e6xxx_port_vlan_map(chip, port))
2115240ea3efSVivien Didelot 		dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
2116c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2117fad09c73SVivien Didelot }
2118fad09c73SVivien Didelot 
2119aec5ac88SVivien Didelot static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev,
2120aec5ac88SVivien Didelot 					   int port, struct net_device *br)
2121aec5ac88SVivien Didelot {
2122aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2123aec5ac88SVivien Didelot 	int err;
2124aec5ac88SVivien Didelot 
2125c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2126aec5ac88SVivien Didelot 	err = mv88e6xxx_pvt_map(chip, dev, port);
2127c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2128aec5ac88SVivien Didelot 
2129aec5ac88SVivien Didelot 	return err;
2130aec5ac88SVivien Didelot }
2131aec5ac88SVivien Didelot 
2132aec5ac88SVivien Didelot static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev,
2133aec5ac88SVivien Didelot 					     int port, struct net_device *br)
2134aec5ac88SVivien Didelot {
2135aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2136aec5ac88SVivien Didelot 
2137c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2138aec5ac88SVivien Didelot 	if (mv88e6xxx_pvt_map(chip, dev, port))
2139aec5ac88SVivien Didelot 		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
2140c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2141aec5ac88SVivien Didelot }
2142aec5ac88SVivien Didelot 
214317e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
214417e708baSVivien Didelot {
214517e708baSVivien Didelot 	if (chip->info->ops->reset)
214617e708baSVivien Didelot 		return chip->info->ops->reset(chip);
214717e708baSVivien Didelot 
214817e708baSVivien Didelot 	return 0;
214917e708baSVivien Didelot }
215017e708baSVivien Didelot 
2151309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
2152309eca6dSVivien Didelot {
2153309eca6dSVivien Didelot 	struct gpio_desc *gpiod = chip->reset;
2154309eca6dSVivien Didelot 
2155309eca6dSVivien Didelot 	/* If there is a GPIO connected to the reset pin, toggle it */
2156309eca6dSVivien Didelot 	if (gpiod) {
2157309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 1);
2158309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2159309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 0);
2160309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2161309eca6dSVivien Didelot 	}
2162309eca6dSVivien Didelot }
2163309eca6dSVivien Didelot 
21644ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
21654ac4b5a6SVivien Didelot {
21664ac4b5a6SVivien Didelot 	int i, err;
21674ac4b5a6SVivien Didelot 
21684ac4b5a6SVivien Didelot 	/* Set all ports to the Disabled state */
21694ac4b5a6SVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2170f894c29cSVivien Didelot 		err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED);
21714ac4b5a6SVivien Didelot 		if (err)
21724ac4b5a6SVivien Didelot 			return err;
21734ac4b5a6SVivien Didelot 	}
21744ac4b5a6SVivien Didelot 
21754ac4b5a6SVivien Didelot 	/* Wait for transmit queues to drain,
21764ac4b5a6SVivien Didelot 	 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
21774ac4b5a6SVivien Didelot 	 */
21784ac4b5a6SVivien Didelot 	usleep_range(2000, 4000);
21794ac4b5a6SVivien Didelot 
21804ac4b5a6SVivien Didelot 	return 0;
21814ac4b5a6SVivien Didelot }
21824ac4b5a6SVivien Didelot 
2183fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
2184fad09c73SVivien Didelot {
2185a935c052SVivien Didelot 	int err;
2186fad09c73SVivien Didelot 
21874ac4b5a6SVivien Didelot 	err = mv88e6xxx_disable_ports(chip);
21880e7b9925SAndrew Lunn 	if (err)
21890e7b9925SAndrew Lunn 		return err;
2190fad09c73SVivien Didelot 
2191309eca6dSVivien Didelot 	mv88e6xxx_hardware_reset(chip);
2192fad09c73SVivien Didelot 
219317e708baSVivien Didelot 	return mv88e6xxx_software_reset(chip);
2194fad09c73SVivien Didelot }
2195fad09c73SVivien Didelot 
21964314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
219731bef4e9SVivien Didelot 				   enum mv88e6xxx_frame_mode frame,
219831bef4e9SVivien Didelot 				   enum mv88e6xxx_egress_mode egress, u16 etype)
219956995cbcSAndrew Lunn {
220056995cbcSAndrew Lunn 	int err;
220156995cbcSAndrew Lunn 
22024314557cSVivien Didelot 	if (!chip->info->ops->port_set_frame_mode)
22034314557cSVivien Didelot 		return -EOPNOTSUPP;
22044314557cSVivien Didelot 
22054314557cSVivien Didelot 	err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
220656995cbcSAndrew Lunn 	if (err)
220756995cbcSAndrew Lunn 		return err;
220856995cbcSAndrew Lunn 
22094314557cSVivien Didelot 	err = chip->info->ops->port_set_frame_mode(chip, port, frame);
22104314557cSVivien Didelot 	if (err)
22114314557cSVivien Didelot 		return err;
22124314557cSVivien Didelot 
22134314557cSVivien Didelot 	if (chip->info->ops->port_set_ether_type)
22144314557cSVivien Didelot 		return chip->info->ops->port_set_ether_type(chip, port, etype);
22154314557cSVivien Didelot 
22164314557cSVivien Didelot 	return 0;
22174314557cSVivien Didelot }
22184314557cSVivien Didelot 
22194314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
22204314557cSVivien Didelot {
22214314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
222231bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2223b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
22244314557cSVivien Didelot }
22254314557cSVivien Didelot 
22264314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
22274314557cSVivien Didelot {
22284314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
222931bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2230b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
22314314557cSVivien Didelot }
22324314557cSVivien Didelot 
22334314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
22344314557cSVivien Didelot {
22354314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port,
22364314557cSVivien Didelot 				       MV88E6XXX_FRAME_MODE_ETHERTYPE,
223731bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_ETHERTYPE,
223831bef4e9SVivien Didelot 				       ETH_P_EDSA);
22394314557cSVivien Didelot }
22404314557cSVivien Didelot 
22414314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port)
22424314557cSVivien Didelot {
22434314557cSVivien Didelot 	if (dsa_is_dsa_port(chip->ds, port))
22444314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
22454314557cSVivien Didelot 
22462b3e9891SVivien Didelot 	if (dsa_is_user_port(chip->ds, port))
22474314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_normal(chip, port);
22484314557cSVivien Didelot 
22494314557cSVivien Didelot 	/* Setup CPU port mode depending on its supported tag format */
22504314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA)
22514314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
22524314557cSVivien Didelot 
22534314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA)
22544314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_edsa(chip, port);
22554314557cSVivien Didelot 
22564314557cSVivien Didelot 	return -EINVAL;
22574314557cSVivien Didelot }
22584314557cSVivien Didelot 
2259ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
2260ea698f4fSVivien Didelot {
2261ea698f4fSVivien Didelot 	bool message = dsa_is_dsa_port(chip->ds, port);
2262ea698f4fSVivien Didelot 
2263ea698f4fSVivien Didelot 	return mv88e6xxx_port_set_message_port(chip, port, message);
2264ea698f4fSVivien Didelot }
2265ea698f4fSVivien Didelot 
2266601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
2267601aeed3SVivien Didelot {
22683ee50cbfSVivien Didelot 	struct dsa_switch *ds = chip->ds;
2269407308f6SDavid S. Miller 	bool flood;
2270601aeed3SVivien Didelot 
2271407308f6SDavid S. Miller 	/* Upstream ports flood frames with unknown unicast or multicast DA */
2272407308f6SDavid S. Miller 	flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port);
2273407308f6SDavid S. Miller 	if (chip->info->ops->port_set_egress_floods)
2274407308f6SDavid S. Miller 		return chip->info->ops->port_set_egress_floods(chip, port,
2275407308f6SDavid S. Miller 							       flood, flood);
2276407308f6SDavid S. Miller 
2277601aeed3SVivien Didelot 	return 0;
2278601aeed3SVivien Didelot }
2279601aeed3SVivien Didelot 
228045de77ffSVivien Didelot static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
228145de77ffSVivien Didelot {
228245de77ffSVivien Didelot 	struct mv88e6xxx_port *mvp = dev_id;
228345de77ffSVivien Didelot 	struct mv88e6xxx_chip *chip = mvp->chip;
228445de77ffSVivien Didelot 	irqreturn_t ret = IRQ_NONE;
228545de77ffSVivien Didelot 	int port = mvp->port;
228645de77ffSVivien Didelot 	u8 lane;
228745de77ffSVivien Didelot 
228845de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
228945de77ffSVivien Didelot 	lane = mv88e6xxx_serdes_get_lane(chip, port);
229045de77ffSVivien Didelot 	if (lane)
229145de77ffSVivien Didelot 		ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
229245de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
229345de77ffSVivien Didelot 
229445de77ffSVivien Didelot 	return ret;
229545de77ffSVivien Didelot }
229645de77ffSVivien Didelot 
229745de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
229845de77ffSVivien Didelot 					u8 lane)
229945de77ffSVivien Didelot {
230045de77ffSVivien Didelot 	struct mv88e6xxx_port *dev_id = &chip->ports[port];
230145de77ffSVivien Didelot 	unsigned int irq;
230245de77ffSVivien Didelot 	int err;
230345de77ffSVivien Didelot 
230445de77ffSVivien Didelot 	/* Nothing to request if this SERDES port has no IRQ */
230545de77ffSVivien Didelot 	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
230645de77ffSVivien Didelot 	if (!irq)
230745de77ffSVivien Didelot 		return 0;
230845de77ffSVivien Didelot 
2309e6f2f6b8SAndrew Lunn 	snprintf(dev_id->serdes_irq_name, sizeof(dev_id->serdes_irq_name),
2310e6f2f6b8SAndrew Lunn 		 "mv88e6xxx-%s-serdes-%d", dev_name(chip->dev), port);
2311e6f2f6b8SAndrew Lunn 
231245de77ffSVivien Didelot 	/* Requesting the IRQ will trigger IRQ callbacks, so release the lock */
231345de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
231445de77ffSVivien Didelot 	err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn,
2315e6f2f6b8SAndrew Lunn 				   IRQF_ONESHOT, dev_id->serdes_irq_name,
2316e6f2f6b8SAndrew Lunn 				   dev_id);
231745de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
231845de77ffSVivien Didelot 	if (err)
231945de77ffSVivien Didelot 		return err;
232045de77ffSVivien Didelot 
232145de77ffSVivien Didelot 	dev_id->serdes_irq = irq;
232245de77ffSVivien Didelot 
232345de77ffSVivien Didelot 	return mv88e6xxx_serdes_irq_enable(chip, port, lane);
232445de77ffSVivien Didelot }
232545de77ffSVivien Didelot 
232645de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
232745de77ffSVivien Didelot 				     u8 lane)
232845de77ffSVivien Didelot {
232945de77ffSVivien Didelot 	struct mv88e6xxx_port *dev_id = &chip->ports[port];
233045de77ffSVivien Didelot 	unsigned int irq = dev_id->serdes_irq;
233145de77ffSVivien Didelot 	int err;
233245de77ffSVivien Didelot 
233345de77ffSVivien Didelot 	/* Nothing to free if no IRQ has been requested */
233445de77ffSVivien Didelot 	if (!irq)
233545de77ffSVivien Didelot 		return 0;
233645de77ffSVivien Didelot 
233745de77ffSVivien Didelot 	err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
233845de77ffSVivien Didelot 
233945de77ffSVivien Didelot 	/* Freeing the IRQ will trigger IRQ callbacks, so release the lock */
234045de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
234145de77ffSVivien Didelot 	free_irq(irq, dev_id);
234245de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
234345de77ffSVivien Didelot 
234445de77ffSVivien Didelot 	dev_id->serdes_irq = 0;
234545de77ffSVivien Didelot 
234645de77ffSVivien Didelot 	return err;
234745de77ffSVivien Didelot }
234845de77ffSVivien Didelot 
23496d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
23506d91782fSAndrew Lunn 				  bool on)
23516d91782fSAndrew Lunn {
2352dc272f60SVivien Didelot 	u8 lane;
2353fc0bc019SVivien Didelot 	int err;
23546d91782fSAndrew Lunn 
2355dc272f60SVivien Didelot 	lane = mv88e6xxx_serdes_get_lane(chip, port);
2356dc272f60SVivien Didelot 	if (!lane)
2357523a8904SVivien Didelot 		return 0;
2358fc0bc019SVivien Didelot 
2359fc0bc019SVivien Didelot 	if (on) {
2360dc272f60SVivien Didelot 		err = mv88e6xxx_serdes_power_up(chip, port, lane);
2361fc0bc019SVivien Didelot 		if (err)
2362fc0bc019SVivien Didelot 			return err;
2363fc0bc019SVivien Didelot 
236445de77ffSVivien Didelot 		err = mv88e6xxx_serdes_irq_request(chip, port, lane);
2365fc0bc019SVivien Didelot 	} else {
236645de77ffSVivien Didelot 		err = mv88e6xxx_serdes_irq_free(chip, port, lane);
236745de77ffSVivien Didelot 		if (err)
236845de77ffSVivien Didelot 			return err;
2369fc0bc019SVivien Didelot 
2370dc272f60SVivien Didelot 		err = mv88e6xxx_serdes_power_down(chip, port, lane);
2371fc0bc019SVivien Didelot 	}
2372fc0bc019SVivien Didelot 
2373fc0bc019SVivien Didelot 	return err;
23746d91782fSAndrew Lunn }
23756d91782fSAndrew Lunn 
2376fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
2377fa371c80SVivien Didelot {
2378fa371c80SVivien Didelot 	struct dsa_switch *ds = chip->ds;
2379fa371c80SVivien Didelot 	int upstream_port;
2380fa371c80SVivien Didelot 	int err;
2381fa371c80SVivien Didelot 
238207073c79SVivien Didelot 	upstream_port = dsa_upstream_port(ds, port);
2383fa371c80SVivien Didelot 	if (chip->info->ops->port_set_upstream_port) {
2384fa371c80SVivien Didelot 		err = chip->info->ops->port_set_upstream_port(chip, port,
2385fa371c80SVivien Didelot 							      upstream_port);
2386fa371c80SVivien Didelot 		if (err)
2387fa371c80SVivien Didelot 			return err;
2388fa371c80SVivien Didelot 	}
2389fa371c80SVivien Didelot 
23900ea54ddaSVivien Didelot 	if (port == upstream_port) {
23910ea54ddaSVivien Didelot 		if (chip->info->ops->set_cpu_port) {
23920ea54ddaSVivien Didelot 			err = chip->info->ops->set_cpu_port(chip,
23930ea54ddaSVivien Didelot 							    upstream_port);
23940ea54ddaSVivien Didelot 			if (err)
23950ea54ddaSVivien Didelot 				return err;
23960ea54ddaSVivien Didelot 		}
23970ea54ddaSVivien Didelot 
23980ea54ddaSVivien Didelot 		if (chip->info->ops->set_egress_port) {
23990ea54ddaSVivien Didelot 			err = chip->info->ops->set_egress_port(chip,
24005c74c54cSIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS,
24015c74c54cSIwan R Timmer 						upstream_port);
24025c74c54cSIwan R Timmer 			if (err)
24035c74c54cSIwan R Timmer 				return err;
24045c74c54cSIwan R Timmer 
24055c74c54cSIwan R Timmer 			err = chip->info->ops->set_egress_port(chip,
24065c74c54cSIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS,
24070ea54ddaSVivien Didelot 						upstream_port);
24080ea54ddaSVivien Didelot 			if (err)
24090ea54ddaSVivien Didelot 				return err;
24100ea54ddaSVivien Didelot 		}
24110ea54ddaSVivien Didelot 	}
24120ea54ddaSVivien Didelot 
2413fa371c80SVivien Didelot 	return 0;
2414fa371c80SVivien Didelot }
2415fa371c80SVivien Didelot 
2416fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
2417fad09c73SVivien Didelot {
2418fad09c73SVivien Didelot 	struct dsa_switch *ds = chip->ds;
24190e7b9925SAndrew Lunn 	int err;
2420fad09c73SVivien Didelot 	u16 reg;
2421fad09c73SVivien Didelot 
24227b898469SAndrew Lunn 	chip->ports[port].chip = chip;
24237b898469SAndrew Lunn 	chip->ports[port].port = port;
24247b898469SAndrew Lunn 
2425d78343d2SVivien Didelot 	/* MAC Forcing register: don't force link, speed, duplex or flow control
2426d78343d2SVivien Didelot 	 * state to any particular values on physical ports, but force the CPU
2427d78343d2SVivien Didelot 	 * port and all DSA ports to their maximum bandwidth and full duplex.
2428fad09c73SVivien Didelot 	 */
2429d78343d2SVivien Didelot 	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
2430d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
2431d78343d2SVivien Didelot 					       SPEED_MAX, DUPLEX_FULL,
243254186b91SAndrew Lunn 					       PAUSE_OFF,
2433d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
2434fad09c73SVivien Didelot 	else
2435d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
2436d78343d2SVivien Didelot 					       SPEED_UNFORCED, DUPLEX_UNFORCED,
243754186b91SAndrew Lunn 					       PAUSE_ON,
2438d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
24390e7b9925SAndrew Lunn 	if (err)
24400e7b9925SAndrew Lunn 		return err;
2441fad09c73SVivien Didelot 
2442fad09c73SVivien Didelot 	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
2443fad09c73SVivien Didelot 	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
2444fad09c73SVivien Didelot 	 * tunneling, determine priority by looking at 802.1p and IP
2445fad09c73SVivien Didelot 	 * priority fields (IP prio has precedence), and set STP state
2446fad09c73SVivien Didelot 	 * to Forwarding.
2447fad09c73SVivien Didelot 	 *
2448fad09c73SVivien Didelot 	 * If this is the CPU link, use DSA or EDSA tagging depending
2449fad09c73SVivien Didelot 	 * on which tagging mode was configured.
2450fad09c73SVivien Didelot 	 *
2451fad09c73SVivien Didelot 	 * If this is a link to another switch, use DSA tagging mode.
2452fad09c73SVivien Didelot 	 *
2453fad09c73SVivien Didelot 	 * If this is the upstream port for this switch, enable
2454fad09c73SVivien Didelot 	 * forwarding of unknown unicasts and multicasts.
2455fad09c73SVivien Didelot 	 */
2456a89b433bSVivien Didelot 	reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP |
2457a89b433bSVivien Didelot 		MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
2458a89b433bSVivien Didelot 		MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
2459a89b433bSVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
24600e7b9925SAndrew Lunn 	if (err)
24610e7b9925SAndrew Lunn 		return err;
246256995cbcSAndrew Lunn 
2463601aeed3SVivien Didelot 	err = mv88e6xxx_setup_port_mode(chip, port);
246456995cbcSAndrew Lunn 	if (err)
246556995cbcSAndrew Lunn 		return err;
2466fad09c73SVivien Didelot 
2467601aeed3SVivien Didelot 	err = mv88e6xxx_setup_egress_floods(chip, port);
24684314557cSVivien Didelot 	if (err)
24694314557cSVivien Didelot 		return err;
24704314557cSVivien Didelot 
2471fad09c73SVivien Didelot 	/* Port Control 2: don't force a good FCS, set the maximum frame size to
2472fad09c73SVivien Didelot 	 * 10240 bytes, disable 802.1q tags checking, don't discard tagged or
2473fad09c73SVivien Didelot 	 * untagged frames on this port, do a destination address lookup on all
2474fad09c73SVivien Didelot 	 * received packets as usual, disable ARP mirroring and don't send a
2475fad09c73SVivien Didelot 	 * copy of all transmitted/received frames on this port to the CPU.
2476fad09c73SVivien Didelot 	 */
2477a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_map_da(chip, port);
2478a23b2961SAndrew Lunn 	if (err)
2479a23b2961SAndrew Lunn 		return err;
2480a23b2961SAndrew Lunn 
2481fa371c80SVivien Didelot 	err = mv88e6xxx_setup_upstream_port(chip, port);
24820e7b9925SAndrew Lunn 	if (err)
24830e7b9925SAndrew Lunn 		return err;
2484fad09c73SVivien Didelot 
2485a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_8021q_mode(chip, port,
248681c6edb2SVivien Didelot 				MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED);
2487a23b2961SAndrew Lunn 	if (err)
2488a23b2961SAndrew Lunn 		return err;
2489a23b2961SAndrew Lunn 
2490cd782656SVivien Didelot 	if (chip->info->ops->port_set_jumbo_size) {
2491cd782656SVivien Didelot 		err = chip->info->ops->port_set_jumbo_size(chip, port, 10240);
24925f436666SAndrew Lunn 		if (err)
24935f436666SAndrew Lunn 			return err;
24945f436666SAndrew Lunn 	}
24955f436666SAndrew Lunn 
2496fad09c73SVivien Didelot 	/* Port Association Vector: when learning source addresses
2497fad09c73SVivien Didelot 	 * of packets, add the address to the address database using
2498fad09c73SVivien Didelot 	 * a port bitmap that has only the bit for this port set and
2499fad09c73SVivien Didelot 	 * the other bits clear.
2500fad09c73SVivien Didelot 	 */
2501fad09c73SVivien Didelot 	reg = 1 << port;
2502fad09c73SVivien Didelot 	/* Disable learning for CPU port */
2503fad09c73SVivien Didelot 	if (dsa_is_cpu_port(ds, port))
2504fad09c73SVivien Didelot 		reg = 0;
2505fad09c73SVivien Didelot 
25062a4614e4SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
25072a4614e4SVivien Didelot 				   reg);
25080e7b9925SAndrew Lunn 	if (err)
25090e7b9925SAndrew Lunn 		return err;
2510fad09c73SVivien Didelot 
2511fad09c73SVivien Didelot 	/* Egress rate control 2: disable egress rate control. */
25122cb8cb14SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2,
25132cb8cb14SVivien Didelot 				   0x0000);
25140e7b9925SAndrew Lunn 	if (err)
25150e7b9925SAndrew Lunn 		return err;
2516fad09c73SVivien Didelot 
25170898432cSVivien Didelot 	if (chip->info->ops->port_pause_limit) {
25180898432cSVivien Didelot 		err = chip->info->ops->port_pause_limit(chip, port, 0, 0);
2519b35d322aSAndrew Lunn 		if (err)
2520b35d322aSAndrew Lunn 			return err;
2521b35d322aSAndrew Lunn 	}
2522b35d322aSAndrew Lunn 
2523c8c94891SVivien Didelot 	if (chip->info->ops->port_disable_learn_limit) {
2524c8c94891SVivien Didelot 		err = chip->info->ops->port_disable_learn_limit(chip, port);
2525c8c94891SVivien Didelot 		if (err)
2526c8c94891SVivien Didelot 			return err;
2527c8c94891SVivien Didelot 	}
2528c8c94891SVivien Didelot 
25299dbfb4e1SVivien Didelot 	if (chip->info->ops->port_disable_pri_override) {
25309dbfb4e1SVivien Didelot 		err = chip->info->ops->port_disable_pri_override(chip, port);
25310e7b9925SAndrew Lunn 		if (err)
25320e7b9925SAndrew Lunn 			return err;
2533ef0a7318SAndrew Lunn 	}
25342bbb33beSAndrew Lunn 
2535ef0a7318SAndrew Lunn 	if (chip->info->ops->port_tag_remap) {
2536ef0a7318SAndrew Lunn 		err = chip->info->ops->port_tag_remap(chip, port);
25370e7b9925SAndrew Lunn 		if (err)
25380e7b9925SAndrew Lunn 			return err;
2539fad09c73SVivien Didelot 	}
2540fad09c73SVivien Didelot 
2541ef70b111SAndrew Lunn 	if (chip->info->ops->port_egress_rate_limiting) {
2542ef70b111SAndrew Lunn 		err = chip->info->ops->port_egress_rate_limiting(chip, port);
25430e7b9925SAndrew Lunn 		if (err)
25440e7b9925SAndrew Lunn 			return err;
2545fad09c73SVivien Didelot 	}
2546fad09c73SVivien Didelot 
2547121b8fe2SHubert Feurstein 	if (chip->info->ops->port_setup_message_port) {
2548121b8fe2SHubert Feurstein 		err = chip->info->ops->port_setup_message_port(chip, port);
25490e7b9925SAndrew Lunn 		if (err)
25500e7b9925SAndrew Lunn 			return err;
2551121b8fe2SHubert Feurstein 	}
2552fad09c73SVivien Didelot 
2553fad09c73SVivien Didelot 	/* Port based VLAN map: give each port the same default address
2554fad09c73SVivien Didelot 	 * database, and allow bidirectional communication between the
2555fad09c73SVivien Didelot 	 * CPU and DSA port(s), and the other ports.
2556fad09c73SVivien Didelot 	 */
2557b4e48c50SVivien Didelot 	err = mv88e6xxx_port_set_fid(chip, port, 0);
25580e7b9925SAndrew Lunn 	if (err)
25590e7b9925SAndrew Lunn 		return err;
2560fad09c73SVivien Didelot 
2561240ea3efSVivien Didelot 	err = mv88e6xxx_port_vlan_map(chip, port);
25620e7b9925SAndrew Lunn 	if (err)
25630e7b9925SAndrew Lunn 		return err;
2564fad09c73SVivien Didelot 
2565fad09c73SVivien Didelot 	/* Default VLAN ID and priority: don't set a default VLAN
2566fad09c73SVivien Didelot 	 * ID, and set the default packet priority to zero.
2567fad09c73SVivien Didelot 	 */
2568b7929fb3SVivien Didelot 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0);
2569fad09c73SVivien Didelot }
2570fad09c73SVivien Didelot 
257104aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
257204aca993SAndrew Lunn 				 struct phy_device *phydev)
257304aca993SAndrew Lunn {
257404aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
2575523a8904SVivien Didelot 	int err;
257604aca993SAndrew Lunn 
2577c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2578523a8904SVivien Didelot 	err = mv88e6xxx_serdes_power(chip, port, true);
2579c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
258004aca993SAndrew Lunn 
258104aca993SAndrew Lunn 	return err;
258204aca993SAndrew Lunn }
258304aca993SAndrew Lunn 
258475104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
258504aca993SAndrew Lunn {
258604aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
258704aca993SAndrew Lunn 
2588c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2589523a8904SVivien Didelot 	if (mv88e6xxx_serdes_power(chip, port, false))
2590523a8904SVivien Didelot 		dev_err(chip->dev, "failed to power off SERDES\n");
2591c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
259204aca993SAndrew Lunn }
259304aca993SAndrew Lunn 
25942cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
25952cfcd964SVivien Didelot 				     unsigned int ageing_time)
25962cfcd964SVivien Didelot {
259704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
25982cfcd964SVivien Didelot 	int err;
25992cfcd964SVivien Didelot 
2600c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2601720c6343SVivien Didelot 	err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
2602c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
26032cfcd964SVivien Didelot 
26042cfcd964SVivien Didelot 	return err;
26052cfcd964SVivien Didelot }
26062cfcd964SVivien Didelot 
2607447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
2608fad09c73SVivien Didelot {
2609fad09c73SVivien Didelot 	int err;
2610fad09c73SVivien Didelot 
2611de227387SAndrew Lunn 	/* Initialize the statistics unit */
2612447b1bb8SVivien Didelot 	if (chip->info->ops->stats_set_histogram) {
2613447b1bb8SVivien Didelot 		err = chip->info->ops->stats_set_histogram(chip);
2614de227387SAndrew Lunn 		if (err)
2615de227387SAndrew Lunn 			return err;
2616447b1bb8SVivien Didelot 	}
2617de227387SAndrew Lunn 
261840cff8fcSAndrew Lunn 	return mv88e6xxx_g1_stats_clear(chip);
26199729934cSVivien Didelot }
26209729934cSVivien Didelot 
2621ea89098eSAndrew Lunn /* Check if the errata has already been applied. */
2622ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
2623ea89098eSAndrew Lunn {
2624ea89098eSAndrew Lunn 	int port;
2625ea89098eSAndrew Lunn 	int err;
2626ea89098eSAndrew Lunn 	u16 val;
2627ea89098eSAndrew Lunn 
2628ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
262960907013SMarek Behún 		err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val);
2630ea89098eSAndrew Lunn 		if (err) {
2631ea89098eSAndrew Lunn 			dev_err(chip->dev,
2632ea89098eSAndrew Lunn 				"Error reading hidden register: %d\n", err);
2633ea89098eSAndrew Lunn 			return false;
2634ea89098eSAndrew Lunn 		}
2635ea89098eSAndrew Lunn 		if (val != 0x01c0)
2636ea89098eSAndrew Lunn 			return false;
2637ea89098eSAndrew Lunn 	}
2638ea89098eSAndrew Lunn 
2639ea89098eSAndrew Lunn 	return true;
2640ea89098eSAndrew Lunn }
2641ea89098eSAndrew Lunn 
2642ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic
2643ea89098eSAndrew Lunn  * values into undocumented hidden registers and then performing a
2644ea89098eSAndrew Lunn  * software reset.
2645ea89098eSAndrew Lunn  */
2646ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
2647ea89098eSAndrew Lunn {
2648ea89098eSAndrew Lunn 	int port;
2649ea89098eSAndrew Lunn 	int err;
2650ea89098eSAndrew Lunn 
2651ea89098eSAndrew Lunn 	if (mv88e6390_setup_errata_applied(chip))
2652ea89098eSAndrew Lunn 		return 0;
2653ea89098eSAndrew Lunn 
2654ea89098eSAndrew Lunn 	/* Set the ports into blocking mode */
2655ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
2656ea89098eSAndrew Lunn 		err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED);
2657ea89098eSAndrew Lunn 		if (err)
2658ea89098eSAndrew Lunn 			return err;
2659ea89098eSAndrew Lunn 	}
2660ea89098eSAndrew Lunn 
2661ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
266260907013SMarek Behún 		err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0);
2663ea89098eSAndrew Lunn 		if (err)
2664ea89098eSAndrew Lunn 			return err;
2665ea89098eSAndrew Lunn 	}
2666ea89098eSAndrew Lunn 
2667ea89098eSAndrew Lunn 	return mv88e6xxx_software_reset(chip);
2668ea89098eSAndrew Lunn }
2669ea89098eSAndrew Lunn 
267023e8b470SAndrew Lunn enum mv88e6xxx_devlink_param_id {
267123e8b470SAndrew Lunn 	MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
267223e8b470SAndrew Lunn 	MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
267323e8b470SAndrew Lunn };
267423e8b470SAndrew Lunn 
267523e8b470SAndrew Lunn static int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id,
267623e8b470SAndrew Lunn 				       struct devlink_param_gset_ctx *ctx)
267723e8b470SAndrew Lunn {
267823e8b470SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
267923e8b470SAndrew Lunn 	int err;
268023e8b470SAndrew Lunn 
268123e8b470SAndrew Lunn 	mv88e6xxx_reg_lock(chip);
268223e8b470SAndrew Lunn 
268323e8b470SAndrew Lunn 	switch (id) {
268423e8b470SAndrew Lunn 	case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
268523e8b470SAndrew Lunn 		err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8);
268623e8b470SAndrew Lunn 		break;
268723e8b470SAndrew Lunn 	default:
268823e8b470SAndrew Lunn 		err = -EOPNOTSUPP;
268923e8b470SAndrew Lunn 		break;
269023e8b470SAndrew Lunn 	}
269123e8b470SAndrew Lunn 
269223e8b470SAndrew Lunn 	mv88e6xxx_reg_unlock(chip);
269323e8b470SAndrew Lunn 
269423e8b470SAndrew Lunn 	return err;
269523e8b470SAndrew Lunn }
269623e8b470SAndrew Lunn 
269723e8b470SAndrew Lunn static int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id,
269823e8b470SAndrew Lunn 				       struct devlink_param_gset_ctx *ctx)
269923e8b470SAndrew Lunn {
270023e8b470SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
270123e8b470SAndrew Lunn 	int err;
270223e8b470SAndrew Lunn 
270323e8b470SAndrew Lunn 	mv88e6xxx_reg_lock(chip);
270423e8b470SAndrew Lunn 
270523e8b470SAndrew Lunn 	switch (id) {
270623e8b470SAndrew Lunn 	case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
270723e8b470SAndrew Lunn 		err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8);
270823e8b470SAndrew Lunn 		break;
270923e8b470SAndrew Lunn 	default:
271023e8b470SAndrew Lunn 		err = -EOPNOTSUPP;
271123e8b470SAndrew Lunn 		break;
271223e8b470SAndrew Lunn 	}
271323e8b470SAndrew Lunn 
271423e8b470SAndrew Lunn 	mv88e6xxx_reg_unlock(chip);
271523e8b470SAndrew Lunn 
271623e8b470SAndrew Lunn 	return err;
271723e8b470SAndrew Lunn }
271823e8b470SAndrew Lunn 
271923e8b470SAndrew Lunn static const struct devlink_param mv88e6xxx_devlink_params[] = {
272023e8b470SAndrew Lunn 	DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
272123e8b470SAndrew Lunn 				 "ATU_hash", DEVLINK_PARAM_TYPE_U8,
272223e8b470SAndrew Lunn 				 BIT(DEVLINK_PARAM_CMODE_RUNTIME)),
272323e8b470SAndrew Lunn };
272423e8b470SAndrew Lunn 
272523e8b470SAndrew Lunn static int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds)
272623e8b470SAndrew Lunn {
272723e8b470SAndrew Lunn 	return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params,
272823e8b470SAndrew Lunn 					   ARRAY_SIZE(mv88e6xxx_devlink_params));
272923e8b470SAndrew Lunn }
273023e8b470SAndrew Lunn 
273123e8b470SAndrew Lunn static void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds)
273223e8b470SAndrew Lunn {
273323e8b470SAndrew Lunn 	dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params,
273423e8b470SAndrew Lunn 				      ARRAY_SIZE(mv88e6xxx_devlink_params));
273523e8b470SAndrew Lunn }
273623e8b470SAndrew Lunn 
2737e0c69ca7SAndrew Lunn enum mv88e6xxx_devlink_resource_id {
2738e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU,
2739e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
2740e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
2741e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
2742e0c69ca7SAndrew Lunn 	MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
2743e0c69ca7SAndrew Lunn };
2744e0c69ca7SAndrew Lunn 
2745e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip,
2746e0c69ca7SAndrew Lunn 					 u16 bin)
2747e0c69ca7SAndrew Lunn {
2748e0c69ca7SAndrew Lunn 	u16 occupancy = 0;
2749e0c69ca7SAndrew Lunn 	int err;
2750e0c69ca7SAndrew Lunn 
2751e0c69ca7SAndrew Lunn 	mv88e6xxx_reg_lock(chip);
2752e0c69ca7SAndrew Lunn 
2753e0c69ca7SAndrew Lunn 	err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL,
2754e0c69ca7SAndrew Lunn 					 bin);
2755e0c69ca7SAndrew Lunn 	if (err) {
2756e0c69ca7SAndrew Lunn 		dev_err(chip->dev, "failed to set ATU stats kind/bin\n");
2757e0c69ca7SAndrew Lunn 		goto unlock;
2758e0c69ca7SAndrew Lunn 	}
2759e0c69ca7SAndrew Lunn 
2760e0c69ca7SAndrew Lunn 	err = mv88e6xxx_g1_atu_get_next(chip, 0);
2761e0c69ca7SAndrew Lunn 	if (err) {
2762e0c69ca7SAndrew Lunn 		dev_err(chip->dev, "failed to perform ATU get next\n");
2763e0c69ca7SAndrew Lunn 		goto unlock;
2764e0c69ca7SAndrew Lunn 	}
2765e0c69ca7SAndrew Lunn 
2766e0c69ca7SAndrew Lunn 	err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy);
2767e0c69ca7SAndrew Lunn 	if (err) {
2768e0c69ca7SAndrew Lunn 		dev_err(chip->dev, "failed to get ATU stats\n");
2769e0c69ca7SAndrew Lunn 		goto unlock;
2770e0c69ca7SAndrew Lunn 	}
2771e0c69ca7SAndrew Lunn 
2772e0c69ca7SAndrew Lunn unlock:
2773e0c69ca7SAndrew Lunn 	mv88e6xxx_reg_unlock(chip);
2774e0c69ca7SAndrew Lunn 
2775e0c69ca7SAndrew Lunn 	return occupancy;
2776e0c69ca7SAndrew Lunn }
2777e0c69ca7SAndrew Lunn 
2778e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv)
2779e0c69ca7SAndrew Lunn {
2780e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = priv;
2781e0c69ca7SAndrew Lunn 
2782e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_get(chip,
2783e0c69ca7SAndrew Lunn 					     MV88E6XXX_G2_ATU_STATS_BIN_0);
2784e0c69ca7SAndrew Lunn }
2785e0c69ca7SAndrew Lunn 
2786e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv)
2787e0c69ca7SAndrew Lunn {
2788e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = priv;
2789e0c69ca7SAndrew Lunn 
2790e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_get(chip,
2791e0c69ca7SAndrew Lunn 					     MV88E6XXX_G2_ATU_STATS_BIN_1);
2792e0c69ca7SAndrew Lunn }
2793e0c69ca7SAndrew Lunn 
2794e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv)
2795e0c69ca7SAndrew Lunn {
2796e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = priv;
2797e0c69ca7SAndrew Lunn 
2798e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_get(chip,
2799e0c69ca7SAndrew Lunn 					     MV88E6XXX_G2_ATU_STATS_BIN_2);
2800e0c69ca7SAndrew Lunn }
2801e0c69ca7SAndrew Lunn 
2802e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv)
2803e0c69ca7SAndrew Lunn {
2804e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = priv;
2805e0c69ca7SAndrew Lunn 
2806e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_get(chip,
2807e0c69ca7SAndrew Lunn 					     MV88E6XXX_G2_ATU_STATS_BIN_3);
2808e0c69ca7SAndrew Lunn }
2809e0c69ca7SAndrew Lunn 
2810e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_get(void *priv)
2811e0c69ca7SAndrew Lunn {
2812e0c69ca7SAndrew Lunn 	return mv88e6xxx_devlink_atu_bin_0_get(priv) +
2813e0c69ca7SAndrew Lunn 		mv88e6xxx_devlink_atu_bin_1_get(priv) +
2814e0c69ca7SAndrew Lunn 		mv88e6xxx_devlink_atu_bin_2_get(priv) +
2815e0c69ca7SAndrew Lunn 		mv88e6xxx_devlink_atu_bin_3_get(priv);
2816e0c69ca7SAndrew Lunn }
2817e0c69ca7SAndrew Lunn 
2818e0c69ca7SAndrew Lunn static int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds)
2819e0c69ca7SAndrew Lunn {
2820e0c69ca7SAndrew Lunn 	struct devlink_resource_size_params size_params;
2821e0c69ca7SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
2822e0c69ca7SAndrew Lunn 	int err;
2823e0c69ca7SAndrew Lunn 
2824e0c69ca7SAndrew Lunn 	devlink_resource_size_params_init(&size_params,
2825e0c69ca7SAndrew Lunn 					  mv88e6xxx_num_macs(chip),
2826e0c69ca7SAndrew Lunn 					  mv88e6xxx_num_macs(chip),
2827e0c69ca7SAndrew Lunn 					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
2828e0c69ca7SAndrew Lunn 
2829e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU",
2830e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip),
2831e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2832e0c69ca7SAndrew Lunn 					    DEVLINK_RESOURCE_ID_PARENT_TOP,
2833e0c69ca7SAndrew Lunn 					    &size_params);
2834e0c69ca7SAndrew Lunn 	if (err)
2835e0c69ca7SAndrew Lunn 		goto out;
2836e0c69ca7SAndrew Lunn 
2837e0c69ca7SAndrew Lunn 	devlink_resource_size_params_init(&size_params,
2838e0c69ca7SAndrew Lunn 					  mv88e6xxx_num_macs(chip) / 4,
2839e0c69ca7SAndrew Lunn 					  mv88e6xxx_num_macs(chip) / 4,
2840e0c69ca7SAndrew Lunn 					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
2841e0c69ca7SAndrew Lunn 
2842e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU_bin_0",
2843e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip) / 4,
2844e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
2845e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2846e0c69ca7SAndrew Lunn 					    &size_params);
2847e0c69ca7SAndrew Lunn 	if (err)
2848e0c69ca7SAndrew Lunn 		goto out;
2849e0c69ca7SAndrew Lunn 
2850e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU_bin_1",
2851e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip) / 4,
2852e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
2853e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2854e0c69ca7SAndrew Lunn 					    &size_params);
2855e0c69ca7SAndrew Lunn 	if (err)
2856e0c69ca7SAndrew Lunn 		goto out;
2857e0c69ca7SAndrew Lunn 
2858e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU_bin_2",
2859e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip) / 4,
2860e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
2861e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2862e0c69ca7SAndrew Lunn 					    &size_params);
2863e0c69ca7SAndrew Lunn 	if (err)
2864e0c69ca7SAndrew Lunn 		goto out;
2865e0c69ca7SAndrew Lunn 
2866e0c69ca7SAndrew Lunn 	err = dsa_devlink_resource_register(ds, "ATU_bin_3",
2867e0c69ca7SAndrew Lunn 					    mv88e6xxx_num_macs(chip) / 4,
2868e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
2869e0c69ca7SAndrew Lunn 					    MV88E6XXX_RESOURCE_ID_ATU,
2870e0c69ca7SAndrew Lunn 					    &size_params);
2871e0c69ca7SAndrew Lunn 	if (err)
2872e0c69ca7SAndrew Lunn 		goto out;
2873e0c69ca7SAndrew Lunn 
2874e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
2875e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU,
2876e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_get,
2877e0c69ca7SAndrew Lunn 					      chip);
2878e0c69ca7SAndrew Lunn 
2879e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
2880e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
2881e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_bin_0_get,
2882e0c69ca7SAndrew Lunn 					      chip);
2883e0c69ca7SAndrew Lunn 
2884e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
2885e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
2886e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_bin_1_get,
2887e0c69ca7SAndrew Lunn 					      chip);
2888e0c69ca7SAndrew Lunn 
2889e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
2890e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
2891e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_bin_2_get,
2892e0c69ca7SAndrew Lunn 					      chip);
2893e0c69ca7SAndrew Lunn 
2894e0c69ca7SAndrew Lunn 	dsa_devlink_resource_occ_get_register(ds,
2895e0c69ca7SAndrew Lunn 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
2896e0c69ca7SAndrew Lunn 					      mv88e6xxx_devlink_atu_bin_3_get,
2897e0c69ca7SAndrew Lunn 					      chip);
2898e0c69ca7SAndrew Lunn 
2899e0c69ca7SAndrew Lunn 	return 0;
2900e0c69ca7SAndrew Lunn 
2901e0c69ca7SAndrew Lunn out:
2902e0c69ca7SAndrew Lunn 	dsa_devlink_resources_unregister(ds);
2903e0c69ca7SAndrew Lunn 	return err;
2904e0c69ca7SAndrew Lunn }
2905e0c69ca7SAndrew Lunn 
290623e8b470SAndrew Lunn static void mv88e6xxx_teardown(struct dsa_switch *ds)
290723e8b470SAndrew Lunn {
290823e8b470SAndrew Lunn 	mv88e6xxx_teardown_devlink_params(ds);
2909e0c69ca7SAndrew Lunn 	dsa_devlink_resources_unregister(ds);
291023e8b470SAndrew Lunn }
291123e8b470SAndrew Lunn 
2912fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds)
2913fad09c73SVivien Didelot {
291404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
29152d2e1dd2SAndrew Lunn 	u8 cmode;
2916fad09c73SVivien Didelot 	int err;
2917fad09c73SVivien Didelot 	int i;
2918fad09c73SVivien Didelot 
2919fad09c73SVivien Didelot 	chip->ds = ds;
2920a3c53be5SAndrew Lunn 	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
2921fad09c73SVivien Didelot 
2922c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2923fad09c73SVivien Didelot 
2924ea89098eSAndrew Lunn 	if (chip->info->ops->setup_errata) {
2925ea89098eSAndrew Lunn 		err = chip->info->ops->setup_errata(chip);
2926ea89098eSAndrew Lunn 		if (err)
2927ea89098eSAndrew Lunn 			goto unlock;
2928ea89098eSAndrew Lunn 	}
2929ea89098eSAndrew Lunn 
29302d2e1dd2SAndrew Lunn 	/* Cache the cmode of each port. */
29312d2e1dd2SAndrew Lunn 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
29322d2e1dd2SAndrew Lunn 		if (chip->info->ops->port_get_cmode) {
29332d2e1dd2SAndrew Lunn 			err = chip->info->ops->port_get_cmode(chip, i, &cmode);
29342d2e1dd2SAndrew Lunn 			if (err)
2935e29129fcSDan Carpenter 				goto unlock;
29362d2e1dd2SAndrew Lunn 
29372d2e1dd2SAndrew Lunn 			chip->ports[i].cmode = cmode;
29382d2e1dd2SAndrew Lunn 		}
29392d2e1dd2SAndrew Lunn 	}
29402d2e1dd2SAndrew Lunn 
29419729934cSVivien Didelot 	/* Setup Switch Port Registers */
2942370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2943b759f528SVivien Didelot 		if (dsa_is_unused_port(ds, i))
2944b759f528SVivien Didelot 			continue;
2945b759f528SVivien Didelot 
2946c857486aSHubert Feurstein 		/* Prevent the use of an invalid port. */
2947b759f528SVivien Didelot 		if (mv88e6xxx_is_invalid_port(chip, i)) {
2948c857486aSHubert Feurstein 			dev_err(chip->dev, "port %d is invalid\n", i);
2949c857486aSHubert Feurstein 			err = -EINVAL;
2950c857486aSHubert Feurstein 			goto unlock;
2951c857486aSHubert Feurstein 		}
2952c857486aSHubert Feurstein 
29539729934cSVivien Didelot 		err = mv88e6xxx_setup_port(chip, i);
29549729934cSVivien Didelot 		if (err)
29559729934cSVivien Didelot 			goto unlock;
29569729934cSVivien Didelot 	}
29579729934cSVivien Didelot 
2958cd8da8bbSVivien Didelot 	err = mv88e6xxx_irl_setup(chip);
2959cd8da8bbSVivien Didelot 	if (err)
2960cd8da8bbSVivien Didelot 		goto unlock;
2961cd8da8bbSVivien Didelot 
296204a69a17SVivien Didelot 	err = mv88e6xxx_mac_setup(chip);
296304a69a17SVivien Didelot 	if (err)
296404a69a17SVivien Didelot 		goto unlock;
296504a69a17SVivien Didelot 
29661b17aedfSVivien Didelot 	err = mv88e6xxx_phy_setup(chip);
29671b17aedfSVivien Didelot 	if (err)
29681b17aedfSVivien Didelot 		goto unlock;
29691b17aedfSVivien Didelot 
2970b486d7c9SVivien Didelot 	err = mv88e6xxx_vtu_setup(chip);
2971b486d7c9SVivien Didelot 	if (err)
2972b486d7c9SVivien Didelot 		goto unlock;
2973b486d7c9SVivien Didelot 
297481228996SVivien Didelot 	err = mv88e6xxx_pvt_setup(chip);
297581228996SVivien Didelot 	if (err)
297681228996SVivien Didelot 		goto unlock;
297781228996SVivien Didelot 
2978a2ac29d2SVivien Didelot 	err = mv88e6xxx_atu_setup(chip);
2979a2ac29d2SVivien Didelot 	if (err)
2980a2ac29d2SVivien Didelot 		goto unlock;
2981a2ac29d2SVivien Didelot 
298287fa886eSAndrew Lunn 	err = mv88e6xxx_broadcast_setup(chip, 0);
298387fa886eSAndrew Lunn 	if (err)
298487fa886eSAndrew Lunn 		goto unlock;
298587fa886eSAndrew Lunn 
29869e907d73SVivien Didelot 	err = mv88e6xxx_pot_setup(chip);
29879e907d73SVivien Didelot 	if (err)
29889e907d73SVivien Didelot 		goto unlock;
29899e907d73SVivien Didelot 
29909e5baf9bSVivien Didelot 	err = mv88e6xxx_rmu_setup(chip);
29919e5baf9bSVivien Didelot 	if (err)
29929e5baf9bSVivien Didelot 		goto unlock;
29939e5baf9bSVivien Didelot 
299451c901a7SVivien Didelot 	err = mv88e6xxx_rsvd2cpu_setup(chip);
29956e55f698SAndrew Lunn 	if (err)
29966e55f698SAndrew Lunn 		goto unlock;
29976e55f698SAndrew Lunn 
2998b28f872dSVivien Didelot 	err = mv88e6xxx_trunk_setup(chip);
2999b28f872dSVivien Didelot 	if (err)
3000b28f872dSVivien Didelot 		goto unlock;
3001b28f872dSVivien Didelot 
3002c7f047b6SVivien Didelot 	err = mv88e6xxx_devmap_setup(chip);
3003c7f047b6SVivien Didelot 	if (err)
3004c7f047b6SVivien Didelot 		goto unlock;
3005c7f047b6SVivien Didelot 
300693e18d61SVivien Didelot 	err = mv88e6xxx_pri_setup(chip);
300793e18d61SVivien Didelot 	if (err)
300893e18d61SVivien Didelot 		goto unlock;
300993e18d61SVivien Didelot 
3010c6fe0ad2SBrandon Streiff 	/* Setup PTP Hardware Clock and timestamping */
30112fa8d3afSBrandon Streiff 	if (chip->info->ptp_support) {
30122fa8d3afSBrandon Streiff 		err = mv88e6xxx_ptp_setup(chip);
30132fa8d3afSBrandon Streiff 		if (err)
30142fa8d3afSBrandon Streiff 			goto unlock;
3015c6fe0ad2SBrandon Streiff 
3016c6fe0ad2SBrandon Streiff 		err = mv88e6xxx_hwtstamp_setup(chip);
3017c6fe0ad2SBrandon Streiff 		if (err)
3018c6fe0ad2SBrandon Streiff 			goto unlock;
30192fa8d3afSBrandon Streiff 	}
30202fa8d3afSBrandon Streiff 
3021447b1bb8SVivien Didelot 	err = mv88e6xxx_stats_setup(chip);
3022447b1bb8SVivien Didelot 	if (err)
3023447b1bb8SVivien Didelot 		goto unlock;
3024447b1bb8SVivien Didelot 
3025fad09c73SVivien Didelot unlock:
3026c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3027fad09c73SVivien Didelot 
3028e0c69ca7SAndrew Lunn 	if (err)
3029e0c69ca7SAndrew Lunn 		return err;
3030e0c69ca7SAndrew Lunn 
3031e0c69ca7SAndrew Lunn 	/* Have to be called without holding the register lock, since
3032e0c69ca7SAndrew Lunn 	 * they take the devlink lock, and we later take the locks in
3033e0c69ca7SAndrew Lunn 	 * the reverse order when getting/setting parameters or
3034e0c69ca7SAndrew Lunn 	 * resource occupancy.
303523e8b470SAndrew Lunn 	 */
3036e0c69ca7SAndrew Lunn 	err = mv88e6xxx_setup_devlink_resources(ds);
3037e0c69ca7SAndrew Lunn 	if (err)
3038e0c69ca7SAndrew Lunn 		return err;
3039e0c69ca7SAndrew Lunn 
3040e0c69ca7SAndrew Lunn 	err = mv88e6xxx_setup_devlink_params(ds);
3041e0c69ca7SAndrew Lunn 	if (err)
3042e0c69ca7SAndrew Lunn 		dsa_devlink_resources_unregister(ds);
3043e0c69ca7SAndrew Lunn 
3044e0c69ca7SAndrew Lunn 	return err;
3045fad09c73SVivien Didelot }
3046fad09c73SVivien Didelot 
3047e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
3048fad09c73SVivien Didelot {
30490dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
30500dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
3051e57e5e77SVivien Didelot 	u16 val;
3052e57e5e77SVivien Didelot 	int err;
3053fad09c73SVivien Didelot 
3054ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_read)
3055ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
3056ee26a228SAndrew Lunn 
3057c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3058ee26a228SAndrew Lunn 	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
3059c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3060e57e5e77SVivien Didelot 
3061da9f3301SAndrew Lunn 	if (reg == MII_PHYSID2) {
3062ddc49acbSAndrew Lunn 		/* Some internal PHYs don't have a model number. */
3063ddc49acbSAndrew Lunn 		if (chip->info->family != MV88E6XXX_FAMILY_6165)
3064ddc49acbSAndrew Lunn 			/* Then there is the 6165 family. It gets is
3065ddc49acbSAndrew Lunn 			 * PHYs correct. But it can also have two
3066ddc49acbSAndrew Lunn 			 * SERDES interfaces in the PHY address
3067ddc49acbSAndrew Lunn 			 * space. And these don't have a model
3068ddc49acbSAndrew Lunn 			 * number. But they are not PHYs, so we don't
3069ddc49acbSAndrew Lunn 			 * want to give them something a PHY driver
3070ddc49acbSAndrew Lunn 			 * will recognise.
3071ddc49acbSAndrew Lunn 			 *
3072ddc49acbSAndrew Lunn 			 * Use the mv88e6390 family model number
3073ddc49acbSAndrew Lunn 			 * instead, for anything which really could be
3074ddc49acbSAndrew Lunn 			 * a PHY,
3075da9f3301SAndrew Lunn 			 */
3076da9f3301SAndrew Lunn 			if (!(val & 0x3f0))
3077107fcc10SVivien Didelot 				val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4;
3078da9f3301SAndrew Lunn 	}
3079da9f3301SAndrew Lunn 
3080e57e5e77SVivien Didelot 	return err ? err : val;
3081fad09c73SVivien Didelot }
3082fad09c73SVivien Didelot 
3083e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
3084fad09c73SVivien Didelot {
30850dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
30860dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
3087e57e5e77SVivien Didelot 	int err;
3088fad09c73SVivien Didelot 
3089ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_write)
3090ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
3091ee26a228SAndrew Lunn 
3092c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3093ee26a228SAndrew Lunn 	err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
3094c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3095e57e5e77SVivien Didelot 
3096e57e5e77SVivien Didelot 	return err;
3097fad09c73SVivien Didelot }
3098fad09c73SVivien Didelot 
3099fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
3100a3c53be5SAndrew Lunn 				   struct device_node *np,
3101a3c53be5SAndrew Lunn 				   bool external)
3102fad09c73SVivien Didelot {
3103fad09c73SVivien Didelot 	static int index;
31040dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
3105fad09c73SVivien Didelot 	struct mii_bus *bus;
3106fad09c73SVivien Didelot 	int err;
3107fad09c73SVivien Didelot 
31082510babcSAndrew Lunn 	if (external) {
3109c9acece0SRasmus Villemoes 		mv88e6xxx_reg_lock(chip);
31102510babcSAndrew Lunn 		err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
3111c9acece0SRasmus Villemoes 		mv88e6xxx_reg_unlock(chip);
31122510babcSAndrew Lunn 
31132510babcSAndrew Lunn 		if (err)
31142510babcSAndrew Lunn 			return err;
31152510babcSAndrew Lunn 	}
31162510babcSAndrew Lunn 
31170dd12d54SAndrew Lunn 	bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
3118fad09c73SVivien Didelot 	if (!bus)
3119fad09c73SVivien Didelot 		return -ENOMEM;
3120fad09c73SVivien Didelot 
31210dd12d54SAndrew Lunn 	mdio_bus = bus->priv;
3122a3c53be5SAndrew Lunn 	mdio_bus->bus = bus;
31230dd12d54SAndrew Lunn 	mdio_bus->chip = chip;
3124a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&mdio_bus->list);
3125a3c53be5SAndrew Lunn 	mdio_bus->external = external;
31260dd12d54SAndrew Lunn 
3127fad09c73SVivien Didelot 	if (np) {
3128fad09c73SVivien Didelot 		bus->name = np->full_name;
3129f7ce9103SRob Herring 		snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np);
3130fad09c73SVivien Didelot 	} else {
3131fad09c73SVivien Didelot 		bus->name = "mv88e6xxx SMI";
3132fad09c73SVivien Didelot 		snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
3133fad09c73SVivien Didelot 	}
3134fad09c73SVivien Didelot 
3135fad09c73SVivien Didelot 	bus->read = mv88e6xxx_mdio_read;
3136fad09c73SVivien Didelot 	bus->write = mv88e6xxx_mdio_write;
3137fad09c73SVivien Didelot 	bus->parent = chip->dev;
3138fad09c73SVivien Didelot 
31396f88284fSAndrew Lunn 	if (!external) {
31406f88284fSAndrew Lunn 		err = mv88e6xxx_g2_irq_mdio_setup(chip, bus);
31416f88284fSAndrew Lunn 		if (err)
31426f88284fSAndrew Lunn 			return err;
31436f88284fSAndrew Lunn 	}
31446f88284fSAndrew Lunn 
3145a3c53be5SAndrew Lunn 	err = of_mdiobus_register(bus, np);
3146fad09c73SVivien Didelot 	if (err) {
3147fad09c73SVivien Didelot 		dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
31486f88284fSAndrew Lunn 		mv88e6xxx_g2_irq_mdio_free(chip, bus);
3149fad09c73SVivien Didelot 		return err;
3150fad09c73SVivien Didelot 	}
3151fad09c73SVivien Didelot 
3152a3c53be5SAndrew Lunn 	if (external)
3153a3c53be5SAndrew Lunn 		list_add_tail(&mdio_bus->list, &chip->mdios);
3154a3c53be5SAndrew Lunn 	else
3155a3c53be5SAndrew Lunn 		list_add(&mdio_bus->list, &chip->mdios);
3156a3c53be5SAndrew Lunn 
3157a3c53be5SAndrew Lunn 	return 0;
3158a3c53be5SAndrew Lunn }
3159a3c53be5SAndrew Lunn 
3160a3c53be5SAndrew Lunn static const struct of_device_id mv88e6xxx_mdio_external_match[] = {
3161a3c53be5SAndrew Lunn 	{ .compatible = "marvell,mv88e6xxx-mdio-external",
3162a3c53be5SAndrew Lunn 	  .data = (void *)true },
3163a3c53be5SAndrew Lunn 	{ },
3164a3c53be5SAndrew Lunn };
3165a3c53be5SAndrew Lunn 
31663126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
31673126aeecSAndrew Lunn 
31683126aeecSAndrew Lunn {
31693126aeecSAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
31703126aeecSAndrew Lunn 	struct mii_bus *bus;
31713126aeecSAndrew Lunn 
31723126aeecSAndrew Lunn 	list_for_each_entry(mdio_bus, &chip->mdios, list) {
31733126aeecSAndrew Lunn 		bus = mdio_bus->bus;
31743126aeecSAndrew Lunn 
31756f88284fSAndrew Lunn 		if (!mdio_bus->external)
31766f88284fSAndrew Lunn 			mv88e6xxx_g2_irq_mdio_free(chip, bus);
31776f88284fSAndrew Lunn 
31783126aeecSAndrew Lunn 		mdiobus_unregister(bus);
31793126aeecSAndrew Lunn 	}
31803126aeecSAndrew Lunn }
31813126aeecSAndrew Lunn 
3182a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
3183a3c53be5SAndrew Lunn 				    struct device_node *np)
3184a3c53be5SAndrew Lunn {
3185a3c53be5SAndrew Lunn 	const struct of_device_id *match;
3186a3c53be5SAndrew Lunn 	struct device_node *child;
3187a3c53be5SAndrew Lunn 	int err;
3188a3c53be5SAndrew Lunn 
3189a3c53be5SAndrew Lunn 	/* Always register one mdio bus for the internal/default mdio
3190a3c53be5SAndrew Lunn 	 * bus. This maybe represented in the device tree, but is
3191a3c53be5SAndrew Lunn 	 * optional.
3192a3c53be5SAndrew Lunn 	 */
3193a3c53be5SAndrew Lunn 	child = of_get_child_by_name(np, "mdio");
3194a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdio_register(chip, child, false);
3195a3c53be5SAndrew Lunn 	if (err)
3196a3c53be5SAndrew Lunn 		return err;
3197a3c53be5SAndrew Lunn 
3198a3c53be5SAndrew Lunn 	/* Walk the device tree, and see if there are any other nodes
3199a3c53be5SAndrew Lunn 	 * which say they are compatible with the external mdio
3200a3c53be5SAndrew Lunn 	 * bus.
3201a3c53be5SAndrew Lunn 	 */
3202a3c53be5SAndrew Lunn 	for_each_available_child_of_node(np, child) {
3203a3c53be5SAndrew Lunn 		match = of_match_node(mv88e6xxx_mdio_external_match, child);
3204a3c53be5SAndrew Lunn 		if (match) {
3205a3c53be5SAndrew Lunn 			err = mv88e6xxx_mdio_register(chip, child, true);
32063126aeecSAndrew Lunn 			if (err) {
32073126aeecSAndrew Lunn 				mv88e6xxx_mdios_unregister(chip);
320878e42040SNishka Dasgupta 				of_node_put(child);
3209a3c53be5SAndrew Lunn 				return err;
3210a3c53be5SAndrew Lunn 			}
3211a3c53be5SAndrew Lunn 		}
32123126aeecSAndrew Lunn 	}
3213a3c53be5SAndrew Lunn 
3214a3c53be5SAndrew Lunn 	return 0;
3215a3c53be5SAndrew Lunn }
3216a3c53be5SAndrew Lunn 
3217855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
3218855b1932SVivien Didelot {
321904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3220855b1932SVivien Didelot 
3221855b1932SVivien Didelot 	return chip->eeprom_len;
3222855b1932SVivien Didelot }
3223855b1932SVivien Didelot 
3224855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
3225855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
3226855b1932SVivien Didelot {
322704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3228855b1932SVivien Didelot 	int err;
3229855b1932SVivien Didelot 
3230ee4dc2e7SVivien Didelot 	if (!chip->info->ops->get_eeprom)
3231ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
3232ee4dc2e7SVivien Didelot 
3233c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3234ee4dc2e7SVivien Didelot 	err = chip->info->ops->get_eeprom(chip, eeprom, data);
3235c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3236855b1932SVivien Didelot 
3237855b1932SVivien Didelot 	if (err)
3238855b1932SVivien Didelot 		return err;
3239855b1932SVivien Didelot 
3240855b1932SVivien Didelot 	eeprom->magic = 0xc3ec4951;
3241855b1932SVivien Didelot 
3242855b1932SVivien Didelot 	return 0;
3243855b1932SVivien Didelot }
3244855b1932SVivien Didelot 
3245855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
3246855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
3247855b1932SVivien Didelot {
324804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3249855b1932SVivien Didelot 	int err;
3250855b1932SVivien Didelot 
3251ee4dc2e7SVivien Didelot 	if (!chip->info->ops->set_eeprom)
3252ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
3253ee4dc2e7SVivien Didelot 
3254855b1932SVivien Didelot 	if (eeprom->magic != 0xc3ec4951)
3255855b1932SVivien Didelot 		return -EINVAL;
3256855b1932SVivien Didelot 
3257c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3258ee4dc2e7SVivien Didelot 	err = chip->info->ops->set_eeprom(chip, eeprom, data);
3259c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3260855b1932SVivien Didelot 
3261855b1932SVivien Didelot 	return err;
3262855b1932SVivien Didelot }
3263855b1932SVivien Didelot 
3264b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = {
32654b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6097 */
326693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
326793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3268cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3269b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
32707e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
32717e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
327208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
32737f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
327496a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3275ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
327656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3277601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
327856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3279ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
32800898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3281c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
32829dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
32836c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
32842d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3285121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3286a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
328740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3288dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3289dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3290052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3291fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3292fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3293fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
329451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
32959e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
3296a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3297a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
329817e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
32999e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
3300f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
33010ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
33026c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3303b3469dd8SVivien Didelot };
3304b3469dd8SVivien Didelot 
3305b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = {
33064b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6095 */
330793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
330893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3309b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
33107e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
33117e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
331208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
33137f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
331496a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
331556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3316601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
3317a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
33186c422e34SRussell King 	.port_link_state = mv88e6185_port_link_state,
33192d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3320121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3321a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
332240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3323dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3324dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3325052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
332651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3327a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3328a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
332917e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3330f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
33310ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
33326c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3333b3469dd8SVivien Didelot };
3334b3469dd8SVivien Didelot 
33357d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = {
333615da3cc8SStefan Eichenberger 	/* MV88E6XXX_FAMILY_6097 */
333793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
333893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3339cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
33407d381a02SStefan Eichenberger 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
33417d381a02SStefan Eichenberger 	.phy_read = mv88e6xxx_g2_smi_phy_read,
33427d381a02SStefan Eichenberger 	.phy_write = mv88e6xxx_g2_smi_phy_write,
33437d381a02SStefan Eichenberger 	.port_set_link = mv88e6xxx_port_set_link,
33447d381a02SStefan Eichenberger 	.port_set_duplex = mv88e6xxx_port_set_duplex,
33457d381a02SStefan Eichenberger 	.port_set_speed = mv88e6185_port_set_speed,
3346ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
334756995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3348601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
334956995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3350cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3351ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
33520898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3353c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
33549dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
33556c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
33562d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3357121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
33587d381a02SStefan Eichenberger 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
335940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
33607d381a02SStefan Eichenberger 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
33617d381a02SStefan Eichenberger 	.stats_get_strings = mv88e6095_stats_get_strings,
33627d381a02SStefan Eichenberger 	.stats_get_stats = mv88e6095_stats_get_stats,
3363fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3364fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
336591eaa475SVolodymyr Bendiuga 	.watchdog_ops = &mv88e6097_watchdog_ops,
336651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
33679e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
336817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
33699e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
3370f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
33710ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
33726c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
33737d381a02SStefan Eichenberger };
33747d381a02SStefan Eichenberger 
3375b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = {
33764b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
337793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
337893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3379cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3380b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3381ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3382ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
338308ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
33847f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
338596a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
338656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3387601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3388c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
33899dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
33906c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
33912d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3392121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
33930ac64c39SAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
339440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3395dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3396dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3397052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3398fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3399fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3400fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
340151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
34029e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
340317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
340423e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
340523e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3406f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
34070ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
34086c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3409b3469dd8SVivien Didelot };
3410b3469dd8SVivien Didelot 
3411b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = {
34124b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
341393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
341493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3415b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
34167e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
34177e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
341808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
34197f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
342096a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3421ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
342256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3423601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
342456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3425a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
3426cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3427ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
34280898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
342954186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
34306c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
34312d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3432121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3433a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
343440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3435dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3436dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3437052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3438fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3439fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3440fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
344151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3442a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
344302317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3444a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
344517e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3446f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
34470ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
34486c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3449b3469dd8SVivien Didelot };
3450b3469dd8SVivien Didelot 
3451990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = {
3452990e27b0SVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
345393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
345493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3455cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3456990e27b0SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
3457990e27b0SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3458990e27b0SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3459990e27b0SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3460990e27b0SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
3461990e27b0SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3462990e27b0SVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3463990e27b0SVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
346426422340SMarek Behún 	.port_set_speed = mv88e6341_port_set_speed,
34657cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
3466990e27b0SVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
3467990e27b0SVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3468990e27b0SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3469990e27b0SVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3470cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3471990e27b0SVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
34720898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3473990e27b0SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3474990e27b0SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34756c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
34762d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
34777a3007d2SMarek Behún 	.port_set_cmode = mv88e6341_port_set_cmode,
3478121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3479990e27b0SVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
348040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3481990e27b0SVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3482990e27b0SVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
3483990e27b0SVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
3484fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3485fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
3486990e27b0SVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
3487990e27b0SVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
34889e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
3489990e27b0SVivien Didelot 	.reset = mv88e6352_g1_reset,
3490f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
34910ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3492d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
3493d3cf7d8fSMarek Behún 	.serdes_get_lane = mv88e6341_serdes_get_lane,
34944241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
349561a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3496907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
3497a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
3498e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
3499990e27b0SVivien Didelot };
3500990e27b0SVivien Didelot 
3501b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = {
35024b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
350393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
350493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3505cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3506b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3507ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3508ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
350908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
35107f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
351196a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3512ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
351356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3514601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
351556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3516cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3517ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
35180898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3519c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
35209dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35216c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
35222d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3523121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3524a6da21bbSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
352540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3526dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3527dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3528052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3529fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3530fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3531fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
353251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
35339e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
353417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
353523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
353623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3537f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
35380ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3539a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3540dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
35416c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3542b3469dd8SVivien Didelot };
3543b3469dd8SVivien Didelot 
3544b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = {
35454b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
354693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
354793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3548cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3549b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3550efb3e74dSAndrew Lunn 	.phy_read = mv88e6165_phy_read,
3551efb3e74dSAndrew Lunn 	.phy_write = mv88e6165_phy_write,
355208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
35537f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
355496a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3555c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
35569dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35576c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
35582d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3559121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3560a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
356140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3562dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3563dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3564052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3565fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3566fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3567fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
356851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
35699e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
357017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
357123e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
357223e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3573f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
35740ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3575a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3576dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
35776c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3578b3469dd8SVivien Didelot };
3579b3469dd8SVivien Didelot 
3580b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = {
35814b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
358293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
358393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3584cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3585b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3586b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3587b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
358808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
35897f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
359094d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
359196a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3592ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
359356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3594601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
359556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3596cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3597ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
35980898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3599c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36009dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36016c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
36022d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3603121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3604a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
360540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3606dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3607dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3608052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3609fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3610fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3611fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
361251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
36139e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
361417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
361523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
361623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3617f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
36180ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
36196c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3620b3469dd8SVivien Didelot };
3621b3469dd8SVivien Didelot 
3622b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = {
36234b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
362493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
362593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3626cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3627ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3628ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3629b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3630b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3631b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
363208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
36337f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3634a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
363596a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3636ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
3637f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
363856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3639601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
364056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3641cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3642ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36430898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3644c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36459dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36466c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
36472d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3648121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3649a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
365040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3651dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3652dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3653052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3654fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3655fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3656fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
365751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
36589e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
365917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
36609e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
366123e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
366223e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3663f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
36640ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
36659db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
36666d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
3667a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
36686c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3669b3469dd8SVivien Didelot };
3670b3469dd8SVivien Didelot 
3671b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = {
36724b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
367393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
367493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3675cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3676b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3677b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3678b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
367908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
36807f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
368194d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
368296a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3683ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
368456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3685601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
368656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3687cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3688ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36890898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3690c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36919dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36926c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
36932d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3694121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3695a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
369640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3697dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3698dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3699052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3700fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3701fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3702fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
370351c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
37049e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
370517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
370623e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
370723e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3708f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37090ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37106c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3711b3469dd8SVivien Didelot };
3712b3469dd8SVivien Didelot 
3713b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = {
37144b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
371593e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
371693e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3717cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3718ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3719ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3720b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3721b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3722b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
372308ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
37247f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3725a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
372696a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3727ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
3728f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
372956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3730601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
373156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3732cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3733ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37340898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3735c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
37369dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37376c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
37382d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3739121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3740a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
374140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3742dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3743dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3744052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3745fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3746fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3747fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
374851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
37499e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
375017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
37519e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
375223e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
375323e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3754f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37550ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37569db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
37576d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
37584241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
375961a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
3760907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
3761a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
37626c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3763b3469dd8SVivien Didelot };
3764b3469dd8SVivien Didelot 
3765b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = {
37664b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
376793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
376893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3769b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
37707e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
37717e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
377208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
37737f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
377496a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
377556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3776601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
3777ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
3778a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
377954186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
37806c422e34SRussell King 	.port_link_state = mv88e6185_port_link_state,
37812d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3782121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3783a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
378440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3785dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3786dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3787052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3788fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3789fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3790fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
379151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
379202317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3793a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3794a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
379517e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3796f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
37970ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
37986c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3799b3469dd8SVivien Didelot };
3800b3469dd8SVivien Didelot 
38011a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = {
38024b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3803ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3804cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
380598fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
380698fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
38071a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
38081a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
38091a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
38101a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
38111a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
38121a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
38131a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
38147cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
3815ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
3816f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
381756995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3818601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
381956995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
38200898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3821c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38229dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38236c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
38242d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3825fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
3826121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
382779523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3828de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3829dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3830dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3831e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3832fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3833fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
383461303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
38356e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
38369e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
383717e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
38389e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
383923e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
384023e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3841931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3842931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
38436335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
384417deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
38454241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
384661a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3847907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
3848a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
38496c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
38501a3b39ecSAndrew Lunn };
38511a3b39ecSAndrew Lunn 
38521a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = {
38534b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3854ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3855cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
385698fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
385798fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
38581a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
38591a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
38601a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
38611a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
38621a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
38631a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
38641a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390x_port_set_speed,
38657cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
3866ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
3867f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
386856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3869601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
387056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
38710898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3872c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38739dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38746c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
38752d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3876fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
3877121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
387879523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3879de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3880dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3881dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3882e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3883fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3884fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
388561303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
38866e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
38879e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
388817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
38899e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
389023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
389123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3892931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3893931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
3894d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
389517deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390x_serdes_get_lane,
38964241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
389761a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3898907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
3899a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
39006c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
39011a3b39ecSAndrew Lunn };
39021a3b39ecSAndrew Lunn 
39031a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = {
39044b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3905ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3906cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
390798fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
390898fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
39091a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
39101a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
39111a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
39121a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
39131a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
39141a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
39151a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
39167cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
3917ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
391856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3919601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
392056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
39210898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3922c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
39239dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
39246c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
39252d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3926fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
3927121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
392879523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3929de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3930dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3931dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3932e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3933fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3934fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
393561303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
39366e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
39379e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
393817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
39399e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
394023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
394123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3942931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3943931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
39446335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
394517deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
39464241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
394761a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3948907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
39496d2ac8eeSAndrew Lunn 	.avb_ops = &mv88e6390_avb_ops,
39506d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
39516c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
39521a3b39ecSAndrew Lunn };
39531a3b39ecSAndrew Lunn 
3954b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = {
39554b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
395693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
395793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3958cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3959ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3960ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3961b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3962b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3963b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
396408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
39657f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3966a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
396796a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3968ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
3969f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
397056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3971601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
397256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3973cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3974ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
39750898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3976c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
39779dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
39786c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
39792d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3980121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3981a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
398240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3983dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3984dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3985052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3986fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3987fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3988fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
398951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
39909e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
399117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
39929e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
399323e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
399423e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3995f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
39960ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
39979db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
39986d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
39994241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
400061a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4001907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
4002a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
40030d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
40046d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
40056c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
4006b3469dd8SVivien Didelot };
4007b3469dd8SVivien Didelot 
40081f71836fSRasmus Villemoes static const struct mv88e6xxx_ops mv88e6250_ops = {
40091f71836fSRasmus Villemoes 	/* MV88E6XXX_FAMILY_6250 */
40101f71836fSRasmus Villemoes 	.ieee_pri_map = mv88e6250_g1_ieee_pri_map,
40111f71836fSRasmus Villemoes 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
40121f71836fSRasmus Villemoes 	.irl_init_all = mv88e6352_g2_irl_init_all,
40131f71836fSRasmus Villemoes 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
40141f71836fSRasmus Villemoes 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
40151f71836fSRasmus Villemoes 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
40161f71836fSRasmus Villemoes 	.phy_read = mv88e6xxx_g2_smi_phy_read,
40171f71836fSRasmus Villemoes 	.phy_write = mv88e6xxx_g2_smi_phy_write,
40181f71836fSRasmus Villemoes 	.port_set_link = mv88e6xxx_port_set_link,
40191f71836fSRasmus Villemoes 	.port_set_duplex = mv88e6xxx_port_set_duplex,
40201f71836fSRasmus Villemoes 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
40211f71836fSRasmus Villemoes 	.port_set_speed = mv88e6250_port_set_speed,
40221f71836fSRasmus Villemoes 	.port_tag_remap = mv88e6095_port_tag_remap,
40231f71836fSRasmus Villemoes 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
40241f71836fSRasmus Villemoes 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
40251f71836fSRasmus Villemoes 	.port_set_ether_type = mv88e6351_port_set_ether_type,
40261f71836fSRasmus Villemoes 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
40271f71836fSRasmus Villemoes 	.port_pause_limit = mv88e6097_port_pause_limit,
40281f71836fSRasmus Villemoes 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
40291f71836fSRasmus Villemoes 	.port_link_state = mv88e6250_port_link_state,
40301f71836fSRasmus Villemoes 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
40311f71836fSRasmus Villemoes 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
40321f71836fSRasmus Villemoes 	.stats_get_sset_count = mv88e6250_stats_get_sset_count,
40331f71836fSRasmus Villemoes 	.stats_get_strings = mv88e6250_stats_get_strings,
40341f71836fSRasmus Villemoes 	.stats_get_stats = mv88e6250_stats_get_stats,
40351f71836fSRasmus Villemoes 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
40361f71836fSRasmus Villemoes 	.set_egress_port = mv88e6095_g1_set_egress_port,
40371f71836fSRasmus Villemoes 	.watchdog_ops = &mv88e6250_watchdog_ops,
40381f71836fSRasmus Villemoes 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
40391f71836fSRasmus Villemoes 	.pot_clear = mv88e6xxx_g2_pot_clear,
40401f71836fSRasmus Villemoes 	.reset = mv88e6250_g1_reset,
40411f71836fSRasmus Villemoes 	.vtu_getnext = mv88e6250_g1_vtu_getnext,
40421f71836fSRasmus Villemoes 	.vtu_loadpurge = mv88e6250_g1_vtu_loadpurge,
404371509614SHubert Feurstein 	.avb_ops = &mv88e6352_avb_ops,
404471509614SHubert Feurstein 	.ptp_ops = &mv88e6250_ptp_ops,
40451f71836fSRasmus Villemoes 	.phylink_validate = mv88e6065_phylink_validate,
40461f71836fSRasmus Villemoes };
40471f71836fSRasmus Villemoes 
40481a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = {
40494b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4050ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4051cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
405298fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
405398fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
40541a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
40551a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
40561a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
40571a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
40581a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
40591a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
40601a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
40617cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4062ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4063f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
406456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4065601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
406656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
40670898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4068c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
40699dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
40706c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
40712d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4072fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4073121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
407479523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4075de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4076dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4077dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4078e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4079fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4080fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
408161303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
40826e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
40839e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
408417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
40859e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
408623e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
408723e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4088931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4089931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
40906335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
409117deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
40924241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
409361a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4094907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
4095a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
40960d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
40976d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
40986c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
40991a3b39ecSAndrew Lunn };
41001a3b39ecSAndrew Lunn 
4101b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = {
41024b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6320 */
410393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
410493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4105cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4106ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4107ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4108b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4109b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4110b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
411108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
41127f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
411396a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
4114ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
411556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4116601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
411756995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4118cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4119ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
41200898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4121c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
41229dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
41236c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
41242d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4125121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4126a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
412740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4128dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4129dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4130052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
4131fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4132fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
41339c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
413451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
41359e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
413617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
4137f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
41380ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4139a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
41400d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
41416d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
41426c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4143b3469dd8SVivien Didelot };
4144b3469dd8SVivien Didelot 
4145b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = {
4146bd807204SVivien Didelot 	/* MV88E6XXX_FAMILY_6320 */
414793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
414893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4149cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4150ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4151ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4152b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4153b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4154b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
415508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
41567f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
415796a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
4158ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
415956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4160601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
416156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4162cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4163ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
41640898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4165c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
41669dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
41676c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
41682d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4169121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4170a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
417140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4172dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4173dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4174052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
4175fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4176fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
41779c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
417817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
4179f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
41800ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4181a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
41820d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
41836d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
41846c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4185b3469dd8SVivien Didelot };
4186b3469dd8SVivien Didelot 
418716e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = {
418816e329aeSVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
418993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
419093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4191cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
419216e329aeSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
419316e329aeSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
419416e329aeSVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
419516e329aeSVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
419616e329aeSVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
419716e329aeSVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
419816e329aeSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
419916e329aeSVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
420026422340SMarek Behún 	.port_set_speed = mv88e6341_port_set_speed,
42017cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
420216e329aeSVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
420316e329aeSVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
420416e329aeSVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
420516e329aeSVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4206cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
420716e329aeSVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
42080898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
420916e329aeSVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
421016e329aeSVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
42116c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
42122d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
42137a3007d2SMarek Behún 	.port_set_cmode = mv88e6341_port_set_cmode,
4214121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
421516e329aeSVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
421640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
421716e329aeSVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
421816e329aeSVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
421916e329aeSVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
4220fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4221fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
422216e329aeSVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
422316e329aeSVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
42249e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
422516e329aeSVivien Didelot 	.reset = mv88e6352_g1_reset,
4226f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
42270ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4228d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
4229d3cf7d8fSMarek Behún 	.serdes_get_lane = mv88e6341_serdes_get_lane,
42304241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
423161a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4232907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
4233a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
42340d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
42356d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
4236e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
423716e329aeSVivien Didelot };
423816e329aeSVivien Didelot 
4239b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = {
42404b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
424193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
424293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4243cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4244b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4245b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4246b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
424708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
42487f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
424994d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
425096a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
4251ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
425256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4253601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
425456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4255cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4256ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
42570898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4258c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
42599dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
42606c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
42612d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4262121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4263a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
426440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4265dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4266dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4267052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4268fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4269fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4270fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
427151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
42729e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
427317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
427423e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
427523e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4276f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
42770ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
42786c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4279b3469dd8SVivien Didelot };
4280b3469dd8SVivien Didelot 
4281b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = {
42824b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
428393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
428493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4285cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4286b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4287b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4288b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
428908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
42907f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
429194d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
429296a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
4293ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
429456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4295601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
429656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4297cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4298ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
42990898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4300c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
43019dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
43026c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
43032d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4304121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4305a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
430640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4307dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4308dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4309052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4310fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4311fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4312fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
431351c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
43149e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
431517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
431623e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
431723e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4318f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
43190ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
43200d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
43216d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
43226c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4323b3469dd8SVivien Didelot };
4324b3469dd8SVivien Didelot 
4325b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = {
43264b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
432793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
432893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4329cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4330ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4331ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4332b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4333b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4334b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
433508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
43367f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
4337a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
433896a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
4339ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
4340f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
434156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4342601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
434356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4344cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4345ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
43460898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4347c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
43489dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
43496c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
43502d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4351121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4352a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
435340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4354dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4355dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4356052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4357fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4358fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4359fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
436051c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
43619e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
436217e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
43639e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
436423e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
436523e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4366f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
43670ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
43689db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
43696d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
43704241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
437161a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4372907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
4373a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
43740d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
43756d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
4376cda9f4aaSAndrew Lunn 	.serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
4377cda9f4aaSAndrew Lunn 	.serdes_get_strings = mv88e6352_serdes_get_strings,
4378cda9f4aaSAndrew Lunn 	.serdes_get_stats = mv88e6352_serdes_get_stats,
43796c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
4380b3469dd8SVivien Didelot };
4381b3469dd8SVivien Didelot 
43821a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = {
43834b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4384ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4385cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
438698fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
438798fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
43881a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
43891a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
43901a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
43911a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
43921a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
43931a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
43941a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
43957cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4396ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4397f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
439856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4399601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
440056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4401cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4402ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
44030898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4404c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
44059dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
44066c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
44072d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4408fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4409121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
441079523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4411de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4412dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4413dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4414e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4415fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4416fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
441761303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
44186e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
44199e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
442017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
44219e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
442223e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
442323e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4424931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4425931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
44266335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
442717deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
44284241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
442961a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4430907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
4431a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
44320d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
44336d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
44340df95287SNikita Yushchenko 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
44350df95287SNikita Yushchenko 	.serdes_get_strings = mv88e6390_serdes_get_strings,
44360df95287SNikita Yushchenko 	.serdes_get_stats = mv88e6390_serdes_get_stats,
44376c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
44381a3b39ecSAndrew Lunn };
44391a3b39ecSAndrew Lunn 
44401a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = {
44414b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4442ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4443cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
444498fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
444598fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
44461a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
44471a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
44481a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
44491a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
44501a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
44511a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
44521a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390x_port_set_speed,
44537cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
4454ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4455f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
445656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4457601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
445856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4459cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4460ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
44610898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4462c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
44639dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
44646c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
44652d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4466b3dce4daSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
4467121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
446879523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4469de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4470dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4471dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4472e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4473fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4474fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
447561303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
44766e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
44779e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
447817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
44799e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
448023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
448123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4482931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4483931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4484d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
448517deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390x_serdes_get_lane,
44864241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
448761a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4488907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
4489a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
44900d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
44916d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
44926c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
44931a3b39ecSAndrew Lunn };
44941a3b39ecSAndrew Lunn 
4495fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = {
4496fad09c73SVivien Didelot 	[MV88E6085] = {
4497107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
4498fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6097,
4499fad09c73SVivien Didelot 		.name = "Marvell 88E6085",
4500fad09c73SVivien Didelot 		.num_databases = 4096,
4501d9ea5620SAndrew Lunn 		.num_macs = 8192,
4502fad09c73SVivien Didelot 		.num_ports = 10,
4503bc393155SAndrew Lunn 		.num_internal_phys = 5,
45043cf3c846SVivien Didelot 		.max_vid = 4095,
4505fad09c73SVivien Didelot 		.port_base_addr = 0x10,
45069255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4507a935c052SVivien Didelot 		.global1_addr = 0x1b,
45089069c13aSVivien Didelot 		.global2_addr = 0x1c,
4509acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4510dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4511d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4512e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4513f3645652SVivien Didelot 		.pvt = true,
4514b3e05aa1SVivien Didelot 		.multi_chip = true,
4515443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4516b3469dd8SVivien Didelot 		.ops = &mv88e6085_ops,
4517fad09c73SVivien Didelot 	},
4518fad09c73SVivien Didelot 
4519fad09c73SVivien Didelot 	[MV88E6095] = {
4520107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095,
4521fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6095,
4522fad09c73SVivien Didelot 		.name = "Marvell 88E6095/88E6095F",
4523fad09c73SVivien Didelot 		.num_databases = 256,
4524d9ea5620SAndrew Lunn 		.num_macs = 8192,
4525fad09c73SVivien Didelot 		.num_ports = 11,
4526bc393155SAndrew Lunn 		.num_internal_phys = 0,
45273cf3c846SVivien Didelot 		.max_vid = 4095,
4528fad09c73SVivien Didelot 		.port_base_addr = 0x10,
45299255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4530a935c052SVivien Didelot 		.global1_addr = 0x1b,
45319069c13aSVivien Didelot 		.global2_addr = 0x1c,
4532acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4533dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4534e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4535b3e05aa1SVivien Didelot 		.multi_chip = true,
4536443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4537b3469dd8SVivien Didelot 		.ops = &mv88e6095_ops,
4538fad09c73SVivien Didelot 	},
4539fad09c73SVivien Didelot 
45407d381a02SStefan Eichenberger 	[MV88E6097] = {
4541107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097,
45427d381a02SStefan Eichenberger 		.family = MV88E6XXX_FAMILY_6097,
45437d381a02SStefan Eichenberger 		.name = "Marvell 88E6097/88E6097F",
45447d381a02SStefan Eichenberger 		.num_databases = 4096,
4545d9ea5620SAndrew Lunn 		.num_macs = 8192,
45467d381a02SStefan Eichenberger 		.num_ports = 11,
4547bc393155SAndrew Lunn 		.num_internal_phys = 8,
45483cf3c846SVivien Didelot 		.max_vid = 4095,
45497d381a02SStefan Eichenberger 		.port_base_addr = 0x10,
45509255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
45517d381a02SStefan Eichenberger 		.global1_addr = 0x1b,
45529069c13aSVivien Didelot 		.global2_addr = 0x1c,
45537d381a02SStefan Eichenberger 		.age_time_coeff = 15000,
4554c534178bSStefan Eichenberger 		.g1_irqs = 8,
4555d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4556e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4557f3645652SVivien Didelot 		.pvt = true,
4558b3e05aa1SVivien Didelot 		.multi_chip = true,
45592bfcfcd3SStefan Eichenberger 		.tag_protocol = DSA_TAG_PROTO_EDSA,
45607d381a02SStefan Eichenberger 		.ops = &mv88e6097_ops,
45617d381a02SStefan Eichenberger 	},
45627d381a02SStefan Eichenberger 
4563fad09c73SVivien Didelot 	[MV88E6123] = {
4564107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123,
4565fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4566fad09c73SVivien Didelot 		.name = "Marvell 88E6123",
4567fad09c73SVivien Didelot 		.num_databases = 4096,
4568d9ea5620SAndrew Lunn 		.num_macs = 1024,
4569fad09c73SVivien Didelot 		.num_ports = 3,
4570bc393155SAndrew Lunn 		.num_internal_phys = 5,
45713cf3c846SVivien Didelot 		.max_vid = 4095,
4572fad09c73SVivien Didelot 		.port_base_addr = 0x10,
45739255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4574a935c052SVivien Didelot 		.global1_addr = 0x1b,
45759069c13aSVivien Didelot 		.global2_addr = 0x1c,
4576acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4577dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4578d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4579e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4580f3645652SVivien Didelot 		.pvt = true,
4581b3e05aa1SVivien Didelot 		.multi_chip = true,
45825ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4583b3469dd8SVivien Didelot 		.ops = &mv88e6123_ops,
4584fad09c73SVivien Didelot 	},
4585fad09c73SVivien Didelot 
4586fad09c73SVivien Didelot 	[MV88E6131] = {
4587107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131,
4588fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
4589fad09c73SVivien Didelot 		.name = "Marvell 88E6131",
4590fad09c73SVivien Didelot 		.num_databases = 256,
4591d9ea5620SAndrew Lunn 		.num_macs = 8192,
4592fad09c73SVivien Didelot 		.num_ports = 8,
4593bc393155SAndrew Lunn 		.num_internal_phys = 0,
45943cf3c846SVivien Didelot 		.max_vid = 4095,
4595fad09c73SVivien Didelot 		.port_base_addr = 0x10,
45969255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4597a935c052SVivien Didelot 		.global1_addr = 0x1b,
45989069c13aSVivien Didelot 		.global2_addr = 0x1c,
4599acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4600dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4601e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4602b3e05aa1SVivien Didelot 		.multi_chip = true,
4603443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4604b3469dd8SVivien Didelot 		.ops = &mv88e6131_ops,
4605fad09c73SVivien Didelot 	},
4606fad09c73SVivien Didelot 
4607990e27b0SVivien Didelot 	[MV88E6141] = {
4608107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141,
4609990e27b0SVivien Didelot 		.family = MV88E6XXX_FAMILY_6341,
461079a68b26SUwe Kleine-König 		.name = "Marvell 88E6141",
4611990e27b0SVivien Didelot 		.num_databases = 4096,
4612d9ea5620SAndrew Lunn 		.num_macs = 2048,
4613990e27b0SVivien Didelot 		.num_ports = 6,
4614bc393155SAndrew Lunn 		.num_internal_phys = 5,
4615a73ccd61SBrandon Streiff 		.num_gpio = 11,
46163cf3c846SVivien Didelot 		.max_vid = 4095,
4617990e27b0SVivien Didelot 		.port_base_addr = 0x10,
46189255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
4619990e27b0SVivien Didelot 		.global1_addr = 0x1b,
46209069c13aSVivien Didelot 		.global2_addr = 0x1c,
4621990e27b0SVivien Didelot 		.age_time_coeff = 3750,
4622990e27b0SVivien Didelot 		.atu_move_port_mask = 0x1f,
4623adfccf11SAndrew Lunn 		.g1_irqs = 9,
4624d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4625f3645652SVivien Didelot 		.pvt = true,
4626b3e05aa1SVivien Didelot 		.multi_chip = true,
4627990e27b0SVivien Didelot 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4628990e27b0SVivien Didelot 		.ops = &mv88e6141_ops,
4629990e27b0SVivien Didelot 	},
4630990e27b0SVivien Didelot 
4631fad09c73SVivien Didelot 	[MV88E6161] = {
4632107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161,
4633fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4634fad09c73SVivien Didelot 		.name = "Marvell 88E6161",
4635fad09c73SVivien Didelot 		.num_databases = 4096,
4636d9ea5620SAndrew Lunn 		.num_macs = 1024,
4637fad09c73SVivien Didelot 		.num_ports = 6,
4638bc393155SAndrew Lunn 		.num_internal_phys = 5,
46393cf3c846SVivien Didelot 		.max_vid = 4095,
4640fad09c73SVivien Didelot 		.port_base_addr = 0x10,
46419255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4642a935c052SVivien Didelot 		.global1_addr = 0x1b,
46439069c13aSVivien Didelot 		.global2_addr = 0x1c,
4644acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4645dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4646d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4647e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4648f3645652SVivien Didelot 		.pvt = true,
4649b3e05aa1SVivien Didelot 		.multi_chip = true,
46505ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4651dfa54348SAndrew Lunn 		.ptp_support = true,
4652b3469dd8SVivien Didelot 		.ops = &mv88e6161_ops,
4653fad09c73SVivien Didelot 	},
4654fad09c73SVivien Didelot 
4655fad09c73SVivien Didelot 	[MV88E6165] = {
4656107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165,
4657fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4658fad09c73SVivien Didelot 		.name = "Marvell 88E6165",
4659fad09c73SVivien Didelot 		.num_databases = 4096,
4660d9ea5620SAndrew Lunn 		.num_macs = 8192,
4661fad09c73SVivien Didelot 		.num_ports = 6,
4662bc393155SAndrew Lunn 		.num_internal_phys = 0,
46633cf3c846SVivien Didelot 		.max_vid = 4095,
4664fad09c73SVivien Didelot 		.port_base_addr = 0x10,
46659255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4666a935c052SVivien Didelot 		.global1_addr = 0x1b,
46679069c13aSVivien Didelot 		.global2_addr = 0x1c,
4668acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4669dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4670d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4671e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4672f3645652SVivien Didelot 		.pvt = true,
4673b3e05aa1SVivien Didelot 		.multi_chip = true,
4674443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4675dfa54348SAndrew Lunn 		.ptp_support = true,
4676b3469dd8SVivien Didelot 		.ops = &mv88e6165_ops,
4677fad09c73SVivien Didelot 	},
4678fad09c73SVivien Didelot 
4679fad09c73SVivien Didelot 	[MV88E6171] = {
4680107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171,
4681fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4682fad09c73SVivien Didelot 		.name = "Marvell 88E6171",
4683fad09c73SVivien Didelot 		.num_databases = 4096,
4684d9ea5620SAndrew Lunn 		.num_macs = 8192,
4685fad09c73SVivien Didelot 		.num_ports = 7,
4686bc393155SAndrew Lunn 		.num_internal_phys = 5,
46873cf3c846SVivien Didelot 		.max_vid = 4095,
4688fad09c73SVivien Didelot 		.port_base_addr = 0x10,
46899255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4690a935c052SVivien Didelot 		.global1_addr = 0x1b,
46919069c13aSVivien Didelot 		.global2_addr = 0x1c,
4692acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4693dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4694d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4695e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4696f3645652SVivien Didelot 		.pvt = true,
4697b3e05aa1SVivien Didelot 		.multi_chip = true,
4698443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4699b3469dd8SVivien Didelot 		.ops = &mv88e6171_ops,
4700fad09c73SVivien Didelot 	},
4701fad09c73SVivien Didelot 
4702fad09c73SVivien Didelot 	[MV88E6172] = {
4703107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172,
4704fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4705fad09c73SVivien Didelot 		.name = "Marvell 88E6172",
4706fad09c73SVivien Didelot 		.num_databases = 4096,
4707d9ea5620SAndrew Lunn 		.num_macs = 8192,
4708fad09c73SVivien Didelot 		.num_ports = 7,
4709bc393155SAndrew Lunn 		.num_internal_phys = 5,
4710a73ccd61SBrandon Streiff 		.num_gpio = 15,
47113cf3c846SVivien Didelot 		.max_vid = 4095,
4712fad09c73SVivien Didelot 		.port_base_addr = 0x10,
47139255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4714a935c052SVivien Didelot 		.global1_addr = 0x1b,
47159069c13aSVivien Didelot 		.global2_addr = 0x1c,
4716acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4717dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4718d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4719e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4720f3645652SVivien Didelot 		.pvt = true,
4721b3e05aa1SVivien Didelot 		.multi_chip = true,
4722443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4723b3469dd8SVivien Didelot 		.ops = &mv88e6172_ops,
4724fad09c73SVivien Didelot 	},
4725fad09c73SVivien Didelot 
4726fad09c73SVivien Didelot 	[MV88E6175] = {
4727107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175,
4728fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4729fad09c73SVivien Didelot 		.name = "Marvell 88E6175",
4730fad09c73SVivien Didelot 		.num_databases = 4096,
4731d9ea5620SAndrew Lunn 		.num_macs = 8192,
4732fad09c73SVivien Didelot 		.num_ports = 7,
4733bc393155SAndrew Lunn 		.num_internal_phys = 5,
47343cf3c846SVivien Didelot 		.max_vid = 4095,
4735fad09c73SVivien Didelot 		.port_base_addr = 0x10,
47369255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4737a935c052SVivien Didelot 		.global1_addr = 0x1b,
47389069c13aSVivien Didelot 		.global2_addr = 0x1c,
4739acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4740dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4741d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4742e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4743f3645652SVivien Didelot 		.pvt = true,
4744b3e05aa1SVivien Didelot 		.multi_chip = true,
4745443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4746b3469dd8SVivien Didelot 		.ops = &mv88e6175_ops,
4747fad09c73SVivien Didelot 	},
4748fad09c73SVivien Didelot 
4749fad09c73SVivien Didelot 	[MV88E6176] = {
4750107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176,
4751fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4752fad09c73SVivien Didelot 		.name = "Marvell 88E6176",
4753fad09c73SVivien Didelot 		.num_databases = 4096,
4754d9ea5620SAndrew Lunn 		.num_macs = 8192,
4755fad09c73SVivien Didelot 		.num_ports = 7,
4756bc393155SAndrew Lunn 		.num_internal_phys = 5,
4757a73ccd61SBrandon Streiff 		.num_gpio = 15,
47583cf3c846SVivien Didelot 		.max_vid = 4095,
4759fad09c73SVivien Didelot 		.port_base_addr = 0x10,
47609255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4761a935c052SVivien Didelot 		.global1_addr = 0x1b,
47629069c13aSVivien Didelot 		.global2_addr = 0x1c,
4763acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4764dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4765d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4766e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4767f3645652SVivien Didelot 		.pvt = true,
4768b3e05aa1SVivien Didelot 		.multi_chip = true,
4769443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4770b3469dd8SVivien Didelot 		.ops = &mv88e6176_ops,
4771fad09c73SVivien Didelot 	},
4772fad09c73SVivien Didelot 
4773fad09c73SVivien Didelot 	[MV88E6185] = {
4774107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185,
4775fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
4776fad09c73SVivien Didelot 		.name = "Marvell 88E6185",
4777fad09c73SVivien Didelot 		.num_databases = 256,
4778d9ea5620SAndrew Lunn 		.num_macs = 8192,
4779fad09c73SVivien Didelot 		.num_ports = 10,
4780bc393155SAndrew Lunn 		.num_internal_phys = 0,
47813cf3c846SVivien Didelot 		.max_vid = 4095,
4782fad09c73SVivien Didelot 		.port_base_addr = 0x10,
47839255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4784a935c052SVivien Didelot 		.global1_addr = 0x1b,
47859069c13aSVivien Didelot 		.global2_addr = 0x1c,
4786acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4787dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4788e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4789b3e05aa1SVivien Didelot 		.multi_chip = true,
4790443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4791b3469dd8SVivien Didelot 		.ops = &mv88e6185_ops,
4792fad09c73SVivien Didelot 	},
4793fad09c73SVivien Didelot 
47941a3b39ecSAndrew Lunn 	[MV88E6190] = {
4795107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190,
47961a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
47971a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190",
47981a3b39ecSAndrew Lunn 		.num_databases = 4096,
4799d9ea5620SAndrew Lunn 		.num_macs = 16384,
48001a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
480195150f29SHeiner Kallweit 		.num_internal_phys = 9,
4802a73ccd61SBrandon Streiff 		.num_gpio = 16,
4803931d1822SVivien Didelot 		.max_vid = 8191,
48041a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
48059255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
48061a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
48079069c13aSVivien Didelot 		.global2_addr = 0x1c,
4808443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4809b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
48101a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4811d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4812f3645652SVivien Didelot 		.pvt = true,
4813b3e05aa1SVivien Didelot 		.multi_chip = true,
4814e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
48151a3b39ecSAndrew Lunn 		.ops = &mv88e6190_ops,
48161a3b39ecSAndrew Lunn 	},
48171a3b39ecSAndrew Lunn 
48181a3b39ecSAndrew Lunn 	[MV88E6190X] = {
4819107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X,
48201a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
48211a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190X",
48221a3b39ecSAndrew Lunn 		.num_databases = 4096,
4823d9ea5620SAndrew Lunn 		.num_macs = 16384,
48241a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
482595150f29SHeiner Kallweit 		.num_internal_phys = 9,
4826a73ccd61SBrandon Streiff 		.num_gpio = 16,
4827931d1822SVivien Didelot 		.max_vid = 8191,
48281a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
48299255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
48301a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
48319069c13aSVivien Didelot 		.global2_addr = 0x1c,
4832b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
48331a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4834d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4835e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4836f3645652SVivien Didelot 		.pvt = true,
4837b3e05aa1SVivien Didelot 		.multi_chip = true,
4838443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
48391a3b39ecSAndrew Lunn 		.ops = &mv88e6190x_ops,
48401a3b39ecSAndrew Lunn 	},
48411a3b39ecSAndrew Lunn 
48421a3b39ecSAndrew Lunn 	[MV88E6191] = {
4843107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191,
48441a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
48451a3b39ecSAndrew Lunn 		.name = "Marvell 88E6191",
48461a3b39ecSAndrew Lunn 		.num_databases = 4096,
4847d9ea5620SAndrew Lunn 		.num_macs = 16384,
48481a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
484995150f29SHeiner Kallweit 		.num_internal_phys = 9,
4850931d1822SVivien Didelot 		.max_vid = 8191,
48511a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
48529255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
48531a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
48549069c13aSVivien Didelot 		.global2_addr = 0x1c,
4855b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
4856443d5a1bSAndrew Lunn 		.g1_irqs = 9,
4857d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4858e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4859f3645652SVivien Didelot 		.pvt = true,
4860b3e05aa1SVivien Didelot 		.multi_chip = true,
4861443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
48622fa8d3afSBrandon Streiff 		.ptp_support = true,
48632cf4cefbSVivien Didelot 		.ops = &mv88e6191_ops,
48641a3b39ecSAndrew Lunn 	},
48651a3b39ecSAndrew Lunn 
486649022647SHubert Feurstein 	[MV88E6220] = {
486749022647SHubert Feurstein 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
486849022647SHubert Feurstein 		.family = MV88E6XXX_FAMILY_6250,
486949022647SHubert Feurstein 		.name = "Marvell 88E6220",
487049022647SHubert Feurstein 		.num_databases = 64,
487149022647SHubert Feurstein 
487249022647SHubert Feurstein 		/* Ports 2-4 are not routed to pins
487349022647SHubert Feurstein 		 * => usable ports 0, 1, 5, 6
487449022647SHubert Feurstein 		 */
487549022647SHubert Feurstein 		.num_ports = 7,
487649022647SHubert Feurstein 		.num_internal_phys = 2,
4877c857486aSHubert Feurstein 		.invalid_port_mask = BIT(2) | BIT(3) | BIT(4),
487849022647SHubert Feurstein 		.max_vid = 4095,
487949022647SHubert Feurstein 		.port_base_addr = 0x08,
488049022647SHubert Feurstein 		.phy_base_addr = 0x00,
488149022647SHubert Feurstein 		.global1_addr = 0x0f,
488249022647SHubert Feurstein 		.global2_addr = 0x07,
488349022647SHubert Feurstein 		.age_time_coeff = 15000,
488449022647SHubert Feurstein 		.g1_irqs = 9,
488549022647SHubert Feurstein 		.g2_irqs = 10,
488649022647SHubert Feurstein 		.atu_move_port_mask = 0xf,
488749022647SHubert Feurstein 		.dual_chip = true,
488849022647SHubert Feurstein 		.tag_protocol = DSA_TAG_PROTO_DSA,
488971509614SHubert Feurstein 		.ptp_support = true,
489049022647SHubert Feurstein 		.ops = &mv88e6250_ops,
489149022647SHubert Feurstein 	},
489249022647SHubert Feurstein 
4893fad09c73SVivien Didelot 	[MV88E6240] = {
4894107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240,
4895fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4896fad09c73SVivien Didelot 		.name = "Marvell 88E6240",
4897fad09c73SVivien Didelot 		.num_databases = 4096,
4898d9ea5620SAndrew Lunn 		.num_macs = 8192,
4899fad09c73SVivien Didelot 		.num_ports = 7,
4900bc393155SAndrew Lunn 		.num_internal_phys = 5,
4901a73ccd61SBrandon Streiff 		.num_gpio = 15,
49023cf3c846SVivien Didelot 		.max_vid = 4095,
4903fad09c73SVivien Didelot 		.port_base_addr = 0x10,
49049255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4905a935c052SVivien Didelot 		.global1_addr = 0x1b,
49069069c13aSVivien Didelot 		.global2_addr = 0x1c,
4907acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4908dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4909d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4910e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4911f3645652SVivien Didelot 		.pvt = true,
4912b3e05aa1SVivien Didelot 		.multi_chip = true,
4913443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
49142fa8d3afSBrandon Streiff 		.ptp_support = true,
4915b3469dd8SVivien Didelot 		.ops = &mv88e6240_ops,
4916fad09c73SVivien Didelot 	},
4917fad09c73SVivien Didelot 
49181f71836fSRasmus Villemoes 	[MV88E6250] = {
49191f71836fSRasmus Villemoes 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250,
49201f71836fSRasmus Villemoes 		.family = MV88E6XXX_FAMILY_6250,
49211f71836fSRasmus Villemoes 		.name = "Marvell 88E6250",
49221f71836fSRasmus Villemoes 		.num_databases = 64,
49231f71836fSRasmus Villemoes 		.num_ports = 7,
49241f71836fSRasmus Villemoes 		.num_internal_phys = 5,
49251f71836fSRasmus Villemoes 		.max_vid = 4095,
49261f71836fSRasmus Villemoes 		.port_base_addr = 0x08,
49271f71836fSRasmus Villemoes 		.phy_base_addr = 0x00,
49281f71836fSRasmus Villemoes 		.global1_addr = 0x0f,
49291f71836fSRasmus Villemoes 		.global2_addr = 0x07,
49301f71836fSRasmus Villemoes 		.age_time_coeff = 15000,
49311f71836fSRasmus Villemoes 		.g1_irqs = 9,
49321f71836fSRasmus Villemoes 		.g2_irqs = 10,
49331f71836fSRasmus Villemoes 		.atu_move_port_mask = 0xf,
49341f71836fSRasmus Villemoes 		.dual_chip = true,
49351f71836fSRasmus Villemoes 		.tag_protocol = DSA_TAG_PROTO_DSA,
493671509614SHubert Feurstein 		.ptp_support = true,
49371f71836fSRasmus Villemoes 		.ops = &mv88e6250_ops,
49381f71836fSRasmus Villemoes 	},
49391f71836fSRasmus Villemoes 
49401a3b39ecSAndrew Lunn 	[MV88E6290] = {
4941107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
49421a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
49431a3b39ecSAndrew Lunn 		.name = "Marvell 88E6290",
49441a3b39ecSAndrew Lunn 		.num_databases = 4096,
49451a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
494695150f29SHeiner Kallweit 		.num_internal_phys = 9,
4947a73ccd61SBrandon Streiff 		.num_gpio = 16,
4948931d1822SVivien Didelot 		.max_vid = 8191,
49491a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
49509255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
49511a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
49529069c13aSVivien Didelot 		.global2_addr = 0x1c,
4953b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
49541a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4955d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4956e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4957f3645652SVivien Didelot 		.pvt = true,
4958b3e05aa1SVivien Didelot 		.multi_chip = true,
4959443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
49602fa8d3afSBrandon Streiff 		.ptp_support = true,
49611a3b39ecSAndrew Lunn 		.ops = &mv88e6290_ops,
49621a3b39ecSAndrew Lunn 	},
49631a3b39ecSAndrew Lunn 
4964fad09c73SVivien Didelot 	[MV88E6320] = {
4965107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320,
4966fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
4967fad09c73SVivien Didelot 		.name = "Marvell 88E6320",
4968fad09c73SVivien Didelot 		.num_databases = 4096,
4969d9ea5620SAndrew Lunn 		.num_macs = 8192,
4970fad09c73SVivien Didelot 		.num_ports = 7,
4971bc393155SAndrew Lunn 		.num_internal_phys = 5,
4972a73ccd61SBrandon Streiff 		.num_gpio = 15,
49733cf3c846SVivien Didelot 		.max_vid = 4095,
4974fad09c73SVivien Didelot 		.port_base_addr = 0x10,
49759255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4976a935c052SVivien Didelot 		.global1_addr = 0x1b,
49779069c13aSVivien Didelot 		.global2_addr = 0x1c,
4978acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4979dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4980bc393155SAndrew Lunn 		.g2_irqs = 10,
4981e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4982f3645652SVivien Didelot 		.pvt = true,
4983b3e05aa1SVivien Didelot 		.multi_chip = true,
4984443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
49852fa8d3afSBrandon Streiff 		.ptp_support = true,
4986b3469dd8SVivien Didelot 		.ops = &mv88e6320_ops,
4987fad09c73SVivien Didelot 	},
4988fad09c73SVivien Didelot 
4989fad09c73SVivien Didelot 	[MV88E6321] = {
4990107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321,
4991fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
4992fad09c73SVivien Didelot 		.name = "Marvell 88E6321",
4993fad09c73SVivien Didelot 		.num_databases = 4096,
4994d9ea5620SAndrew Lunn 		.num_macs = 8192,
4995fad09c73SVivien Didelot 		.num_ports = 7,
4996bc393155SAndrew Lunn 		.num_internal_phys = 5,
4997a73ccd61SBrandon Streiff 		.num_gpio = 15,
49983cf3c846SVivien Didelot 		.max_vid = 4095,
4999fad09c73SVivien Didelot 		.port_base_addr = 0x10,
50009255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5001a935c052SVivien Didelot 		.global1_addr = 0x1b,
50029069c13aSVivien Didelot 		.global2_addr = 0x1c,
5003acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5004dc30c35bSAndrew Lunn 		.g1_irqs = 8,
5005bc393155SAndrew Lunn 		.g2_irqs = 10,
5006e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5007b3e05aa1SVivien Didelot 		.multi_chip = true,
5008443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
50092fa8d3afSBrandon Streiff 		.ptp_support = true,
5010b3469dd8SVivien Didelot 		.ops = &mv88e6321_ops,
5011fad09c73SVivien Didelot 	},
5012fad09c73SVivien Didelot 
5013a75961d0SGregory CLEMENT 	[MV88E6341] = {
5014107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
5015a75961d0SGregory CLEMENT 		.family = MV88E6XXX_FAMILY_6341,
5016a75961d0SGregory CLEMENT 		.name = "Marvell 88E6341",
5017a75961d0SGregory CLEMENT 		.num_databases = 4096,
5018d9ea5620SAndrew Lunn 		.num_macs = 2048,
5019bc393155SAndrew Lunn 		.num_internal_phys = 5,
5020a75961d0SGregory CLEMENT 		.num_ports = 6,
5021a73ccd61SBrandon Streiff 		.num_gpio = 11,
50223cf3c846SVivien Didelot 		.max_vid = 4095,
5023a75961d0SGregory CLEMENT 		.port_base_addr = 0x10,
50249255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
5025a75961d0SGregory CLEMENT 		.global1_addr = 0x1b,
50269069c13aSVivien Didelot 		.global2_addr = 0x1c,
5027a75961d0SGregory CLEMENT 		.age_time_coeff = 3750,
5028e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5029adfccf11SAndrew Lunn 		.g1_irqs = 9,
5030d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5031f3645652SVivien Didelot 		.pvt = true,
5032b3e05aa1SVivien Didelot 		.multi_chip = true,
5033a75961d0SGregory CLEMENT 		.tag_protocol = DSA_TAG_PROTO_EDSA,
50342fa8d3afSBrandon Streiff 		.ptp_support = true,
5035a75961d0SGregory CLEMENT 		.ops = &mv88e6341_ops,
5036a75961d0SGregory CLEMENT 	},
5037a75961d0SGregory CLEMENT 
5038fad09c73SVivien Didelot 	[MV88E6350] = {
5039107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350,
5040fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5041fad09c73SVivien Didelot 		.name = "Marvell 88E6350",
5042fad09c73SVivien Didelot 		.num_databases = 4096,
5043d9ea5620SAndrew Lunn 		.num_macs = 8192,
5044fad09c73SVivien Didelot 		.num_ports = 7,
5045bc393155SAndrew Lunn 		.num_internal_phys = 5,
50463cf3c846SVivien Didelot 		.max_vid = 4095,
5047fad09c73SVivien Didelot 		.port_base_addr = 0x10,
50489255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5049a935c052SVivien Didelot 		.global1_addr = 0x1b,
50509069c13aSVivien Didelot 		.global2_addr = 0x1c,
5051acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5052dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5053d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5054e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5055f3645652SVivien Didelot 		.pvt = true,
5056b3e05aa1SVivien Didelot 		.multi_chip = true,
5057443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
5058b3469dd8SVivien Didelot 		.ops = &mv88e6350_ops,
5059fad09c73SVivien Didelot 	},
5060fad09c73SVivien Didelot 
5061fad09c73SVivien Didelot 	[MV88E6351] = {
5062107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351,
5063fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5064fad09c73SVivien Didelot 		.name = "Marvell 88E6351",
5065fad09c73SVivien Didelot 		.num_databases = 4096,
5066d9ea5620SAndrew Lunn 		.num_macs = 8192,
5067fad09c73SVivien Didelot 		.num_ports = 7,
5068bc393155SAndrew Lunn 		.num_internal_phys = 5,
50693cf3c846SVivien Didelot 		.max_vid = 4095,
5070fad09c73SVivien Didelot 		.port_base_addr = 0x10,
50719255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5072a935c052SVivien Didelot 		.global1_addr = 0x1b,
50739069c13aSVivien Didelot 		.global2_addr = 0x1c,
5074acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5075dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5076d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5077e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5078f3645652SVivien Didelot 		.pvt = true,
5079b3e05aa1SVivien Didelot 		.multi_chip = true,
5080443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
5081b3469dd8SVivien Didelot 		.ops = &mv88e6351_ops,
5082fad09c73SVivien Didelot 	},
5083fad09c73SVivien Didelot 
5084fad09c73SVivien Didelot 	[MV88E6352] = {
5085107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352,
5086fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
5087fad09c73SVivien Didelot 		.name = "Marvell 88E6352",
5088fad09c73SVivien Didelot 		.num_databases = 4096,
5089d9ea5620SAndrew Lunn 		.num_macs = 8192,
5090fad09c73SVivien Didelot 		.num_ports = 7,
5091bc393155SAndrew Lunn 		.num_internal_phys = 5,
5092a73ccd61SBrandon Streiff 		.num_gpio = 15,
50933cf3c846SVivien Didelot 		.max_vid = 4095,
5094fad09c73SVivien Didelot 		.port_base_addr = 0x10,
50959255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5096a935c052SVivien Didelot 		.global1_addr = 0x1b,
50979069c13aSVivien Didelot 		.global2_addr = 0x1c,
5098acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5099dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5100d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5101e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5102f3645652SVivien Didelot 		.pvt = true,
5103b3e05aa1SVivien Didelot 		.multi_chip = true,
5104443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
51052fa8d3afSBrandon Streiff 		.ptp_support = true,
5106b3469dd8SVivien Didelot 		.ops = &mv88e6352_ops,
5107fad09c73SVivien Didelot 	},
51081a3b39ecSAndrew Lunn 	[MV88E6390] = {
5109107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
51101a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
51111a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390",
51121a3b39ecSAndrew Lunn 		.num_databases = 4096,
5113d9ea5620SAndrew Lunn 		.num_macs = 16384,
51141a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
511595150f29SHeiner Kallweit 		.num_internal_phys = 9,
5116a73ccd61SBrandon Streiff 		.num_gpio = 16,
5117931d1822SVivien Didelot 		.max_vid = 8191,
51181a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
51199255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
51201a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
51219069c13aSVivien Didelot 		.global2_addr = 0x1c,
5122b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
51231a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5124d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5125e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5126f3645652SVivien Didelot 		.pvt = true,
5127b3e05aa1SVivien Didelot 		.multi_chip = true,
5128443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
51292fa8d3afSBrandon Streiff 		.ptp_support = true,
51301a3b39ecSAndrew Lunn 		.ops = &mv88e6390_ops,
51311a3b39ecSAndrew Lunn 	},
51321a3b39ecSAndrew Lunn 	[MV88E6390X] = {
5133107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X,
51341a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
51351a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390X",
51361a3b39ecSAndrew Lunn 		.num_databases = 4096,
5137d9ea5620SAndrew Lunn 		.num_macs = 16384,
51381a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
513995150f29SHeiner Kallweit 		.num_internal_phys = 9,
5140a73ccd61SBrandon Streiff 		.num_gpio = 16,
5141931d1822SVivien Didelot 		.max_vid = 8191,
51421a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
51439255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
51441a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
51459069c13aSVivien Didelot 		.global2_addr = 0x1c,
5146b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
51471a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5148d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5149e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5150f3645652SVivien Didelot 		.pvt = true,
5151b3e05aa1SVivien Didelot 		.multi_chip = true,
5152443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
51532fa8d3afSBrandon Streiff 		.ptp_support = true,
51541a3b39ecSAndrew Lunn 		.ops = &mv88e6390x_ops,
51551a3b39ecSAndrew Lunn 	},
5156fad09c73SVivien Didelot };
5157fad09c73SVivien Didelot 
5158fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
5159fad09c73SVivien Didelot {
5160fad09c73SVivien Didelot 	int i;
5161fad09c73SVivien Didelot 
5162fad09c73SVivien Didelot 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
5163fad09c73SVivien Didelot 		if (mv88e6xxx_table[i].prod_num == prod_num)
5164fad09c73SVivien Didelot 			return &mv88e6xxx_table[i];
5165fad09c73SVivien Didelot 
5166fad09c73SVivien Didelot 	return NULL;
5167fad09c73SVivien Didelot }
5168fad09c73SVivien Didelot 
5169fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
5170fad09c73SVivien Didelot {
5171fad09c73SVivien Didelot 	const struct mv88e6xxx_info *info;
51728f6345b2SVivien Didelot 	unsigned int prod_num, rev;
51738f6345b2SVivien Didelot 	u16 id;
51748f6345b2SVivien Didelot 	int err;
5175fad09c73SVivien Didelot 
5176c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5177107fcc10SVivien Didelot 	err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
5178c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
51798f6345b2SVivien Didelot 	if (err)
51808f6345b2SVivien Didelot 		return err;
5181fad09c73SVivien Didelot 
5182107fcc10SVivien Didelot 	prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK;
5183107fcc10SVivien Didelot 	rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK;
5184fad09c73SVivien Didelot 
5185fad09c73SVivien Didelot 	info = mv88e6xxx_lookup_info(prod_num);
5186fad09c73SVivien Didelot 	if (!info)
5187fad09c73SVivien Didelot 		return -ENODEV;
5188fad09c73SVivien Didelot 
5189fad09c73SVivien Didelot 	/* Update the compatible info with the probed one */
5190fad09c73SVivien Didelot 	chip->info = info;
5191fad09c73SVivien Didelot 
5192ca070c10SVivien Didelot 	err = mv88e6xxx_g2_require(chip);
5193ca070c10SVivien Didelot 	if (err)
5194ca070c10SVivien Didelot 		return err;
5195ca070c10SVivien Didelot 
5196fad09c73SVivien Didelot 	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
5197fad09c73SVivien Didelot 		 chip->info->prod_num, chip->info->name, rev);
5198fad09c73SVivien Didelot 
5199fad09c73SVivien Didelot 	return 0;
5200fad09c73SVivien Didelot }
5201fad09c73SVivien Didelot 
5202fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
5203fad09c73SVivien Didelot {
5204fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
5205fad09c73SVivien Didelot 
5206fad09c73SVivien Didelot 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
5207fad09c73SVivien Didelot 	if (!chip)
5208fad09c73SVivien Didelot 		return NULL;
5209fad09c73SVivien Didelot 
5210fad09c73SVivien Didelot 	chip->dev = dev;
5211fad09c73SVivien Didelot 
5212fad09c73SVivien Didelot 	mutex_init(&chip->reg_lock);
5213a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&chip->mdios);
5214da7dc875SVivien Didelot 	idr_init(&chip->policies);
5215fad09c73SVivien Didelot 
5216fad09c73SVivien Didelot 	return chip;
5217fad09c73SVivien Didelot }
5218fad09c73SVivien Didelot 
52195ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
52205ed4e3ebSFlorian Fainelli 							int port)
52217b314362SAndrew Lunn {
522204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
52232bbb33beSAndrew Lunn 
5224443d5a1bSAndrew Lunn 	return chip->info->tag_protocol;
52257b314362SAndrew Lunn }
52267b314362SAndrew Lunn 
52277df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port,
52283709aadcSVivien Didelot 				      const struct switchdev_obj_port_mdb *mdb)
52297df8fbddSVivien Didelot {
52307df8fbddSVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
52317df8fbddSVivien Didelot 	 * so skip the prepare phase.
52327df8fbddSVivien Didelot 	 */
52337df8fbddSVivien Didelot 
52347df8fbddSVivien Didelot 	return 0;
52357df8fbddSVivien Didelot }
52367df8fbddSVivien Didelot 
52377df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
52383709aadcSVivien Didelot 				   const struct switchdev_obj_port_mdb *mdb)
52397df8fbddSVivien Didelot {
524004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
52417df8fbddSVivien Didelot 
5242c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
52437df8fbddSVivien Didelot 	if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
524427c0e600SVivien Didelot 					 MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC))
5245774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to load multicast MAC address\n",
5246774439e5SVivien Didelot 			port);
5247c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
52487df8fbddSVivien Didelot }
52497df8fbddSVivien Didelot 
52507df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
52517df8fbddSVivien Didelot 				  const struct switchdev_obj_port_mdb *mdb)
52527df8fbddSVivien Didelot {
525304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
52547df8fbddSVivien Didelot 	int err;
52557df8fbddSVivien Didelot 
5256c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5257d8291a95SVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0);
5258c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
52597df8fbddSVivien Didelot 
52607df8fbddSVivien Didelot 	return err;
52617df8fbddSVivien Didelot }
52627df8fbddSVivien Didelot 
5263f0942e00SIwan R Timmer static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
5264f0942e00SIwan R Timmer 				     struct dsa_mall_mirror_tc_entry *mirror,
5265f0942e00SIwan R Timmer 				     bool ingress)
5266f0942e00SIwan R Timmer {
5267f0942e00SIwan R Timmer 	enum mv88e6xxx_egress_direction direction = ingress ?
5268f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS :
5269f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS;
5270f0942e00SIwan R Timmer 	struct mv88e6xxx_chip *chip = ds->priv;
5271f0942e00SIwan R Timmer 	bool other_mirrors = false;
5272f0942e00SIwan R Timmer 	int i;
5273f0942e00SIwan R Timmer 	int err;
5274f0942e00SIwan R Timmer 
5275f0942e00SIwan R Timmer 	if (!chip->info->ops->set_egress_port)
5276f0942e00SIwan R Timmer 		return -EOPNOTSUPP;
5277f0942e00SIwan R Timmer 
5278f0942e00SIwan R Timmer 	mutex_lock(&chip->reg_lock);
5279f0942e00SIwan R Timmer 	if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
5280f0942e00SIwan R Timmer 	    mirror->to_local_port) {
5281f0942e00SIwan R Timmer 		for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
5282f0942e00SIwan R Timmer 			other_mirrors |= ingress ?
5283f0942e00SIwan R Timmer 					 chip->ports[i].mirror_ingress :
5284f0942e00SIwan R Timmer 					 chip->ports[i].mirror_egress;
5285f0942e00SIwan R Timmer 
5286f0942e00SIwan R Timmer 		/* Can't change egress port when other mirror is active */
5287f0942e00SIwan R Timmer 		if (other_mirrors) {
5288f0942e00SIwan R Timmer 			err = -EBUSY;
5289f0942e00SIwan R Timmer 			goto out;
5290f0942e00SIwan R Timmer 		}
5291f0942e00SIwan R Timmer 
5292f0942e00SIwan R Timmer 		err = chip->info->ops->set_egress_port(chip,
5293f0942e00SIwan R Timmer 						       direction,
5294f0942e00SIwan R Timmer 						       mirror->to_local_port);
5295f0942e00SIwan R Timmer 		if (err)
5296f0942e00SIwan R Timmer 			goto out;
5297f0942e00SIwan R Timmer 	}
5298f0942e00SIwan R Timmer 
5299f0942e00SIwan R Timmer 	err = mv88e6xxx_port_set_mirror(chip, port, direction, true);
5300f0942e00SIwan R Timmer out:
5301f0942e00SIwan R Timmer 	mutex_unlock(&chip->reg_lock);
5302f0942e00SIwan R Timmer 
5303f0942e00SIwan R Timmer 	return err;
5304f0942e00SIwan R Timmer }
5305f0942e00SIwan R Timmer 
5306f0942e00SIwan R Timmer static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
5307f0942e00SIwan R Timmer 				      struct dsa_mall_mirror_tc_entry *mirror)
5308f0942e00SIwan R Timmer {
5309f0942e00SIwan R Timmer 	enum mv88e6xxx_egress_direction direction = mirror->ingress ?
5310f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS :
5311f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS;
5312f0942e00SIwan R Timmer 	struct mv88e6xxx_chip *chip = ds->priv;
5313f0942e00SIwan R Timmer 	bool other_mirrors = false;
5314f0942e00SIwan R Timmer 	int i;
5315f0942e00SIwan R Timmer 
5316f0942e00SIwan R Timmer 	mutex_lock(&chip->reg_lock);
5317f0942e00SIwan R Timmer 	if (mv88e6xxx_port_set_mirror(chip, port, direction, false))
5318f0942e00SIwan R Timmer 		dev_err(ds->dev, "p%d: failed to disable mirroring\n", port);
5319f0942e00SIwan R Timmer 
5320f0942e00SIwan R Timmer 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
5321f0942e00SIwan R Timmer 		other_mirrors |= mirror->ingress ?
5322f0942e00SIwan R Timmer 				 chip->ports[i].mirror_ingress :
5323f0942e00SIwan R Timmer 				 chip->ports[i].mirror_egress;
5324f0942e00SIwan R Timmer 
5325f0942e00SIwan R Timmer 	/* Reset egress port when no other mirror is active */
5326f0942e00SIwan R Timmer 	if (!other_mirrors) {
5327f0942e00SIwan R Timmer 		if (chip->info->ops->set_egress_port(chip,
5328f0942e00SIwan R Timmer 						     direction,
5329f0942e00SIwan R Timmer 						     dsa_upstream_port(ds,
53304e4637b1SColin Ian King 								       port)))
5331f0942e00SIwan R Timmer 			dev_err(ds->dev, "failed to set egress port\n");
5332f0942e00SIwan R Timmer 	}
5333f0942e00SIwan R Timmer 
5334f0942e00SIwan R Timmer 	mutex_unlock(&chip->reg_lock);
5335f0942e00SIwan R Timmer }
5336f0942e00SIwan R Timmer 
53374f85901fSRussell King static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
53384f85901fSRussell King 					 bool unicast, bool multicast)
53394f85901fSRussell King {
53404f85901fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
53414f85901fSRussell King 	int err = -EOPNOTSUPP;
53424f85901fSRussell King 
5343c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
53444f85901fSRussell King 	if (chip->info->ops->port_set_egress_floods)
53454f85901fSRussell King 		err = chip->info->ops->port_set_egress_floods(chip, port,
53464f85901fSRussell King 							      unicast,
53474f85901fSRussell King 							      multicast);
5348c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
53494f85901fSRussell King 
53504f85901fSRussell King 	return err;
53514f85901fSRussell King }
53524f85901fSRussell King 
5353a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
53547b314362SAndrew Lunn 	.get_tag_protocol	= mv88e6xxx_get_tag_protocol,
5355fad09c73SVivien Didelot 	.setup			= mv88e6xxx_setup,
535623e8b470SAndrew Lunn 	.teardown		= mv88e6xxx_teardown,
5357c9a2356fSRussell King 	.phylink_validate	= mv88e6xxx_validate,
5358c9a2356fSRussell King 	.phylink_mac_link_state	= mv88e6xxx_link_state,
5359c9a2356fSRussell King 	.phylink_mac_config	= mv88e6xxx_mac_config,
5360c9a2356fSRussell King 	.phylink_mac_link_down	= mv88e6xxx_mac_link_down,
5361c9a2356fSRussell King 	.phylink_mac_link_up	= mv88e6xxx_mac_link_up,
5362fad09c73SVivien Didelot 	.get_strings		= mv88e6xxx_get_strings,
5363fad09c73SVivien Didelot 	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
5364fad09c73SVivien Didelot 	.get_sset_count		= mv88e6xxx_get_sset_count,
536504aca993SAndrew Lunn 	.port_enable		= mv88e6xxx_port_enable,
536604aca993SAndrew Lunn 	.port_disable		= mv88e6xxx_port_disable,
536708f50061SVivien Didelot 	.get_mac_eee		= mv88e6xxx_get_mac_eee,
536808f50061SVivien Didelot 	.set_mac_eee		= mv88e6xxx_set_mac_eee,
5369fad09c73SVivien Didelot 	.get_eeprom_len		= mv88e6xxx_get_eeprom_len,
5370fad09c73SVivien Didelot 	.get_eeprom		= mv88e6xxx_get_eeprom,
5371fad09c73SVivien Didelot 	.set_eeprom		= mv88e6xxx_set_eeprom,
5372fad09c73SVivien Didelot 	.get_regs_len		= mv88e6xxx_get_regs_len,
5373fad09c73SVivien Didelot 	.get_regs		= mv88e6xxx_get_regs,
5374da7dc875SVivien Didelot 	.get_rxnfc		= mv88e6xxx_get_rxnfc,
5375da7dc875SVivien Didelot 	.set_rxnfc		= mv88e6xxx_set_rxnfc,
53762cfcd964SVivien Didelot 	.set_ageing_time	= mv88e6xxx_set_ageing_time,
5377fad09c73SVivien Didelot 	.port_bridge_join	= mv88e6xxx_port_bridge_join,
5378fad09c73SVivien Didelot 	.port_bridge_leave	= mv88e6xxx_port_bridge_leave,
53794f85901fSRussell King 	.port_egress_floods	= mv88e6xxx_port_egress_floods,
5380fad09c73SVivien Didelot 	.port_stp_state_set	= mv88e6xxx_port_stp_state_set,
5381749efcb8SVivien Didelot 	.port_fast_age		= mv88e6xxx_port_fast_age,
5382fad09c73SVivien Didelot 	.port_vlan_filtering	= mv88e6xxx_port_vlan_filtering,
5383fad09c73SVivien Didelot 	.port_vlan_prepare	= mv88e6xxx_port_vlan_prepare,
5384fad09c73SVivien Didelot 	.port_vlan_add		= mv88e6xxx_port_vlan_add,
5385fad09c73SVivien Didelot 	.port_vlan_del		= mv88e6xxx_port_vlan_del,
5386fad09c73SVivien Didelot 	.port_fdb_add           = mv88e6xxx_port_fdb_add,
5387fad09c73SVivien Didelot 	.port_fdb_del           = mv88e6xxx_port_fdb_del,
5388fad09c73SVivien Didelot 	.port_fdb_dump          = mv88e6xxx_port_fdb_dump,
53897df8fbddSVivien Didelot 	.port_mdb_prepare       = mv88e6xxx_port_mdb_prepare,
53907df8fbddSVivien Didelot 	.port_mdb_add           = mv88e6xxx_port_mdb_add,
53917df8fbddSVivien Didelot 	.port_mdb_del           = mv88e6xxx_port_mdb_del,
5392f0942e00SIwan R Timmer 	.port_mirror_add	= mv88e6xxx_port_mirror_add,
5393f0942e00SIwan R Timmer 	.port_mirror_del	= mv88e6xxx_port_mirror_del,
5394aec5ac88SVivien Didelot 	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
5395aec5ac88SVivien Didelot 	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
5396c6fe0ad2SBrandon Streiff 	.port_hwtstamp_set	= mv88e6xxx_port_hwtstamp_set,
5397c6fe0ad2SBrandon Streiff 	.port_hwtstamp_get	= mv88e6xxx_port_hwtstamp_get,
5398c6fe0ad2SBrandon Streiff 	.port_txtstamp		= mv88e6xxx_port_txtstamp,
5399c6fe0ad2SBrandon Streiff 	.port_rxtstamp		= mv88e6xxx_port_rxtstamp,
5400c6fe0ad2SBrandon Streiff 	.get_ts_info		= mv88e6xxx_get_ts_info,
540123e8b470SAndrew Lunn 	.devlink_param_get	= mv88e6xxx_devlink_param_get,
540223e8b470SAndrew Lunn 	.devlink_param_set	= mv88e6xxx_devlink_param_set,
5403fad09c73SVivien Didelot };
5404fad09c73SVivien Didelot 
540555ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
5406fad09c73SVivien Didelot {
5407fad09c73SVivien Didelot 	struct device *dev = chip->dev;
5408fad09c73SVivien Didelot 	struct dsa_switch *ds;
5409fad09c73SVivien Didelot 
54107e99e347SVivien Didelot 	ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
5411fad09c73SVivien Didelot 	if (!ds)
5412fad09c73SVivien Didelot 		return -ENOMEM;
5413fad09c73SVivien Didelot 
54147e99e347SVivien Didelot 	ds->dev = dev;
54157e99e347SVivien Didelot 	ds->num_ports = mv88e6xxx_num_ports(chip);
5416fad09c73SVivien Didelot 	ds->priv = chip;
5417877b7cb0SAndrew Lunn 	ds->dev = dev;
54189d490b4eSVivien Didelot 	ds->ops = &mv88e6xxx_switch_ops;
54199ff74f24SVivien Didelot 	ds->ageing_time_min = chip->info->age_time_coeff;
54209ff74f24SVivien Didelot 	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
5421fad09c73SVivien Didelot 
5422fad09c73SVivien Didelot 	dev_set_drvdata(dev, ds);
5423fad09c73SVivien Didelot 
542423c9ee49SVivien Didelot 	return dsa_register_switch(ds);
5425fad09c73SVivien Didelot }
5426fad09c73SVivien Didelot 
5427fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
5428fad09c73SVivien Didelot {
5429fad09c73SVivien Didelot 	dsa_unregister_switch(chip->ds);
5430fad09c73SVivien Didelot }
5431fad09c73SVivien Didelot 
5432877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev)
5433877b7cb0SAndrew Lunn {
5434877b7cb0SAndrew Lunn 	const struct of_device_id *matches = dev->driver->of_match_table;
5435877b7cb0SAndrew Lunn 	const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data;
5436877b7cb0SAndrew Lunn 
5437877b7cb0SAndrew Lunn 	for (; matches->name[0] || matches->type[0] || matches->compatible[0];
5438877b7cb0SAndrew Lunn 	     matches++) {
5439877b7cb0SAndrew Lunn 		if (!strcmp(pdata->compatible, matches->compatible))
5440877b7cb0SAndrew Lunn 			return matches->data;
5441877b7cb0SAndrew Lunn 	}
5442877b7cb0SAndrew Lunn 	return NULL;
5443877b7cb0SAndrew Lunn }
5444877b7cb0SAndrew Lunn 
5445bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration
5446bcd3d9d9SMiquel Raynal  * would be lost after a power cycle so prevent it to be suspended.
5447bcd3d9d9SMiquel Raynal  */
5448bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev)
5449bcd3d9d9SMiquel Raynal {
5450bcd3d9d9SMiquel Raynal 	return -EOPNOTSUPP;
5451bcd3d9d9SMiquel Raynal }
5452bcd3d9d9SMiquel Raynal 
5453bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev)
5454bcd3d9d9SMiquel Raynal {
5455bcd3d9d9SMiquel Raynal 	return 0;
5456bcd3d9d9SMiquel Raynal }
5457bcd3d9d9SMiquel Raynal 
5458bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume);
5459bcd3d9d9SMiquel Raynal 
5460fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev)
5461fad09c73SVivien Didelot {
5462877b7cb0SAndrew Lunn 	struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data;
54637ddae24fSDavid S. Miller 	const struct mv88e6xxx_info *compat_info = NULL;
5464fad09c73SVivien Didelot 	struct device *dev = &mdiodev->dev;
5465fad09c73SVivien Didelot 	struct device_node *np = dev->of_node;
5466fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
5467877b7cb0SAndrew Lunn 	int port;
5468fad09c73SVivien Didelot 	int err;
5469fad09c73SVivien Didelot 
54707bb8c996SAndrew Lunn 	if (!np && !pdata)
54717bb8c996SAndrew Lunn 		return -EINVAL;
54727bb8c996SAndrew Lunn 
5473877b7cb0SAndrew Lunn 	if (np)
5474fad09c73SVivien Didelot 		compat_info = of_device_get_match_data(dev);
5475877b7cb0SAndrew Lunn 
5476877b7cb0SAndrew Lunn 	if (pdata) {
5477877b7cb0SAndrew Lunn 		compat_info = pdata_device_get_match_data(dev);
5478877b7cb0SAndrew Lunn 
5479877b7cb0SAndrew Lunn 		if (!pdata->netdev)
5480877b7cb0SAndrew Lunn 			return -EINVAL;
5481877b7cb0SAndrew Lunn 
5482877b7cb0SAndrew Lunn 		for (port = 0; port < DSA_MAX_PORTS; port++) {
5483877b7cb0SAndrew Lunn 			if (!(pdata->enabled_ports & (1 << port)))
5484877b7cb0SAndrew Lunn 				continue;
5485877b7cb0SAndrew Lunn 			if (strcmp(pdata->cd.port_names[port], "cpu"))
5486877b7cb0SAndrew Lunn 				continue;
5487877b7cb0SAndrew Lunn 			pdata->cd.netdev[port] = &pdata->netdev->dev;
5488877b7cb0SAndrew Lunn 			break;
5489877b7cb0SAndrew Lunn 		}
5490877b7cb0SAndrew Lunn 	}
5491877b7cb0SAndrew Lunn 
5492fad09c73SVivien Didelot 	if (!compat_info)
5493fad09c73SVivien Didelot 		return -EINVAL;
5494fad09c73SVivien Didelot 
5495fad09c73SVivien Didelot 	chip = mv88e6xxx_alloc_chip(dev);
5496877b7cb0SAndrew Lunn 	if (!chip) {
5497877b7cb0SAndrew Lunn 		err = -ENOMEM;
5498877b7cb0SAndrew Lunn 		goto out;
5499877b7cb0SAndrew Lunn 	}
5500fad09c73SVivien Didelot 
5501fad09c73SVivien Didelot 	chip->info = compat_info;
5502fad09c73SVivien Didelot 
5503fad09c73SVivien Didelot 	err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
5504fad09c73SVivien Didelot 	if (err)
5505877b7cb0SAndrew Lunn 		goto out;
5506fad09c73SVivien Didelot 
5507b4308f04SAndrew Lunn 	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
5508877b7cb0SAndrew Lunn 	if (IS_ERR(chip->reset)) {
5509877b7cb0SAndrew Lunn 		err = PTR_ERR(chip->reset);
5510877b7cb0SAndrew Lunn 		goto out;
5511877b7cb0SAndrew Lunn 	}
55127b75e49dSBaruch Siach 	if (chip->reset)
55137b75e49dSBaruch Siach 		usleep_range(1000, 2000);
5514b4308f04SAndrew Lunn 
5515fad09c73SVivien Didelot 	err = mv88e6xxx_detect(chip);
5516fad09c73SVivien Didelot 	if (err)
5517877b7cb0SAndrew Lunn 		goto out;
5518fad09c73SVivien Didelot 
5519e57e5e77SVivien Didelot 	mv88e6xxx_phy_init(chip);
5520e57e5e77SVivien Didelot 
552100baabe5SAndrew Lunn 	if (chip->info->ops->get_eeprom) {
552200baabe5SAndrew Lunn 		if (np)
552300baabe5SAndrew Lunn 			of_property_read_u32(np, "eeprom-length",
552400baabe5SAndrew Lunn 					     &chip->eeprom_len);
552500baabe5SAndrew Lunn 		else
552600baabe5SAndrew Lunn 			chip->eeprom_len = pdata->eeprom_len;
552700baabe5SAndrew Lunn 	}
5528fad09c73SVivien Didelot 
5529c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5530dc30c35bSAndrew Lunn 	err = mv88e6xxx_switch_reset(chip);
5531c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
5532fad09c73SVivien Didelot 	if (err)
5533dc30c35bSAndrew Lunn 		goto out;
5534fad09c73SVivien Didelot 
5535a27415deSAndrew Lunn 	if (np) {
5536dc30c35bSAndrew Lunn 		chip->irq = of_irq_get(np, 0);
5537dc30c35bSAndrew Lunn 		if (chip->irq == -EPROBE_DEFER) {
5538dc30c35bSAndrew Lunn 			err = chip->irq;
5539dc30c35bSAndrew Lunn 			goto out;
5540fad09c73SVivien Didelot 		}
5541a27415deSAndrew Lunn 	}
5542a27415deSAndrew Lunn 
5543a27415deSAndrew Lunn 	if (pdata)
5544a27415deSAndrew Lunn 		chip->irq = pdata->irq;
5545fad09c73SVivien Didelot 
5546294d711eSAndrew Lunn 	/* Has to be performed before the MDIO bus is created, because
5547a708767eSUwe Kleine-König 	 * the PHYs will link their interrupts to these interrupt
5548294d711eSAndrew Lunn 	 * controllers
5549dc30c35bSAndrew Lunn 	 */
5550c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5551294d711eSAndrew Lunn 	if (chip->irq > 0)
5552dc30c35bSAndrew Lunn 		err = mv88e6xxx_g1_irq_setup(chip);
5553294d711eSAndrew Lunn 	else
5554294d711eSAndrew Lunn 		err = mv88e6xxx_irq_poll_setup(chip);
5555c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
5556dc30c35bSAndrew Lunn 
5557dc30c35bSAndrew Lunn 	if (err)
5558dc30c35bSAndrew Lunn 		goto out;
5559dc30c35bSAndrew Lunn 
5560d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0) {
5561dc30c35bSAndrew Lunn 		err = mv88e6xxx_g2_irq_setup(chip);
5562dc30c35bSAndrew Lunn 		if (err)
5563dc30c35bSAndrew Lunn 			goto out_g1_irq;
5564dc30c35bSAndrew Lunn 	}
55650977644cSAndrew Lunn 
55660977644cSAndrew Lunn 	err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
55670977644cSAndrew Lunn 	if (err)
55680977644cSAndrew Lunn 		goto out_g2_irq;
556962eb1162SAndrew Lunn 
557062eb1162SAndrew Lunn 	err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
557162eb1162SAndrew Lunn 	if (err)
557262eb1162SAndrew Lunn 		goto out_g1_atu_prob_irq;
5573dc30c35bSAndrew Lunn 
5574a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdios_register(chip, np);
5575dc30c35bSAndrew Lunn 	if (err)
557662eb1162SAndrew Lunn 		goto out_g1_vtu_prob_irq;
5577dc30c35bSAndrew Lunn 
557855ed0ce0SFlorian Fainelli 	err = mv88e6xxx_register_switch(chip);
5579dc30c35bSAndrew Lunn 	if (err)
5580dc30c35bSAndrew Lunn 		goto out_mdio;
5581dc30c35bSAndrew Lunn 
5582fad09c73SVivien Didelot 	return 0;
5583dc30c35bSAndrew Lunn 
5584dc30c35bSAndrew Lunn out_mdio:
5585a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
558662eb1162SAndrew Lunn out_g1_vtu_prob_irq:
558762eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
55880977644cSAndrew Lunn out_g1_atu_prob_irq:
55890977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
5590dc30c35bSAndrew Lunn out_g2_irq:
5591294d711eSAndrew Lunn 	if (chip->info->g2_irqs > 0)
5592dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
5593dc30c35bSAndrew Lunn out_g1_irq:
5594294d711eSAndrew Lunn 	if (chip->irq > 0)
5595dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
5596294d711eSAndrew Lunn 	else
5597294d711eSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
5598dc30c35bSAndrew Lunn out:
5599877b7cb0SAndrew Lunn 	if (pdata)
5600877b7cb0SAndrew Lunn 		dev_put(pdata->netdev);
5601877b7cb0SAndrew Lunn 
5602dc30c35bSAndrew Lunn 	return err;
5603fad09c73SVivien Didelot }
5604fad09c73SVivien Didelot 
5605fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev)
5606fad09c73SVivien Didelot {
5607fad09c73SVivien Didelot 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
560804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
5609fad09c73SVivien Didelot 
5610c6fe0ad2SBrandon Streiff 	if (chip->info->ptp_support) {
5611c6fe0ad2SBrandon Streiff 		mv88e6xxx_hwtstamp_free(chip);
56122fa8d3afSBrandon Streiff 		mv88e6xxx_ptp_free(chip);
5613c6fe0ad2SBrandon Streiff 	}
56142fa8d3afSBrandon Streiff 
5615930188ceSAndrew Lunn 	mv88e6xxx_phy_destroy(chip);
5616fad09c73SVivien Didelot 	mv88e6xxx_unregister_switch(chip);
5617a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
5618dc30c35bSAndrew Lunn 
561962eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
56200977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
562176f38f1fSAndrew Lunn 
5622d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0)
5623dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
562476f38f1fSAndrew Lunn 
562576f38f1fSAndrew Lunn 	if (chip->irq > 0)
5626dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
562776f38f1fSAndrew Lunn 	else
562876f38f1fSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
5629fad09c73SVivien Didelot }
5630fad09c73SVivien Didelot 
5631fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = {
5632fad09c73SVivien Didelot 	{
5633fad09c73SVivien Didelot 		.compatible = "marvell,mv88e6085",
5634fad09c73SVivien Didelot 		.data = &mv88e6xxx_table[MV88E6085],
5635fad09c73SVivien Didelot 	},
56361a3b39ecSAndrew Lunn 	{
56371a3b39ecSAndrew Lunn 		.compatible = "marvell,mv88e6190",
56381a3b39ecSAndrew Lunn 		.data = &mv88e6xxx_table[MV88E6190],
56391a3b39ecSAndrew Lunn 	},
56401f71836fSRasmus Villemoes 	{
56411f71836fSRasmus Villemoes 		.compatible = "marvell,mv88e6250",
56421f71836fSRasmus Villemoes 		.data = &mv88e6xxx_table[MV88E6250],
56431f71836fSRasmus Villemoes 	},
5644fad09c73SVivien Didelot 	{ /* sentinel */ },
5645fad09c73SVivien Didelot };
5646fad09c73SVivien Didelot 
5647fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);
5648fad09c73SVivien Didelot 
5649fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = {
5650fad09c73SVivien Didelot 	.probe	= mv88e6xxx_probe,
5651fad09c73SVivien Didelot 	.remove = mv88e6xxx_remove,
5652fad09c73SVivien Didelot 	.mdiodrv.driver = {
5653fad09c73SVivien Didelot 		.name = "mv88e6085",
5654fad09c73SVivien Didelot 		.of_match_table = mv88e6xxx_of_match,
5655bcd3d9d9SMiquel Raynal 		.pm = &mv88e6xxx_pm_ops,
5656fad09c73SVivien Didelot 	},
5657fad09c73SVivien Didelot };
5658fad09c73SVivien Didelot 
56597324d50eSAndrew Lunn mdio_module_driver(mv88e6xxx_driver);
5660fad09c73SVivien Didelot 
5661fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
5662fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
5663fad09c73SVivien Didelot MODULE_LICENSE("GPL");
5664