xref: /openbmc/linux/drivers/net/dsa/mv88e6xxx/chip.c (revision 65144067)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2fad09c73SVivien Didelot /*
3fad09c73SVivien Didelot  * Marvell 88e6xxx Ethernet switch single-chip support
4fad09c73SVivien Didelot  *
5fad09c73SVivien Didelot  * Copyright (c) 2008 Marvell Semiconductor
6fad09c73SVivien Didelot  *
7fad09c73SVivien Didelot  * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
8fad09c73SVivien Didelot  *
94333d619SVivien Didelot  * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
104333d619SVivien Didelot  *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
11fad09c73SVivien Didelot  */
12fad09c73SVivien Didelot 
1319fb7f69SVivien Didelot #include <linux/bitfield.h>
14fad09c73SVivien Didelot #include <linux/delay.h>
155bded825SVladimir Oltean #include <linux/dsa/mv88e6xxx.h>
16fad09c73SVivien Didelot #include <linux/etherdevice.h>
17fad09c73SVivien Didelot #include <linux/ethtool.h>
18fad09c73SVivien Didelot #include <linux/if_bridge.h>
19dc30c35bSAndrew Lunn #include <linux/interrupt.h>
20dc30c35bSAndrew Lunn #include <linux/irq.h>
21dc30c35bSAndrew Lunn #include <linux/irqdomain.h>
22fad09c73SVivien Didelot #include <linux/jiffies.h>
23fad09c73SVivien Didelot #include <linux/list.h>
24fad09c73SVivien Didelot #include <linux/mdio.h>
25fad09c73SVivien Didelot #include <linux/module.h>
26fad09c73SVivien Didelot #include <linux/of_device.h>
27dc30c35bSAndrew Lunn #include <linux/of_irq.h>
28fad09c73SVivien Didelot #include <linux/of_mdio.h>
29877b7cb0SAndrew Lunn #include <linux/platform_data/mv88e6xxx.h>
30fad09c73SVivien Didelot #include <linux/netdevice.h>
31fad09c73SVivien Didelot #include <linux/gpio/consumer.h>
32c9a2356fSRussell King #include <linux/phylink.h>
33fad09c73SVivien Didelot #include <net/dsa.h>
34ec561276SVivien Didelot 
354d5f2ba7SVivien Didelot #include "chip.h"
369dd43aa2SAndrew Lunn #include "devlink.h"
37a935c052SVivien Didelot #include "global1.h"
38ec561276SVivien Didelot #include "global2.h"
39c6fe0ad2SBrandon Streiff #include "hwtstamp.h"
4010fa5bfcSAndrew Lunn #include "phy.h"
4118abed21SVivien Didelot #include "port.h"
422fa8d3afSBrandon Streiff #include "ptp.h"
436d91782fSAndrew Lunn #include "serdes.h"
44e7ba0fadSVivien Didelot #include "smi.h"
45fad09c73SVivien Didelot 
46fad09c73SVivien Didelot static void assert_reg_lock(struct mv88e6xxx_chip *chip)
47fad09c73SVivien Didelot {
48fad09c73SVivien Didelot 	if (unlikely(!mutex_is_locked(&chip->reg_lock))) {
49fad09c73SVivien Didelot 		dev_err(chip->dev, "Switch registers lock not held!\n");
50fad09c73SVivien Didelot 		dump_stack();
51fad09c73SVivien Didelot 	}
52fad09c73SVivien Didelot }
53fad09c73SVivien Didelot 
54ec561276SVivien Didelot int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
55fad09c73SVivien Didelot {
56fad09c73SVivien Didelot 	int err;
57fad09c73SVivien Didelot 
58fad09c73SVivien Didelot 	assert_reg_lock(chip);
59fad09c73SVivien Didelot 
60fad09c73SVivien Didelot 	err = mv88e6xxx_smi_read(chip, addr, reg, val);
61fad09c73SVivien Didelot 	if (err)
62fad09c73SVivien Didelot 		return err;
63fad09c73SVivien Didelot 
64fad09c73SVivien Didelot 	dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
65fad09c73SVivien Didelot 		addr, reg, *val);
66fad09c73SVivien Didelot 
67fad09c73SVivien Didelot 	return 0;
68fad09c73SVivien Didelot }
69fad09c73SVivien Didelot 
70ec561276SVivien Didelot int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
71fad09c73SVivien Didelot {
72fad09c73SVivien Didelot 	int err;
73fad09c73SVivien Didelot 
74fad09c73SVivien Didelot 	assert_reg_lock(chip);
75fad09c73SVivien Didelot 
76fad09c73SVivien Didelot 	err = mv88e6xxx_smi_write(chip, addr, reg, val);
77fad09c73SVivien Didelot 	if (err)
78fad09c73SVivien Didelot 		return err;
79fad09c73SVivien Didelot 
80fad09c73SVivien Didelot 	dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
81fad09c73SVivien Didelot 		addr, reg, val);
82fad09c73SVivien Didelot 
83fad09c73SVivien Didelot 	return 0;
84fad09c73SVivien Didelot }
85fad09c73SVivien Didelot 
86683f2244SVivien Didelot int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg,
87683f2244SVivien Didelot 			u16 mask, u16 val)
88683f2244SVivien Didelot {
89683f2244SVivien Didelot 	u16 data;
90683f2244SVivien Didelot 	int err;
91683f2244SVivien Didelot 	int i;
92683f2244SVivien Didelot 
93683f2244SVivien Didelot 	/* There's no bus specific operation to wait for a mask */
94683f2244SVivien Didelot 	for (i = 0; i < 16; i++) {
95683f2244SVivien Didelot 		err = mv88e6xxx_read(chip, addr, reg, &data);
96683f2244SVivien Didelot 		if (err)
97683f2244SVivien Didelot 			return err;
98683f2244SVivien Didelot 
99683f2244SVivien Didelot 		if ((data & mask) == val)
100683f2244SVivien Didelot 			return 0;
101683f2244SVivien Didelot 
102683f2244SVivien Didelot 		usleep_range(1000, 2000);
103683f2244SVivien Didelot 	}
104683f2244SVivien Didelot 
105683f2244SVivien Didelot 	dev_err(chip->dev, "Timeout while waiting for switch\n");
106683f2244SVivien Didelot 	return -ETIMEDOUT;
107683f2244SVivien Didelot }
108683f2244SVivien Didelot 
10919fb7f69SVivien Didelot int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg,
11019fb7f69SVivien Didelot 		       int bit, int val)
11119fb7f69SVivien Didelot {
11219fb7f69SVivien Didelot 	return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit),
11319fb7f69SVivien Didelot 				   val ? BIT(bit) : 0x0000);
11419fb7f69SVivien Didelot }
11519fb7f69SVivien Didelot 
11610fa5bfcSAndrew Lunn struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
117a3c53be5SAndrew Lunn {
118a3c53be5SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
119a3c53be5SAndrew Lunn 
120a3c53be5SAndrew Lunn 	mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus,
121a3c53be5SAndrew Lunn 				    list);
122a3c53be5SAndrew Lunn 	if (!mdio_bus)
123a3c53be5SAndrew Lunn 		return NULL;
124a3c53be5SAndrew Lunn 
125a3c53be5SAndrew Lunn 	return mdio_bus->bus;
126a3c53be5SAndrew Lunn }
127a3c53be5SAndrew Lunn 
128dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_mask(struct irq_data *d)
129dc30c35bSAndrew Lunn {
130dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
131dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
132dc30c35bSAndrew Lunn 
133dc30c35bSAndrew Lunn 	chip->g1_irq.masked |= (1 << n);
134dc30c35bSAndrew Lunn }
135dc30c35bSAndrew Lunn 
136dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_unmask(struct irq_data *d)
137dc30c35bSAndrew Lunn {
138dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
139dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
140dc30c35bSAndrew Lunn 
141dc30c35bSAndrew Lunn 	chip->g1_irq.masked &= ~(1 << n);
142dc30c35bSAndrew Lunn }
143dc30c35bSAndrew Lunn 
144294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip)
145dc30c35bSAndrew Lunn {
146dc30c35bSAndrew Lunn 	unsigned int nhandled = 0;
147dc30c35bSAndrew Lunn 	unsigned int sub_irq;
148dc30c35bSAndrew Lunn 	unsigned int n;
149dc30c35bSAndrew Lunn 	u16 reg;
1507c0db24cSJohn David Anglin 	u16 ctl1;
151dc30c35bSAndrew Lunn 	int err;
152dc30c35bSAndrew Lunn 
153c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
15482466921SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
155c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
156dc30c35bSAndrew Lunn 
157dc30c35bSAndrew Lunn 	if (err)
158dc30c35bSAndrew Lunn 		goto out;
159dc30c35bSAndrew Lunn 
1607c0db24cSJohn David Anglin 	do {
161dc30c35bSAndrew Lunn 		for (n = 0; n < chip->g1_irq.nirqs; ++n) {
162dc30c35bSAndrew Lunn 			if (reg & (1 << n)) {
1637c0db24cSJohn David Anglin 				sub_irq = irq_find_mapping(chip->g1_irq.domain,
1647c0db24cSJohn David Anglin 							   n);
165dc30c35bSAndrew Lunn 				handle_nested_irq(sub_irq);
166dc30c35bSAndrew Lunn 				++nhandled;
167dc30c35bSAndrew Lunn 			}
168dc30c35bSAndrew Lunn 		}
1697c0db24cSJohn David Anglin 
170c9acece0SRasmus Villemoes 		mv88e6xxx_reg_lock(chip);
1717c0db24cSJohn David Anglin 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1);
1727c0db24cSJohn David Anglin 		if (err)
1737c0db24cSJohn David Anglin 			goto unlock;
1747c0db24cSJohn David Anglin 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
1757c0db24cSJohn David Anglin unlock:
176c9acece0SRasmus Villemoes 		mv88e6xxx_reg_unlock(chip);
1777c0db24cSJohn David Anglin 		if (err)
1787c0db24cSJohn David Anglin 			goto out;
1797c0db24cSJohn David Anglin 		ctl1 &= GENMASK(chip->g1_irq.nirqs, 0);
1807c0db24cSJohn David Anglin 	} while (reg & ctl1);
1817c0db24cSJohn David Anglin 
182dc30c35bSAndrew Lunn out:
183dc30c35bSAndrew Lunn 	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
184dc30c35bSAndrew Lunn }
185dc30c35bSAndrew Lunn 
186294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
187294d711eSAndrew Lunn {
188294d711eSAndrew Lunn 	struct mv88e6xxx_chip *chip = dev_id;
189294d711eSAndrew Lunn 
190294d711eSAndrew Lunn 	return mv88e6xxx_g1_irq_thread_work(chip);
191294d711eSAndrew Lunn }
192294d711eSAndrew Lunn 
193dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
194dc30c35bSAndrew Lunn {
195dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
196dc30c35bSAndrew Lunn 
197c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
198dc30c35bSAndrew Lunn }
199dc30c35bSAndrew Lunn 
200dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
201dc30c35bSAndrew Lunn {
202dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
203dc30c35bSAndrew Lunn 	u16 mask = GENMASK(chip->g1_irq.nirqs, 0);
204dc30c35bSAndrew Lunn 	u16 reg;
205dc30c35bSAndrew Lunn 	int err;
206dc30c35bSAndrew Lunn 
207d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &reg);
208dc30c35bSAndrew Lunn 	if (err)
209dc30c35bSAndrew Lunn 		goto out;
210dc30c35bSAndrew Lunn 
211dc30c35bSAndrew Lunn 	reg &= ~mask;
212dc30c35bSAndrew Lunn 	reg |= (~chip->g1_irq.masked & mask);
213dc30c35bSAndrew Lunn 
214d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg);
215dc30c35bSAndrew Lunn 	if (err)
216dc30c35bSAndrew Lunn 		goto out;
217dc30c35bSAndrew Lunn 
218dc30c35bSAndrew Lunn out:
219c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
220dc30c35bSAndrew Lunn }
221dc30c35bSAndrew Lunn 
2226eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g1_irq_chip = {
223dc30c35bSAndrew Lunn 	.name			= "mv88e6xxx-g1",
224dc30c35bSAndrew Lunn 	.irq_mask		= mv88e6xxx_g1_irq_mask,
225dc30c35bSAndrew Lunn 	.irq_unmask		= mv88e6xxx_g1_irq_unmask,
226dc30c35bSAndrew Lunn 	.irq_bus_lock		= mv88e6xxx_g1_irq_bus_lock,
227dc30c35bSAndrew Lunn 	.irq_bus_sync_unlock	= mv88e6xxx_g1_irq_bus_sync_unlock,
228dc30c35bSAndrew Lunn };
229dc30c35bSAndrew Lunn 
230dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d,
231dc30c35bSAndrew Lunn 				       unsigned int irq,
232dc30c35bSAndrew Lunn 				       irq_hw_number_t hwirq)
233dc30c35bSAndrew Lunn {
234dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = d->host_data;
235dc30c35bSAndrew Lunn 
236dc30c35bSAndrew Lunn 	irq_set_chip_data(irq, d->host_data);
237dc30c35bSAndrew Lunn 	irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq);
238dc30c35bSAndrew Lunn 	irq_set_noprobe(irq);
239dc30c35bSAndrew Lunn 
240dc30c35bSAndrew Lunn 	return 0;
241dc30c35bSAndrew Lunn }
242dc30c35bSAndrew Lunn 
243dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = {
244dc30c35bSAndrew Lunn 	.map	= mv88e6xxx_g1_irq_domain_map,
245dc30c35bSAndrew Lunn 	.xlate	= irq_domain_xlate_twocell,
246dc30c35bSAndrew Lunn };
247dc30c35bSAndrew Lunn 
2483d82475aSUwe Kleine-König /* To be called with reg_lock held */
249294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip)
250dc30c35bSAndrew Lunn {
251dc30c35bSAndrew Lunn 	int irq, virq;
2523460a577SAndrew Lunn 	u16 mask;
2533460a577SAndrew Lunn 
254d77f4321SVivien Didelot 	mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
2553d5fdba1SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
256d77f4321SVivien Didelot 	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
2573460a577SAndrew Lunn 
2585edef2f2SAndreas Färber 	for (irq = 0; irq < chip->g1_irq.nirqs; irq++) {
259a3db3d3aSAndrew Lunn 		virq = irq_find_mapping(chip->g1_irq.domain, irq);
260dc30c35bSAndrew Lunn 		irq_dispose_mapping(virq);
261dc30c35bSAndrew Lunn 	}
262dc30c35bSAndrew Lunn 
263a3db3d3aSAndrew Lunn 	irq_domain_remove(chip->g1_irq.domain);
264dc30c35bSAndrew Lunn }
265dc30c35bSAndrew Lunn 
266294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
267294d711eSAndrew Lunn {
2683d82475aSUwe Kleine-König 	/*
2693d82475aSUwe Kleine-König 	 * free_irq must be called without reg_lock taken because the irq
2703d82475aSUwe Kleine-König 	 * handler takes this lock, too.
2713d82475aSUwe Kleine-König 	 */
272294d711eSAndrew Lunn 	free_irq(chip->irq, chip);
2733d82475aSUwe Kleine-König 
274c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2753d82475aSUwe Kleine-König 	mv88e6xxx_g1_irq_free_common(chip);
276c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
277294d711eSAndrew Lunn }
278294d711eSAndrew Lunn 
279294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip)
280dc30c35bSAndrew Lunn {
2813dd0ef05SAndrew Lunn 	int err, irq, virq;
2823dd0ef05SAndrew Lunn 	u16 reg, mask;
283dc30c35bSAndrew Lunn 
284dc30c35bSAndrew Lunn 	chip->g1_irq.nirqs = chip->info->g1_irqs;
285dc30c35bSAndrew Lunn 	chip->g1_irq.domain = irq_domain_add_simple(
286dc30c35bSAndrew Lunn 		NULL, chip->g1_irq.nirqs, 0,
287dc30c35bSAndrew Lunn 		&mv88e6xxx_g1_irq_domain_ops, chip);
288dc30c35bSAndrew Lunn 	if (!chip->g1_irq.domain)
289dc30c35bSAndrew Lunn 		return -ENOMEM;
290dc30c35bSAndrew Lunn 
291dc30c35bSAndrew Lunn 	for (irq = 0; irq < chip->g1_irq.nirqs; irq++)
292dc30c35bSAndrew Lunn 		irq_create_mapping(chip->g1_irq.domain, irq);
293dc30c35bSAndrew Lunn 
294dc30c35bSAndrew Lunn 	chip->g1_irq.chip = mv88e6xxx_g1_irq_chip;
295dc30c35bSAndrew Lunn 	chip->g1_irq.masked = ~0;
296dc30c35bSAndrew Lunn 
297d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
298dc30c35bSAndrew Lunn 	if (err)
2993dd0ef05SAndrew Lunn 		goto out_mapping;
300dc30c35bSAndrew Lunn 
3013dd0ef05SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
302dc30c35bSAndrew Lunn 
303d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
304dc30c35bSAndrew Lunn 	if (err)
3053dd0ef05SAndrew Lunn 		goto out_disable;
306dc30c35bSAndrew Lunn 
307dc30c35bSAndrew Lunn 	/* Reading the interrupt status clears (most of) them */
30882466921SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
309dc30c35bSAndrew Lunn 	if (err)
3103dd0ef05SAndrew Lunn 		goto out_disable;
311dc30c35bSAndrew Lunn 
312dc30c35bSAndrew Lunn 	return 0;
313dc30c35bSAndrew Lunn 
3143dd0ef05SAndrew Lunn out_disable:
3153d5fdba1SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
316d77f4321SVivien Didelot 	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
3173dd0ef05SAndrew Lunn 
3183dd0ef05SAndrew Lunn out_mapping:
3193dd0ef05SAndrew Lunn 	for (irq = 0; irq < 16; irq++) {
3203dd0ef05SAndrew Lunn 		virq = irq_find_mapping(chip->g1_irq.domain, irq);
3213dd0ef05SAndrew Lunn 		irq_dispose_mapping(virq);
3223dd0ef05SAndrew Lunn 	}
3233dd0ef05SAndrew Lunn 
3243dd0ef05SAndrew Lunn 	irq_domain_remove(chip->g1_irq.domain);
325dc30c35bSAndrew Lunn 
326dc30c35bSAndrew Lunn 	return err;
327dc30c35bSAndrew Lunn }
328dc30c35bSAndrew Lunn 
329294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
330294d711eSAndrew Lunn {
331f6d9758bSAndrew Lunn 	static struct lock_class_key lock_key;
332f6d9758bSAndrew Lunn 	static struct lock_class_key request_key;
333294d711eSAndrew Lunn 	int err;
334294d711eSAndrew Lunn 
335294d711eSAndrew Lunn 	err = mv88e6xxx_g1_irq_setup_common(chip);
336294d711eSAndrew Lunn 	if (err)
337294d711eSAndrew Lunn 		return err;
338294d711eSAndrew Lunn 
339f6d9758bSAndrew Lunn 	/* These lock classes tells lockdep that global 1 irqs are in
340f6d9758bSAndrew Lunn 	 * a different category than their parent GPIO, so it won't
341f6d9758bSAndrew Lunn 	 * report false recursion.
342f6d9758bSAndrew Lunn 	 */
343f6d9758bSAndrew Lunn 	irq_set_lockdep_class(chip->irq, &lock_key, &request_key);
344f6d9758bSAndrew Lunn 
3453095383aSAndrew Lunn 	snprintf(chip->irq_name, sizeof(chip->irq_name),
3463095383aSAndrew Lunn 		 "mv88e6xxx-%s", dev_name(chip->dev));
3473095383aSAndrew Lunn 
348c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
349294d711eSAndrew Lunn 	err = request_threaded_irq(chip->irq, NULL,
350294d711eSAndrew Lunn 				   mv88e6xxx_g1_irq_thread_fn,
3510340376eSMarek Behún 				   IRQF_ONESHOT | IRQF_SHARED,
3523095383aSAndrew Lunn 				   chip->irq_name, chip);
353c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
354294d711eSAndrew Lunn 	if (err)
355294d711eSAndrew Lunn 		mv88e6xxx_g1_irq_free_common(chip);
356294d711eSAndrew Lunn 
357294d711eSAndrew Lunn 	return err;
358294d711eSAndrew Lunn }
359294d711eSAndrew Lunn 
360294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work)
361294d711eSAndrew Lunn {
362294d711eSAndrew Lunn 	struct mv88e6xxx_chip *chip = container_of(work,
363294d711eSAndrew Lunn 						   struct mv88e6xxx_chip,
364294d711eSAndrew Lunn 						   irq_poll_work.work);
365294d711eSAndrew Lunn 	mv88e6xxx_g1_irq_thread_work(chip);
366294d711eSAndrew Lunn 
367294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
368294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
369294d711eSAndrew Lunn }
370294d711eSAndrew Lunn 
371294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip)
372294d711eSAndrew Lunn {
373294d711eSAndrew Lunn 	int err;
374294d711eSAndrew Lunn 
375294d711eSAndrew Lunn 	err = mv88e6xxx_g1_irq_setup_common(chip);
376294d711eSAndrew Lunn 	if (err)
377294d711eSAndrew Lunn 		return err;
378294d711eSAndrew Lunn 
379294d711eSAndrew Lunn 	kthread_init_delayed_work(&chip->irq_poll_work,
380294d711eSAndrew Lunn 				  mv88e6xxx_irq_poll);
381294d711eSAndrew Lunn 
3823f8b8696SFlorian Fainelli 	chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev));
383294d711eSAndrew Lunn 	if (IS_ERR(chip->kworker))
384294d711eSAndrew Lunn 		return PTR_ERR(chip->kworker);
385294d711eSAndrew Lunn 
386294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
387294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
388294d711eSAndrew Lunn 
389294d711eSAndrew Lunn 	return 0;
390294d711eSAndrew Lunn }
391294d711eSAndrew Lunn 
392294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip)
393294d711eSAndrew Lunn {
394294d711eSAndrew Lunn 	kthread_cancel_delayed_work_sync(&chip->irq_poll_work);
395294d711eSAndrew Lunn 	kthread_destroy_worker(chip->kworker);
3963d82475aSUwe Kleine-König 
397c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3983d82475aSUwe Kleine-König 	mv88e6xxx_g1_irq_free_common(chip);
399c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
400294d711eSAndrew Lunn }
401294d711eSAndrew Lunn 
40264d47d50SRussell King static int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip,
40364d47d50SRussell King 					   int port, phy_interface_t interface)
40464d47d50SRussell King {
40564d47d50SRussell King 	int err;
40664d47d50SRussell King 
40764d47d50SRussell King 	if (chip->info->ops->port_set_rgmii_delay) {
40864d47d50SRussell King 		err = chip->info->ops->port_set_rgmii_delay(chip, port,
40964d47d50SRussell King 							    interface);
41064d47d50SRussell King 		if (err && err != -EOPNOTSUPP)
41164d47d50SRussell King 			return err;
41264d47d50SRussell King 	}
41364d47d50SRussell King 
41464d47d50SRussell King 	if (chip->info->ops->port_set_cmode) {
41564d47d50SRussell King 		err = chip->info->ops->port_set_cmode(chip, port,
41664d47d50SRussell King 						      interface);
41764d47d50SRussell King 		if (err && err != -EOPNOTSUPP)
41864d47d50SRussell King 			return err;
41964d47d50SRussell King 	}
42064d47d50SRussell King 
42164d47d50SRussell King 	return 0;
42264d47d50SRussell King }
42364d47d50SRussell King 
424a5a6858bSRussell King static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
425a5a6858bSRussell King 				    int link, int speed, int duplex, int pause,
426d78343d2SVivien Didelot 				    phy_interface_t mode)
427d78343d2SVivien Didelot {
428d78343d2SVivien Didelot 	int err;
429d78343d2SVivien Didelot 
430d78343d2SVivien Didelot 	if (!chip->info->ops->port_set_link)
431d78343d2SVivien Didelot 		return 0;
432d78343d2SVivien Didelot 
433d78343d2SVivien Didelot 	/* Port's MAC control must not be changed unless the link is down */
43443c8e0aeSHubert Feurstein 	err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN);
435d78343d2SVivien Didelot 	if (err)
436d78343d2SVivien Didelot 		return err;
437d78343d2SVivien Didelot 
438f365c6f7SRussell King 	if (chip->info->ops->port_set_speed_duplex) {
439f365c6f7SRussell King 		err = chip->info->ops->port_set_speed_duplex(chip, port,
440f365c6f7SRussell King 							     speed, duplex);
441d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
442d78343d2SVivien Didelot 			goto restore_link;
443d78343d2SVivien Didelot 	}
444d78343d2SVivien Didelot 
4457cbbee05SAndrew Lunn 	if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode)
4467cbbee05SAndrew Lunn 		mode = chip->info->ops->port_max_speed_mode(port);
4477cbbee05SAndrew Lunn 
44854186b91SAndrew Lunn 	if (chip->info->ops->port_set_pause) {
44954186b91SAndrew Lunn 		err = chip->info->ops->port_set_pause(chip, port, pause);
45054186b91SAndrew Lunn 		if (err)
45154186b91SAndrew Lunn 			goto restore_link;
45254186b91SAndrew Lunn 	}
45354186b91SAndrew Lunn 
45464d47d50SRussell King 	err = mv88e6xxx_port_config_interface(chip, port, mode);
455d78343d2SVivien Didelot restore_link:
456d78343d2SVivien Didelot 	if (chip->info->ops->port_set_link(chip, port, link))
457774439e5SVivien Didelot 		dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
458d78343d2SVivien Didelot 
459d78343d2SVivien Didelot 	return err;
460d78343d2SVivien Didelot }
461d78343d2SVivien Didelot 
462d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
463d700ec41SMarek Vasut {
464d700ec41SMarek Vasut 	struct mv88e6xxx_chip *chip = ds->priv;
465d700ec41SMarek Vasut 
466d700ec41SMarek Vasut 	return port < chip->info->num_internal_phys;
467d700ec41SMarek Vasut }
468d700ec41SMarek Vasut 
4695d5b231dSRussell King static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port)
4705d5b231dSRussell King {
4715d5b231dSRussell King 	u16 reg;
4725d5b231dSRussell King 	int err;
4735d5b231dSRussell King 
4745d5b231dSRussell King 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
4755d5b231dSRussell King 	if (err) {
4765d5b231dSRussell King 		dev_err(chip->dev,
4775d5b231dSRussell King 			"p%d: %s: failed to read port status\n",
4785d5b231dSRussell King 			port, __func__);
4795d5b231dSRussell King 		return err;
4805d5b231dSRussell King 	}
4815d5b231dSRussell King 
4825d5b231dSRussell King 	return !!(reg & MV88E6XXX_PORT_STS_PHY_DETECT);
4835d5b231dSRussell King }
4845d5b231dSRussell King 
485a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port,
486a5a6858bSRussell King 					  struct phylink_link_state *state)
487a5a6858bSRussell King {
488a5a6858bSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
489193c5b26SPavana Sharma 	int lane;
490a5a6858bSRussell King 	int err;
491a5a6858bSRussell King 
492a5a6858bSRussell King 	mv88e6xxx_reg_lock(chip);
493a5a6858bSRussell King 	lane = mv88e6xxx_serdes_get_lane(chip, port);
494193c5b26SPavana Sharma 	if (lane >= 0 && chip->info->ops->serdes_pcs_get_state)
495a5a6858bSRussell King 		err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
496a5a6858bSRussell King 							    state);
497a5a6858bSRussell King 	else
498a5a6858bSRussell King 		err = -EOPNOTSUPP;
499a5a6858bSRussell King 	mv88e6xxx_reg_unlock(chip);
500a5a6858bSRussell King 
501a5a6858bSRussell King 	return err;
502a5a6858bSRussell King }
503a5a6858bSRussell King 
504a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
505a5a6858bSRussell King 				       unsigned int mode,
506a5a6858bSRussell King 				       phy_interface_t interface,
507a5a6858bSRussell King 				       const unsigned long *advertise)
508a5a6858bSRussell King {
509a5a6858bSRussell King 	const struct mv88e6xxx_ops *ops = chip->info->ops;
510193c5b26SPavana Sharma 	int lane;
511a5a6858bSRussell King 
512a5a6858bSRussell King 	if (ops->serdes_pcs_config) {
513a5a6858bSRussell King 		lane = mv88e6xxx_serdes_get_lane(chip, port);
514193c5b26SPavana Sharma 		if (lane >= 0)
515a5a6858bSRussell King 			return ops->serdes_pcs_config(chip, port, lane, mode,
516a5a6858bSRussell King 						      interface, advertise);
517a5a6858bSRussell King 	}
518a5a6858bSRussell King 
519a5a6858bSRussell King 	return 0;
520a5a6858bSRussell King }
521a5a6858bSRussell King 
522a5a6858bSRussell King static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port)
523a5a6858bSRussell King {
524a5a6858bSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
525a5a6858bSRussell King 	const struct mv88e6xxx_ops *ops;
526a5a6858bSRussell King 	int err = 0;
527193c5b26SPavana Sharma 	int lane;
528a5a6858bSRussell King 
529a5a6858bSRussell King 	ops = chip->info->ops;
530a5a6858bSRussell King 
531a5a6858bSRussell King 	if (ops->serdes_pcs_an_restart) {
532a5a6858bSRussell King 		mv88e6xxx_reg_lock(chip);
533a5a6858bSRussell King 		lane = mv88e6xxx_serdes_get_lane(chip, port);
534193c5b26SPavana Sharma 		if (lane >= 0)
535a5a6858bSRussell King 			err = ops->serdes_pcs_an_restart(chip, port, lane);
536a5a6858bSRussell King 		mv88e6xxx_reg_unlock(chip);
537a5a6858bSRussell King 
538a5a6858bSRussell King 		if (err)
539a5a6858bSRussell King 			dev_err(ds->dev, "p%d: failed to restart AN\n", port);
540a5a6858bSRussell King 	}
541a5a6858bSRussell King }
542a5a6858bSRussell King 
543a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
544a5a6858bSRussell King 					unsigned int mode,
545a5a6858bSRussell King 					int speed, int duplex)
546a5a6858bSRussell King {
547a5a6858bSRussell King 	const struct mv88e6xxx_ops *ops = chip->info->ops;
548193c5b26SPavana Sharma 	int lane;
549a5a6858bSRussell King 
550a5a6858bSRussell King 	if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) {
551a5a6858bSRussell King 		lane = mv88e6xxx_serdes_get_lane(chip, port);
552193c5b26SPavana Sharma 		if (lane >= 0)
553a5a6858bSRussell King 			return ops->serdes_pcs_link_up(chip, port, lane,
554a5a6858bSRussell King 						       speed, duplex);
555a5a6858bSRussell King 	}
556a5a6858bSRussell King 
557a5a6858bSRussell King 	return 0;
558a5a6858bSRussell King }
559a5a6858bSRussell King 
5606c422e34SRussell King static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5616c422e34SRussell King 				       unsigned long *mask,
5626c422e34SRussell King 				       struct phylink_link_state *state)
5636c422e34SRussell King {
5646c422e34SRussell King 	if (!phy_interface_mode_is_8023z(state->interface)) {
5656c422e34SRussell King 		/* 10M and 100M are only supported in non-802.3z mode */
5666c422e34SRussell King 		phylink_set(mask, 10baseT_Half);
5676c422e34SRussell King 		phylink_set(mask, 10baseT_Full);
5686c422e34SRussell King 		phylink_set(mask, 100baseT_Half);
5696c422e34SRussell King 		phylink_set(mask, 100baseT_Full);
5706c422e34SRussell King 	}
5716c422e34SRussell King }
5726c422e34SRussell King 
5736c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5746c422e34SRussell King 				       unsigned long *mask,
5756c422e34SRussell King 				       struct phylink_link_state *state)
5766c422e34SRussell King {
5776c422e34SRussell King 	/* FIXME: if the port is in 1000Base-X mode, then it only supports
5786c422e34SRussell King 	 * 1000M FD speeds.  In this case, CMODE will indicate 5.
5796c422e34SRussell King 	 */
5806c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
5816c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
5826c422e34SRussell King 
5836c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
5846c422e34SRussell King }
5856c422e34SRussell King 
586e3af71a3SMarek Behún static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port,
587e3af71a3SMarek Behún 				       unsigned long *mask,
588e3af71a3SMarek Behún 				       struct phylink_link_state *state)
589e3af71a3SMarek Behún {
590e3af71a3SMarek Behún 	if (port >= 5)
591e3af71a3SMarek Behún 		phylink_set(mask, 2500baseX_Full);
592e3af71a3SMarek Behún 
593e3af71a3SMarek Behún 	/* No ethtool bits for 200Mbps */
594e3af71a3SMarek Behún 	phylink_set(mask, 1000baseT_Full);
595e3af71a3SMarek Behún 	phylink_set(mask, 1000baseX_Full);
596e3af71a3SMarek Behún 
597e3af71a3SMarek Behún 	mv88e6065_phylink_validate(chip, port, mask, state);
598e3af71a3SMarek Behún }
599e3af71a3SMarek Behún 
6006c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6016c422e34SRussell King 				       unsigned long *mask,
6026c422e34SRussell King 				       struct phylink_link_state *state)
6036c422e34SRussell King {
6046c422e34SRussell King 	/* No ethtool bits for 200Mbps */
6056c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
6066c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
6076c422e34SRussell King 
6086c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
6096c422e34SRussell King }
6106c422e34SRussell King 
6116c422e34SRussell King static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6126c422e34SRussell King 				       unsigned long *mask,
6136c422e34SRussell King 				       struct phylink_link_state *state)
6146c422e34SRussell King {
615ec26016bSAndrew Lunn 	if (port >= 9) {
6166c422e34SRussell King 		phylink_set(mask, 2500baseX_Full);
617ec26016bSAndrew Lunn 		phylink_set(mask, 2500baseT_Full);
618ec26016bSAndrew Lunn 	}
6196c422e34SRussell King 
6206c422e34SRussell King 	/* No ethtool bits for 200Mbps */
6216c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
6226c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
6236c422e34SRussell King 
6246c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
6256c422e34SRussell King }
6266c422e34SRussell King 
6276c422e34SRussell King static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6286c422e34SRussell King 					unsigned long *mask,
6296c422e34SRussell King 					struct phylink_link_state *state)
6306c422e34SRussell King {
6316c422e34SRussell King 	if (port >= 9) {
6326c422e34SRussell King 		phylink_set(mask, 10000baseT_Full);
6336c422e34SRussell King 		phylink_set(mask, 10000baseKR_Full);
6346c422e34SRussell King 	}
6356c422e34SRussell King 
6366c422e34SRussell King 	mv88e6390_phylink_validate(chip, port, mask, state);
6376c422e34SRussell King }
6386c422e34SRussell King 
639de776d0dSPavana Sharma static void mv88e6393x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
640de776d0dSPavana Sharma 					unsigned long *mask,
641de776d0dSPavana Sharma 					struct phylink_link_state *state)
642de776d0dSPavana Sharma {
643dc2fc9f0SMarek Behún 	bool is_6191x =
644dc2fc9f0SMarek Behún 		chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X;
645dc2fc9f0SMarek Behún 
646dc2fc9f0SMarek Behún 	if (((port == 0 || port == 9) && !is_6191x) || port == 10) {
647de776d0dSPavana Sharma 		phylink_set(mask, 10000baseT_Full);
648de776d0dSPavana Sharma 		phylink_set(mask, 10000baseKR_Full);
649de776d0dSPavana Sharma 		phylink_set(mask, 10000baseCR_Full);
650de776d0dSPavana Sharma 		phylink_set(mask, 10000baseSR_Full);
651de776d0dSPavana Sharma 		phylink_set(mask, 10000baseLR_Full);
652de776d0dSPavana Sharma 		phylink_set(mask, 10000baseLRM_Full);
653de776d0dSPavana Sharma 		phylink_set(mask, 10000baseER_Full);
654de776d0dSPavana Sharma 		phylink_set(mask, 5000baseT_Full);
655de776d0dSPavana Sharma 		phylink_set(mask, 2500baseX_Full);
656de776d0dSPavana Sharma 		phylink_set(mask, 2500baseT_Full);
657de776d0dSPavana Sharma 	}
658de776d0dSPavana Sharma 
659de776d0dSPavana Sharma 	phylink_set(mask, 1000baseT_Full);
660de776d0dSPavana Sharma 	phylink_set(mask, 1000baseX_Full);
661de776d0dSPavana Sharma 
662de776d0dSPavana Sharma 	mv88e6065_phylink_validate(chip, port, mask, state);
663de776d0dSPavana Sharma }
664de776d0dSPavana Sharma 
665c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
666c9a2356fSRussell King 			       unsigned long *supported,
667c9a2356fSRussell King 			       struct phylink_link_state *state)
668c9a2356fSRussell King {
6696c422e34SRussell King 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
6706c422e34SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
6716c422e34SRussell King 
6726c422e34SRussell King 	/* Allow all the expected bits */
6736c422e34SRussell King 	phylink_set(mask, Autoneg);
6746c422e34SRussell King 	phylink_set(mask, Pause);
6756c422e34SRussell King 	phylink_set_port_modes(mask);
6766c422e34SRussell King 
6776c422e34SRussell King 	if (chip->info->ops->phylink_validate)
6786c422e34SRussell King 		chip->info->ops->phylink_validate(chip, port, mask, state);
6796c422e34SRussell King 
6804973056cSSean Anderson 	linkmode_and(supported, supported, mask);
6814973056cSSean Anderson 	linkmode_and(state->advertising, state->advertising, mask);
6826c422e34SRussell King 
6836c422e34SRussell King 	/* We can only operate at 2500BaseX or 1000BaseX.  If requested
6846c422e34SRussell King 	 * to advertise both, only report advertising at 2500BaseX.
6856c422e34SRussell King 	 */
6866c422e34SRussell King 	phylink_helper_basex_speed(state);
687c9a2356fSRussell King }
688c9a2356fSRussell King 
689c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
690c9a2356fSRussell King 				 unsigned int mode,
691c9a2356fSRussell King 				 const struct phylink_link_state *state)
692c9a2356fSRussell King {
693c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
694fad58190SRussell King 	struct mv88e6xxx_port *p;
69564d47d50SRussell King 	int err;
696c9a2356fSRussell King 
697fad58190SRussell King 	p = &chip->ports[port];
698fad58190SRussell King 
69964d47d50SRussell King 	/* FIXME: is this the correct test? If we're in fixed mode on an
70064d47d50SRussell King 	 * internal port, why should we process this any different from
70164d47d50SRussell King 	 * PHY mode? On the other hand, the port may be automedia between
70264d47d50SRussell King 	 * an internal PHY and the serdes...
70364d47d50SRussell King 	 */
704d700ec41SMarek Vasut 	if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port))
705c9a2356fSRussell King 		return;
706c9a2356fSRussell King 
707c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
708fad58190SRussell King 	/* In inband mode, the link may come up at any time while the link
709fad58190SRussell King 	 * is not forced down. Force the link down while we reconfigure the
710fad58190SRussell King 	 * interface mode.
71164d47d50SRussell King 	 */
712fad58190SRussell King 	if (mode == MLO_AN_INBAND && p->interface != state->interface &&
713fad58190SRussell King 	    chip->info->ops->port_set_link)
714fad58190SRussell King 		chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN);
715fad58190SRussell King 
71664d47d50SRussell King 	err = mv88e6xxx_port_config_interface(chip, port, state->interface);
717a5a6858bSRussell King 	if (err && err != -EOPNOTSUPP)
718a5a6858bSRussell King 		goto err_unlock;
719a5a6858bSRussell King 
720a5a6858bSRussell King 	err = mv88e6xxx_serdes_pcs_config(chip, port, mode, state->interface,
721a5a6858bSRussell King 					  state->advertising);
722a5a6858bSRussell King 	/* FIXME: we should restart negotiation if something changed - which
723a5a6858bSRussell King 	 * is something we get if we convert to using phylinks PCS operations.
724a5a6858bSRussell King 	 */
725a5a6858bSRussell King 	if (err > 0)
726a5a6858bSRussell King 		err = 0;
727a5a6858bSRussell King 
728fad58190SRussell King 	/* Undo the forced down state above after completing configuration
729fad58190SRussell King 	 * irrespective of its state on entry, which allows the link to come up.
730fad58190SRussell King 	 */
731fad58190SRussell King 	if (mode == MLO_AN_INBAND && p->interface != state->interface &&
732fad58190SRussell King 	    chip->info->ops->port_set_link)
733fad58190SRussell King 		chip->info->ops->port_set_link(chip, port, LINK_UNFORCED);
734fad58190SRussell King 
735fad58190SRussell King 	p->interface = state->interface;
736fad58190SRussell King 
737a5a6858bSRussell King err_unlock:
738c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
739c9a2356fSRussell King 
740c9a2356fSRussell King 	if (err && err != -EOPNOTSUPP)
74164d47d50SRussell King 		dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port);
742c9a2356fSRussell King }
743c9a2356fSRussell King 
744c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
745c9a2356fSRussell King 				    unsigned int mode,
746c9a2356fSRussell King 				    phy_interface_t interface)
747c9a2356fSRussell King {
74830c4a5b0SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
74930c4a5b0SRussell King 	const struct mv88e6xxx_ops *ops;
75030c4a5b0SRussell King 	int err = 0;
75130c4a5b0SRussell King 
75230c4a5b0SRussell King 	ops = chip->info->ops;
75330c4a5b0SRussell King 
75430c4a5b0SRussell King 	mv88e6xxx_reg_lock(chip);
7554a3e0aedSMaarten Zanders 	/* Internal PHYs propagate their configuration directly to the MAC.
7564a3e0aedSMaarten Zanders 	 * External PHYs depend on whether the PPU is enabled for this port.
7574a3e0aedSMaarten Zanders 	 */
7584a3e0aedSMaarten Zanders 	if (((!mv88e6xxx_phy_is_internal(ds, port) &&
7594a3e0aedSMaarten Zanders 	      !mv88e6xxx_port_ppu_updates(chip, port)) ||
7604efe7662SChris Packham 	     mode == MLO_AN_FIXED) && ops->port_sync_link)
7614efe7662SChris Packham 		err = ops->port_sync_link(chip, port, mode, false);
76230c4a5b0SRussell King 	mv88e6xxx_reg_unlock(chip);
76330c4a5b0SRussell King 
76430c4a5b0SRussell King 	if (err)
76530c4a5b0SRussell King 		dev_err(chip->dev,
76630c4a5b0SRussell King 			"p%d: failed to force MAC link down\n", port);
76730c4a5b0SRussell King }
768c9a2356fSRussell King 
769c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
770c9a2356fSRussell King 				  unsigned int mode, phy_interface_t interface,
7715b502a7bSRussell King 				  struct phy_device *phydev,
7725b502a7bSRussell King 				  int speed, int duplex,
7735b502a7bSRussell King 				  bool tx_pause, bool rx_pause)
774c9a2356fSRussell King {
77530c4a5b0SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
77630c4a5b0SRussell King 	const struct mv88e6xxx_ops *ops;
77730c4a5b0SRussell King 	int err = 0;
77830c4a5b0SRussell King 
77930c4a5b0SRussell King 	ops = chip->info->ops;
78030c4a5b0SRussell King 
78130c4a5b0SRussell King 	mv88e6xxx_reg_lock(chip);
7824a3e0aedSMaarten Zanders 	/* Internal PHYs propagate their configuration directly to the MAC.
7834a3e0aedSMaarten Zanders 	 * External PHYs depend on whether the PPU is enabled for this port.
7844a3e0aedSMaarten Zanders 	 */
7854a3e0aedSMaarten Zanders 	if ((!mv88e6xxx_phy_is_internal(ds, port) &&
7864a3e0aedSMaarten Zanders 	     !mv88e6xxx_port_ppu_updates(chip, port)) ||
7874a3e0aedSMaarten Zanders 	    mode == MLO_AN_FIXED) {
78830c4a5b0SRussell King 		/* FIXME: for an automedia port, should we force the link
78930c4a5b0SRussell King 		 * down here - what if the link comes up due to "other" media
79030c4a5b0SRussell King 		 * while we're bringing the port up, how is the exclusivity
791a5a6858bSRussell King 		 * handled in the Marvell hardware? E.g. port 2 on 88E6390
79230c4a5b0SRussell King 		 * shared between internal PHY and Serdes.
79330c4a5b0SRussell King 		 */
794a5a6858bSRussell King 		err = mv88e6xxx_serdes_pcs_link_up(chip, port, mode, speed,
795a5a6858bSRussell King 						   duplex);
796a5a6858bSRussell King 		if (err)
797a5a6858bSRussell King 			goto error;
798a5a6858bSRussell King 
799f365c6f7SRussell King 		if (ops->port_set_speed_duplex) {
800f365c6f7SRussell King 			err = ops->port_set_speed_duplex(chip, port,
801f365c6f7SRussell King 							 speed, duplex);
80230c4a5b0SRussell King 			if (err && err != -EOPNOTSUPP)
80330c4a5b0SRussell King 				goto error;
80430c4a5b0SRussell King 		}
80530c4a5b0SRussell King 
8064efe7662SChris Packham 		if (ops->port_sync_link)
8074efe7662SChris Packham 			err = ops->port_sync_link(chip, port, mode, true);
8085d5b231dSRussell King 	}
80930c4a5b0SRussell King error:
81030c4a5b0SRussell King 	mv88e6xxx_reg_unlock(chip);
81130c4a5b0SRussell King 
81230c4a5b0SRussell King 	if (err && err != -EOPNOTSUPP)
81330c4a5b0SRussell King 		dev_err(ds->dev,
81430c4a5b0SRussell King 			"p%d: failed to configure MAC link up\n", port);
81530c4a5b0SRussell King }
816c9a2356fSRussell King 
817a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
818fad09c73SVivien Didelot {
819a605a0feSAndrew Lunn 	if (!chip->info->ops->stats_snapshot)
820a605a0feSAndrew Lunn 		return -EOPNOTSUPP;
821fad09c73SVivien Didelot 
822a605a0feSAndrew Lunn 	return chip->info->ops->stats_snapshot(chip, port);
823fad09c73SVivien Didelot }
824fad09c73SVivien Didelot 
825fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
826dfafe449SAndrew Lunn 	{ "in_good_octets",		8, 0x00, STATS_TYPE_BANK0, },
827dfafe449SAndrew Lunn 	{ "in_bad_octets",		4, 0x02, STATS_TYPE_BANK0, },
828dfafe449SAndrew Lunn 	{ "in_unicast",			4, 0x04, STATS_TYPE_BANK0, },
829dfafe449SAndrew Lunn 	{ "in_broadcasts",		4, 0x06, STATS_TYPE_BANK0, },
830dfafe449SAndrew Lunn 	{ "in_multicasts",		4, 0x07, STATS_TYPE_BANK0, },
831dfafe449SAndrew Lunn 	{ "in_pause",			4, 0x16, STATS_TYPE_BANK0, },
832dfafe449SAndrew Lunn 	{ "in_undersize",		4, 0x18, STATS_TYPE_BANK0, },
833dfafe449SAndrew Lunn 	{ "in_fragments",		4, 0x19, STATS_TYPE_BANK0, },
834dfafe449SAndrew Lunn 	{ "in_oversize",		4, 0x1a, STATS_TYPE_BANK0, },
835dfafe449SAndrew Lunn 	{ "in_jabber",			4, 0x1b, STATS_TYPE_BANK0, },
836dfafe449SAndrew Lunn 	{ "in_rx_error",		4, 0x1c, STATS_TYPE_BANK0, },
837dfafe449SAndrew Lunn 	{ "in_fcs_error",		4, 0x1d, STATS_TYPE_BANK0, },
838dfafe449SAndrew Lunn 	{ "out_octets",			8, 0x0e, STATS_TYPE_BANK0, },
839dfafe449SAndrew Lunn 	{ "out_unicast",		4, 0x10, STATS_TYPE_BANK0, },
840dfafe449SAndrew Lunn 	{ "out_broadcasts",		4, 0x13, STATS_TYPE_BANK0, },
841dfafe449SAndrew Lunn 	{ "out_multicasts",		4, 0x12, STATS_TYPE_BANK0, },
842dfafe449SAndrew Lunn 	{ "out_pause",			4, 0x15, STATS_TYPE_BANK0, },
843dfafe449SAndrew Lunn 	{ "excessive",			4, 0x11, STATS_TYPE_BANK0, },
844dfafe449SAndrew Lunn 	{ "collisions",			4, 0x1e, STATS_TYPE_BANK0, },
845dfafe449SAndrew Lunn 	{ "deferred",			4, 0x05, STATS_TYPE_BANK0, },
846dfafe449SAndrew Lunn 	{ "single",			4, 0x14, STATS_TYPE_BANK0, },
847dfafe449SAndrew Lunn 	{ "multiple",			4, 0x17, STATS_TYPE_BANK0, },
848dfafe449SAndrew Lunn 	{ "out_fcs_error",		4, 0x03, STATS_TYPE_BANK0, },
849dfafe449SAndrew Lunn 	{ "late",			4, 0x1f, STATS_TYPE_BANK0, },
850dfafe449SAndrew Lunn 	{ "hist_64bytes",		4, 0x08, STATS_TYPE_BANK0, },
851dfafe449SAndrew Lunn 	{ "hist_65_127bytes",		4, 0x09, STATS_TYPE_BANK0, },
852dfafe449SAndrew Lunn 	{ "hist_128_255bytes",		4, 0x0a, STATS_TYPE_BANK0, },
853dfafe449SAndrew Lunn 	{ "hist_256_511bytes",		4, 0x0b, STATS_TYPE_BANK0, },
854dfafe449SAndrew Lunn 	{ "hist_512_1023bytes",		4, 0x0c, STATS_TYPE_BANK0, },
855dfafe449SAndrew Lunn 	{ "hist_1024_max_bytes",	4, 0x0d, STATS_TYPE_BANK0, },
856dfafe449SAndrew Lunn 	{ "sw_in_discards",		4, 0x10, STATS_TYPE_PORT, },
857dfafe449SAndrew Lunn 	{ "sw_in_filtered",		2, 0x12, STATS_TYPE_PORT, },
858dfafe449SAndrew Lunn 	{ "sw_out_filtered",		2, 0x13, STATS_TYPE_PORT, },
859dfafe449SAndrew Lunn 	{ "in_discards",		4, 0x00, STATS_TYPE_BANK1, },
860dfafe449SAndrew Lunn 	{ "in_filtered",		4, 0x01, STATS_TYPE_BANK1, },
861dfafe449SAndrew Lunn 	{ "in_accepted",		4, 0x02, STATS_TYPE_BANK1, },
862dfafe449SAndrew Lunn 	{ "in_bad_accepted",		4, 0x03, STATS_TYPE_BANK1, },
863dfafe449SAndrew Lunn 	{ "in_good_avb_class_a",	4, 0x04, STATS_TYPE_BANK1, },
864dfafe449SAndrew Lunn 	{ "in_good_avb_class_b",	4, 0x05, STATS_TYPE_BANK1, },
865dfafe449SAndrew Lunn 	{ "in_bad_avb_class_a",		4, 0x06, STATS_TYPE_BANK1, },
866dfafe449SAndrew Lunn 	{ "in_bad_avb_class_b",		4, 0x07, STATS_TYPE_BANK1, },
867dfafe449SAndrew Lunn 	{ "tcam_counter_0",		4, 0x08, STATS_TYPE_BANK1, },
868dfafe449SAndrew Lunn 	{ "tcam_counter_1",		4, 0x09, STATS_TYPE_BANK1, },
869dfafe449SAndrew Lunn 	{ "tcam_counter_2",		4, 0x0a, STATS_TYPE_BANK1, },
870dfafe449SAndrew Lunn 	{ "tcam_counter_3",		4, 0x0b, STATS_TYPE_BANK1, },
871dfafe449SAndrew Lunn 	{ "in_da_unknown",		4, 0x0e, STATS_TYPE_BANK1, },
872dfafe449SAndrew Lunn 	{ "in_management",		4, 0x0f, STATS_TYPE_BANK1, },
873dfafe449SAndrew Lunn 	{ "out_queue_0",		4, 0x10, STATS_TYPE_BANK1, },
874dfafe449SAndrew Lunn 	{ "out_queue_1",		4, 0x11, STATS_TYPE_BANK1, },
875dfafe449SAndrew Lunn 	{ "out_queue_2",		4, 0x12, STATS_TYPE_BANK1, },
876dfafe449SAndrew Lunn 	{ "out_queue_3",		4, 0x13, STATS_TYPE_BANK1, },
877dfafe449SAndrew Lunn 	{ "out_queue_4",		4, 0x14, STATS_TYPE_BANK1, },
878dfafe449SAndrew Lunn 	{ "out_queue_5",		4, 0x15, STATS_TYPE_BANK1, },
879dfafe449SAndrew Lunn 	{ "out_queue_6",		4, 0x16, STATS_TYPE_BANK1, },
880dfafe449SAndrew Lunn 	{ "out_queue_7",		4, 0x17, STATS_TYPE_BANK1, },
881dfafe449SAndrew Lunn 	{ "out_cut_through",		4, 0x18, STATS_TYPE_BANK1, },
882dfafe449SAndrew Lunn 	{ "out_octets_a",		4, 0x1a, STATS_TYPE_BANK1, },
883dfafe449SAndrew Lunn 	{ "out_octets_b",		4, 0x1b, STATS_TYPE_BANK1, },
884dfafe449SAndrew Lunn 	{ "out_management",		4, 0x1f, STATS_TYPE_BANK1, },
885fad09c73SVivien Didelot };
886fad09c73SVivien Didelot 
887fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
888fad09c73SVivien Didelot 					    struct mv88e6xxx_hw_stat *s,
889e0d8b615SAndrew Lunn 					    int port, u16 bank1_select,
890e0d8b615SAndrew Lunn 					    u16 histogram)
891fad09c73SVivien Didelot {
892fad09c73SVivien Didelot 	u32 low;
893fad09c73SVivien Didelot 	u32 high = 0;
894dfafe449SAndrew Lunn 	u16 reg = 0;
8950e7b9925SAndrew Lunn 	int err;
896fad09c73SVivien Didelot 	u64 value;
897fad09c73SVivien Didelot 
898fad09c73SVivien Didelot 	switch (s->type) {
899dfafe449SAndrew Lunn 	case STATS_TYPE_PORT:
9000e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
9010e7b9925SAndrew Lunn 		if (err)
9026c3442f5SJisheng Zhang 			return U64_MAX;
903fad09c73SVivien Didelot 
9040e7b9925SAndrew Lunn 		low = reg;
905cda9f4aaSAndrew Lunn 		if (s->size == 4) {
9060e7b9925SAndrew Lunn 			err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
9070e7b9925SAndrew Lunn 			if (err)
9086c3442f5SJisheng Zhang 				return U64_MAX;
90984b3fd1fSRasmus Villemoes 			low |= ((u32)reg) << 16;
910fad09c73SVivien Didelot 		}
911fad09c73SVivien Didelot 		break;
912dfafe449SAndrew Lunn 	case STATS_TYPE_BANK1:
913e0d8b615SAndrew Lunn 		reg = bank1_select;
914df561f66SGustavo A. R. Silva 		fallthrough;
915dfafe449SAndrew Lunn 	case STATS_TYPE_BANK0:
916e0d8b615SAndrew Lunn 		reg |= s->reg | histogram;
9177f9ef3afSAndrew Lunn 		mv88e6xxx_g1_stats_read(chip, reg, &low);
918cda9f4aaSAndrew Lunn 		if (s->size == 8)
9197f9ef3afSAndrew Lunn 			mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
9209fc3e4dcSGustavo A. R. Silva 		break;
9219fc3e4dcSGustavo A. R. Silva 	default:
9226c3442f5SJisheng Zhang 		return U64_MAX;
923fad09c73SVivien Didelot 	}
9246e46e2d8SAndrew Lunn 	value = (((u64)high) << 32) | low;
925fad09c73SVivien Didelot 	return value;
926fad09c73SVivien Didelot }
927fad09c73SVivien Didelot 
928436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
929dfafe449SAndrew Lunn 				       uint8_t *data, int types)
930fad09c73SVivien Didelot {
931fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
932fad09c73SVivien Didelot 	int i, j;
933fad09c73SVivien Didelot 
934fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
935fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
936dfafe449SAndrew Lunn 		if (stat->type & types) {
937fad09c73SVivien Didelot 			memcpy(data + j * ETH_GSTRING_LEN, stat->string,
938fad09c73SVivien Didelot 			       ETH_GSTRING_LEN);
939fad09c73SVivien Didelot 			j++;
940fad09c73SVivien Didelot 		}
941fad09c73SVivien Didelot 	}
942436fe17dSAndrew Lunn 
943436fe17dSAndrew Lunn 	return j;
944fad09c73SVivien Didelot }
945fad09c73SVivien Didelot 
946436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
947dfafe449SAndrew Lunn 				       uint8_t *data)
948dfafe449SAndrew Lunn {
949436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
950dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_PORT);
951dfafe449SAndrew Lunn }
952dfafe449SAndrew Lunn 
9531f71836fSRasmus Villemoes static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip,
9541f71836fSRasmus Villemoes 				       uint8_t *data)
9551f71836fSRasmus Villemoes {
9561f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0);
9571f71836fSRasmus Villemoes }
9581f71836fSRasmus Villemoes 
959436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
960dfafe449SAndrew Lunn 				       uint8_t *data)
961dfafe449SAndrew Lunn {
962436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
963dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
964dfafe449SAndrew Lunn }
965dfafe449SAndrew Lunn 
96665f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = {
96765f60e45SAndrew Lunn 	"atu_member_violation",
96865f60e45SAndrew Lunn 	"atu_miss_violation",
96965f60e45SAndrew Lunn 	"atu_full_violation",
97065f60e45SAndrew Lunn 	"vtu_member_violation",
97165f60e45SAndrew Lunn 	"vtu_miss_violation",
97265f60e45SAndrew Lunn };
97365f60e45SAndrew Lunn 
97465f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data)
97565f60e45SAndrew Lunn {
97665f60e45SAndrew Lunn 	unsigned int i;
97765f60e45SAndrew Lunn 
97865f60e45SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++)
97965f60e45SAndrew Lunn 		strlcpy(data + i * ETH_GSTRING_LEN,
98065f60e45SAndrew Lunn 			mv88e6xxx_atu_vtu_stats_strings[i],
98165f60e45SAndrew Lunn 			ETH_GSTRING_LEN);
98265f60e45SAndrew Lunn }
98365f60e45SAndrew Lunn 
984dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
98589f09048SFlorian Fainelli 				  u32 stringset, uint8_t *data)
986fad09c73SVivien Didelot {
98704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
988436fe17dSAndrew Lunn 	int count = 0;
989dfafe449SAndrew Lunn 
99089f09048SFlorian Fainelli 	if (stringset != ETH_SS_STATS)
99189f09048SFlorian Fainelli 		return;
99289f09048SFlorian Fainelli 
993c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
994c6c8cd5eSAndrew Lunn 
995dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_strings)
996436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_strings(chip, data);
997436fe17dSAndrew Lunn 
998436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_strings) {
999436fe17dSAndrew Lunn 		data += count * ETH_GSTRING_LEN;
100065f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_strings(chip, port, data);
1001436fe17dSAndrew Lunn 	}
1002c6c8cd5eSAndrew Lunn 
100365f60e45SAndrew Lunn 	data += count * ETH_GSTRING_LEN;
100465f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_strings(data);
100565f60e45SAndrew Lunn 
1006c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1007dfafe449SAndrew Lunn }
1008dfafe449SAndrew Lunn 
1009dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
1010dfafe449SAndrew Lunn 					  int types)
1011dfafe449SAndrew Lunn {
1012fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
1013fad09c73SVivien Didelot 	int i, j;
1014fad09c73SVivien Didelot 
1015fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
1016fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
1017dfafe449SAndrew Lunn 		if (stat->type & types)
1018fad09c73SVivien Didelot 			j++;
1019fad09c73SVivien Didelot 	}
1020fad09c73SVivien Didelot 	return j;
1021fad09c73SVivien Didelot }
1022fad09c73SVivien Didelot 
1023dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
1024dfafe449SAndrew Lunn {
1025dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
1026dfafe449SAndrew Lunn 					      STATS_TYPE_PORT);
1027dfafe449SAndrew Lunn }
1028dfafe449SAndrew Lunn 
10291f71836fSRasmus Villemoes static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip)
10301f71836fSRasmus Villemoes {
10311f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0);
10321f71836fSRasmus Villemoes }
10331f71836fSRasmus Villemoes 
1034dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
1035dfafe449SAndrew Lunn {
1036dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
1037dfafe449SAndrew Lunn 					      STATS_TYPE_BANK1);
1038dfafe449SAndrew Lunn }
1039dfafe449SAndrew Lunn 
104089f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
1041dfafe449SAndrew Lunn {
1042dfafe449SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
1043436fe17dSAndrew Lunn 	int serdes_count = 0;
1044436fe17dSAndrew Lunn 	int count = 0;
1045dfafe449SAndrew Lunn 
104689f09048SFlorian Fainelli 	if (sset != ETH_SS_STATS)
104789f09048SFlorian Fainelli 		return 0;
104889f09048SFlorian Fainelli 
1049c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1050dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_sset_count)
1051436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_sset_count(chip);
1052436fe17dSAndrew Lunn 	if (count < 0)
1053436fe17dSAndrew Lunn 		goto out;
1054436fe17dSAndrew Lunn 
1055436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_sset_count)
1056436fe17dSAndrew Lunn 		serdes_count = chip->info->ops->serdes_get_sset_count(chip,
1057436fe17dSAndrew Lunn 								      port);
105865f60e45SAndrew Lunn 	if (serdes_count < 0) {
1059436fe17dSAndrew Lunn 		count = serdes_count;
106065f60e45SAndrew Lunn 		goto out;
106165f60e45SAndrew Lunn 	}
1062436fe17dSAndrew Lunn 	count += serdes_count;
106365f60e45SAndrew Lunn 	count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings);
106465f60e45SAndrew Lunn 
1065436fe17dSAndrew Lunn out:
1066c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1067dfafe449SAndrew Lunn 
1068436fe17dSAndrew Lunn 	return count;
1069dfafe449SAndrew Lunn }
1070dfafe449SAndrew Lunn 
1071436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1072e0d8b615SAndrew Lunn 				     uint64_t *data, int types,
1073e0d8b615SAndrew Lunn 				     u16 bank1_select, u16 histogram)
1074052f947fSAndrew Lunn {
1075052f947fSAndrew Lunn 	struct mv88e6xxx_hw_stat *stat;
1076052f947fSAndrew Lunn 	int i, j;
1077052f947fSAndrew Lunn 
1078052f947fSAndrew Lunn 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
1079052f947fSAndrew Lunn 		stat = &mv88e6xxx_hw_stats[i];
1080052f947fSAndrew Lunn 		if (stat->type & types) {
1081c9acece0SRasmus Villemoes 			mv88e6xxx_reg_lock(chip);
1082e0d8b615SAndrew Lunn 			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
1083e0d8b615SAndrew Lunn 							      bank1_select,
1084e0d8b615SAndrew Lunn 							      histogram);
1085c9acece0SRasmus Villemoes 			mv88e6xxx_reg_unlock(chip);
1086377cda13SAndrew Lunn 
1087052f947fSAndrew Lunn 			j++;
1088052f947fSAndrew Lunn 		}
1089052f947fSAndrew Lunn 	}
1090436fe17dSAndrew Lunn 	return j;
1091052f947fSAndrew Lunn }
1092052f947fSAndrew Lunn 
1093436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1094052f947fSAndrew Lunn 				     uint64_t *data)
1095052f947fSAndrew Lunn {
1096052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1097e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
109857d1ef38SVivien Didelot 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1099052f947fSAndrew Lunn }
1100052f947fSAndrew Lunn 
11011f71836fSRasmus Villemoes static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
11021f71836fSRasmus Villemoes 				     uint64_t *data)
11031f71836fSRasmus Villemoes {
11041f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0,
11051f71836fSRasmus Villemoes 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
11061f71836fSRasmus Villemoes }
11071f71836fSRasmus Villemoes 
1108436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1109052f947fSAndrew Lunn 				     uint64_t *data)
1110052f947fSAndrew Lunn {
1111052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1112e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
111357d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
111457d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1115e0d8b615SAndrew Lunn }
1116e0d8b615SAndrew Lunn 
1117436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1118e0d8b615SAndrew Lunn 				     uint64_t *data)
1119e0d8b615SAndrew Lunn {
1120e0d8b615SAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1121e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
112257d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
112357d1ef38SVivien Didelot 					 0);
1124052f947fSAndrew Lunn }
1125052f947fSAndrew Lunn 
112665f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
112765f60e45SAndrew Lunn 					uint64_t *data)
112865f60e45SAndrew Lunn {
112965f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_member_violation;
113065f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_miss_violation;
113165f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_full_violation;
113265f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_member_violation;
113365f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_miss_violation;
113465f60e45SAndrew Lunn }
113565f60e45SAndrew Lunn 
1136052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
1137052f947fSAndrew Lunn 				uint64_t *data)
1138052f947fSAndrew Lunn {
1139436fe17dSAndrew Lunn 	int count = 0;
1140436fe17dSAndrew Lunn 
1141052f947fSAndrew Lunn 	if (chip->info->ops->stats_get_stats)
1142436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_stats(chip, port, data);
1143436fe17dSAndrew Lunn 
1144c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1145436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_stats) {
1146436fe17dSAndrew Lunn 		data += count;
114765f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_stats(chip, port, data);
1148436fe17dSAndrew Lunn 	}
114965f60e45SAndrew Lunn 	data += count;
115065f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_stats(chip, port, data);
1151c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1152052f947fSAndrew Lunn }
1153052f947fSAndrew Lunn 
1154fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
1155fad09c73SVivien Didelot 					uint64_t *data)
1156fad09c73SVivien Didelot {
115704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1158fad09c73SVivien Didelot 	int ret;
1159fad09c73SVivien Didelot 
1160c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1161fad09c73SVivien Didelot 
1162a605a0feSAndrew Lunn 	ret = mv88e6xxx_stats_snapshot(chip, port);
1163c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1164377cda13SAndrew Lunn 
1165377cda13SAndrew Lunn 	if (ret < 0)
1166fad09c73SVivien Didelot 		return;
1167052f947fSAndrew Lunn 
1168052f947fSAndrew Lunn 	mv88e6xxx_get_stats(chip, port, data);
1169fad09c73SVivien Didelot 
1170fad09c73SVivien Didelot }
1171fad09c73SVivien Didelot 
1172fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
1173fad09c73SVivien Didelot {
11740d30bbd0SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
11750d30bbd0SAndrew Lunn 	int len;
11760d30bbd0SAndrew Lunn 
11770d30bbd0SAndrew Lunn 	len = 32 * sizeof(u16);
11780d30bbd0SAndrew Lunn 	if (chip->info->ops->serdes_get_regs_len)
11790d30bbd0SAndrew Lunn 		len += chip->info->ops->serdes_get_regs_len(chip, port);
11800d30bbd0SAndrew Lunn 
11810d30bbd0SAndrew Lunn 	return len;
1182fad09c73SVivien Didelot }
1183fad09c73SVivien Didelot 
1184fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
1185fad09c73SVivien Didelot 			       struct ethtool_regs *regs, void *_p)
1186fad09c73SVivien Didelot {
118704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
11880e7b9925SAndrew Lunn 	int err;
11890e7b9925SAndrew Lunn 	u16 reg;
1190fad09c73SVivien Didelot 	u16 *p = _p;
1191fad09c73SVivien Didelot 	int i;
1192fad09c73SVivien Didelot 
1193a5f39326SVivien Didelot 	regs->version = chip->info->prod_num;
1194fad09c73SVivien Didelot 
1195fad09c73SVivien Didelot 	memset(p, 0xff, 32 * sizeof(u16));
1196fad09c73SVivien Didelot 
1197c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1198fad09c73SVivien Didelot 
1199fad09c73SVivien Didelot 	for (i = 0; i < 32; i++) {
1200fad09c73SVivien Didelot 
12010e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, i, &reg);
12020e7b9925SAndrew Lunn 		if (!err)
12030e7b9925SAndrew Lunn 			p[i] = reg;
1204fad09c73SVivien Didelot 	}
1205fad09c73SVivien Didelot 
12060d30bbd0SAndrew Lunn 	if (chip->info->ops->serdes_get_regs)
12070d30bbd0SAndrew Lunn 		chip->info->ops->serdes_get_regs(chip, port, &p[i]);
12080d30bbd0SAndrew Lunn 
1209c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1210fad09c73SVivien Didelot }
1211fad09c73SVivien Didelot 
121208f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
1213fad09c73SVivien Didelot 				 struct ethtool_eee *e)
1214fad09c73SVivien Didelot {
12155480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
12165480db69SVivien Didelot 	return 0;
1217fad09c73SVivien Didelot }
1218fad09c73SVivien Didelot 
121908f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port,
122046587e4aSVivien Didelot 				 struct ethtool_eee *e)
1221fad09c73SVivien Didelot {
12225480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
12235480db69SVivien Didelot 	return 0;
1224fad09c73SVivien Didelot }
1225fad09c73SVivien Didelot 
12269dc8b13eSVivien Didelot /* Mask of the local ports allowed to receive frames from a given fabric port */
1227e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
1228fad09c73SVivien Didelot {
12299dc8b13eSVivien Didelot 	struct dsa_switch *ds = chip->ds;
12309dc8b13eSVivien Didelot 	struct dsa_switch_tree *dst = ds->dst;
1231*65144067SVladimir Oltean 	struct dsa_port *dp, *other_dp;
12329dc8b13eSVivien Didelot 	bool found = false;
1233e5887a2aSVivien Didelot 	u16 pvlan;
1234fad09c73SVivien Didelot 
1235ce5df689SVladimir Oltean 	/* dev is a physical switch */
1236ce5df689SVladimir Oltean 	if (dev <= dst->last_switch) {
12379dc8b13eSVivien Didelot 		list_for_each_entry(dp, &dst->ports, list) {
12389dc8b13eSVivien Didelot 			if (dp->ds->index == dev && dp->index == port) {
1239ce5df689SVladimir Oltean 				/* dp might be a DSA link or a user port, so it
1240*65144067SVladimir Oltean 				 * might or might not have a bridge.
1241*65144067SVladimir Oltean 				 * Use the "found" variable for both cases.
1242ce5df689SVladimir Oltean 				 */
1243ce5df689SVladimir Oltean 				found = true;
1244ce5df689SVladimir Oltean 				break;
1245ce5df689SVladimir Oltean 			}
1246ce5df689SVladimir Oltean 		}
1247ce5df689SVladimir Oltean 	/* dev is a virtual bridge */
1248ce5df689SVladimir Oltean 	} else {
1249ce5df689SVladimir Oltean 		list_for_each_entry(dp, &dst->ports, list) {
12503f9bb030SVladimir Oltean 			if (!dp->bridge_num)
1251ce5df689SVladimir Oltean 				continue;
1252ce5df689SVladimir Oltean 
12533f9bb030SVladimir Oltean 			if (dp->bridge_num + dst->last_switch != dev)
1254ce5df689SVladimir Oltean 				continue;
1255ce5df689SVladimir Oltean 
12569dc8b13eSVivien Didelot 			found = true;
12579dc8b13eSVivien Didelot 			break;
12589dc8b13eSVivien Didelot 		}
12599dc8b13eSVivien Didelot 	}
1260fad09c73SVivien Didelot 
1261ce5df689SVladimir Oltean 	/* Prevent frames from unknown switch or virtual bridge */
12629dc8b13eSVivien Didelot 	if (!found)
1263e5887a2aSVivien Didelot 		return 0;
1264e5887a2aSVivien Didelot 
1265e5887a2aSVivien Didelot 	/* Frames from DSA links and CPU ports can egress any local port */
12669dc8b13eSVivien Didelot 	if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA)
1267e5887a2aSVivien Didelot 		return mv88e6xxx_port_mask(chip);
1268e5887a2aSVivien Didelot 
1269e5887a2aSVivien Didelot 	pvlan = 0;
1270e5887a2aSVivien Didelot 
1271e5887a2aSVivien Didelot 	/* Frames from user ports can egress any local DSA links and CPU ports,
1272e5887a2aSVivien Didelot 	 * as well as any local member of their bridge group.
1273e5887a2aSVivien Didelot 	 */
1274*65144067SVladimir Oltean 	dsa_switch_for_each_port(other_dp, ds)
1275*65144067SVladimir Oltean 		if (other_dp->type == DSA_PORT_TYPE_CPU ||
1276*65144067SVladimir Oltean 		    other_dp->type == DSA_PORT_TYPE_DSA ||
1277*65144067SVladimir Oltean 		    (dp->bridge_dev && dp->bridge_dev == other_dp->bridge_dev))
1278*65144067SVladimir Oltean 			pvlan |= BIT(other_dp->index);
1279e5887a2aSVivien Didelot 
1280e5887a2aSVivien Didelot 	return pvlan;
1281fad09c73SVivien Didelot }
1282e5887a2aSVivien Didelot 
1283240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port)
1284e5887a2aSVivien Didelot {
1285e5887a2aSVivien Didelot 	u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port);
1286fad09c73SVivien Didelot 
1287fad09c73SVivien Didelot 	/* prevent frames from going back out of the port they came in on */
1288fad09c73SVivien Didelot 	output_ports &= ~BIT(port);
1289fad09c73SVivien Didelot 
12905a7921f4SVivien Didelot 	return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
1291fad09c73SVivien Didelot }
1292fad09c73SVivien Didelot 
1293fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
1294fad09c73SVivien Didelot 					 u8 state)
1295fad09c73SVivien Didelot {
129604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1297fad09c73SVivien Didelot 	int err;
1298fad09c73SVivien Didelot 
1299c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1300f894c29cSVivien Didelot 	err = mv88e6xxx_port_set_state(chip, port, state);
1301c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1302fad09c73SVivien Didelot 
1303fad09c73SVivien Didelot 	if (err)
1304774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to update state\n", port);
1305fad09c73SVivien Didelot }
1306fad09c73SVivien Didelot 
130793e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip)
130893e18d61SVivien Didelot {
130993e18d61SVivien Didelot 	int err;
131093e18d61SVivien Didelot 
131193e18d61SVivien Didelot 	if (chip->info->ops->ieee_pri_map) {
131293e18d61SVivien Didelot 		err = chip->info->ops->ieee_pri_map(chip);
131393e18d61SVivien Didelot 		if (err)
131493e18d61SVivien Didelot 			return err;
131593e18d61SVivien Didelot 	}
131693e18d61SVivien Didelot 
131793e18d61SVivien Didelot 	if (chip->info->ops->ip_pri_map) {
131893e18d61SVivien Didelot 		err = chip->info->ops->ip_pri_map(chip);
131993e18d61SVivien Didelot 		if (err)
132093e18d61SVivien Didelot 			return err;
132193e18d61SVivien Didelot 	}
132293e18d61SVivien Didelot 
132393e18d61SVivien Didelot 	return 0;
132493e18d61SVivien Didelot }
132593e18d61SVivien Didelot 
1326c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
1327c7f047b6SVivien Didelot {
1328c5f51765SVivien Didelot 	struct dsa_switch *ds = chip->ds;
1329c7f047b6SVivien Didelot 	int target, port;
1330c7f047b6SVivien Didelot 	int err;
1331c7f047b6SVivien Didelot 
1332c7f047b6SVivien Didelot 	if (!chip->info->global2_addr)
1333c7f047b6SVivien Didelot 		return 0;
1334c7f047b6SVivien Didelot 
1335c7f047b6SVivien Didelot 	/* Initialize the routing port to the 32 possible target devices */
1336c7f047b6SVivien Didelot 	for (target = 0; target < 32; target++) {
1337c5f51765SVivien Didelot 		port = dsa_routing_port(ds, target);
1338c5f51765SVivien Didelot 		if (port == ds->num_ports)
1339c7f047b6SVivien Didelot 			port = 0x1f;
1340c7f047b6SVivien Didelot 
1341c7f047b6SVivien Didelot 		err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
1342c7f047b6SVivien Didelot 		if (err)
1343c7f047b6SVivien Didelot 			return err;
1344c7f047b6SVivien Didelot 	}
1345c7f047b6SVivien Didelot 
134602317e68SVivien Didelot 	if (chip->info->ops->set_cascade_port) {
134702317e68SVivien Didelot 		port = MV88E6XXX_CASCADE_PORT_MULTIPLE;
134802317e68SVivien Didelot 		err = chip->info->ops->set_cascade_port(chip, port);
134902317e68SVivien Didelot 		if (err)
135002317e68SVivien Didelot 			return err;
135102317e68SVivien Didelot 	}
135202317e68SVivien Didelot 
135323c98919SVivien Didelot 	err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index);
135423c98919SVivien Didelot 	if (err)
135523c98919SVivien Didelot 		return err;
135623c98919SVivien Didelot 
1357c7f047b6SVivien Didelot 	return 0;
1358c7f047b6SVivien Didelot }
1359c7f047b6SVivien Didelot 
1360b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip)
1361b28f872dSVivien Didelot {
1362b28f872dSVivien Didelot 	/* Clear all trunk masks and mapping */
1363b28f872dSVivien Didelot 	if (chip->info->global2_addr)
1364b28f872dSVivien Didelot 		return mv88e6xxx_g2_trunk_clear(chip);
1365b28f872dSVivien Didelot 
1366b28f872dSVivien Didelot 	return 0;
1367b28f872dSVivien Didelot }
1368b28f872dSVivien Didelot 
13699e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
13709e5baf9bSVivien Didelot {
13719e5baf9bSVivien Didelot 	if (chip->info->ops->rmu_disable)
13729e5baf9bSVivien Didelot 		return chip->info->ops->rmu_disable(chip);
13739e5baf9bSVivien Didelot 
13749e5baf9bSVivien Didelot 	return 0;
13759e5baf9bSVivien Didelot }
13769e5baf9bSVivien Didelot 
13779e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
13789e907d73SVivien Didelot {
13799e907d73SVivien Didelot 	if (chip->info->ops->pot_clear)
13809e907d73SVivien Didelot 		return chip->info->ops->pot_clear(chip);
13819e907d73SVivien Didelot 
13829e907d73SVivien Didelot 	return 0;
13839e907d73SVivien Didelot }
13849e907d73SVivien Didelot 
138551c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip)
138651c901a7SVivien Didelot {
138751c901a7SVivien Didelot 	if (chip->info->ops->mgmt_rsvd2cpu)
138851c901a7SVivien Didelot 		return chip->info->ops->mgmt_rsvd2cpu(chip);
138951c901a7SVivien Didelot 
139051c901a7SVivien Didelot 	return 0;
139151c901a7SVivien Didelot }
139251c901a7SVivien Didelot 
1393a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
1394a2ac29d2SVivien Didelot {
1395c3a7d4adSVivien Didelot 	int err;
1396c3a7d4adSVivien Didelot 
1397daefc943SVivien Didelot 	err = mv88e6xxx_g1_atu_flush(chip, 0, true);
1398daefc943SVivien Didelot 	if (err)
1399daefc943SVivien Didelot 		return err;
1400daefc943SVivien Didelot 
140149506a9bSRasmus Villemoes 	/* The chips that have a "learn2all" bit in Global1, ATU
140249506a9bSRasmus Villemoes 	 * Control are precisely those whose port registers have a
140349506a9bSRasmus Villemoes 	 * Message Port bit in Port Control 1 and hence implement
140449506a9bSRasmus Villemoes 	 * ->port_setup_message_port.
140549506a9bSRasmus Villemoes 	 */
140649506a9bSRasmus Villemoes 	if (chip->info->ops->port_setup_message_port) {
1407c3a7d4adSVivien Didelot 		err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
1408c3a7d4adSVivien Didelot 		if (err)
1409c3a7d4adSVivien Didelot 			return err;
141049506a9bSRasmus Villemoes 	}
1411c3a7d4adSVivien Didelot 
1412a2ac29d2SVivien Didelot 	return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
1413a2ac29d2SVivien Didelot }
1414a2ac29d2SVivien Didelot 
1415cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip)
1416cd8da8bbSVivien Didelot {
1417cd8da8bbSVivien Didelot 	int port;
1418cd8da8bbSVivien Didelot 	int err;
1419cd8da8bbSVivien Didelot 
1420cd8da8bbSVivien Didelot 	if (!chip->info->ops->irl_init_all)
1421cd8da8bbSVivien Didelot 		return 0;
1422cd8da8bbSVivien Didelot 
1423cd8da8bbSVivien Didelot 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
1424cd8da8bbSVivien Didelot 		/* Disable ingress rate limiting by resetting all per port
1425cd8da8bbSVivien Didelot 		 * ingress rate limit resources to their initial state.
1426cd8da8bbSVivien Didelot 		 */
1427cd8da8bbSVivien Didelot 		err = chip->info->ops->irl_init_all(chip, port);
1428cd8da8bbSVivien Didelot 		if (err)
1429cd8da8bbSVivien Didelot 			return err;
1430cd8da8bbSVivien Didelot 	}
1431cd8da8bbSVivien Didelot 
1432cd8da8bbSVivien Didelot 	return 0;
1433cd8da8bbSVivien Didelot }
1434cd8da8bbSVivien Didelot 
143504a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip)
143604a69a17SVivien Didelot {
143704a69a17SVivien Didelot 	if (chip->info->ops->set_switch_mac) {
143804a69a17SVivien Didelot 		u8 addr[ETH_ALEN];
143904a69a17SVivien Didelot 
144004a69a17SVivien Didelot 		eth_random_addr(addr);
144104a69a17SVivien Didelot 
144204a69a17SVivien Didelot 		return chip->info->ops->set_switch_mac(chip, addr);
144304a69a17SVivien Didelot 	}
144404a69a17SVivien Didelot 
144504a69a17SVivien Didelot 	return 0;
144604a69a17SVivien Didelot }
144704a69a17SVivien Didelot 
144817a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
144917a1594eSVivien Didelot {
145057e661aaSTobias Waldekranz 	struct dsa_switch_tree *dst = chip->ds->dst;
145157e661aaSTobias Waldekranz 	struct dsa_switch *ds;
145257e661aaSTobias Waldekranz 	struct dsa_port *dp;
145317a1594eSVivien Didelot 	u16 pvlan = 0;
145417a1594eSVivien Didelot 
145517a1594eSVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
1456d14939beSVivien Didelot 		return 0;
145717a1594eSVivien Didelot 
145817a1594eSVivien Didelot 	/* Skip the local source device, which uses in-chip port VLAN */
145957e661aaSTobias Waldekranz 	if (dev != chip->ds->index) {
1460aec5ac88SVivien Didelot 		pvlan = mv88e6xxx_port_vlan(chip, dev, port);
146117a1594eSVivien Didelot 
146257e661aaSTobias Waldekranz 		ds = dsa_switch_find(dst->index, dev);
146357e661aaSTobias Waldekranz 		dp = ds ? dsa_to_port(ds, port) : NULL;
146457e661aaSTobias Waldekranz 		if (dp && dp->lag_dev) {
146557e661aaSTobias Waldekranz 			/* As the PVT is used to limit flooding of
146657e661aaSTobias Waldekranz 			 * FORWARD frames, which use the LAG ID as the
146757e661aaSTobias Waldekranz 			 * source port, we must translate dev/port to
146857e661aaSTobias Waldekranz 			 * the special "LAG device" in the PVT, using
146957e661aaSTobias Waldekranz 			 * the LAG ID as the port number.
147057e661aaSTobias Waldekranz 			 */
147178e70dbcSTobias Waldekranz 			dev = MV88E6XXX_G2_PVT_ADDR_DEV_TRUNK;
147257e661aaSTobias Waldekranz 			port = dsa_lag_id(dst, dp->lag_dev);
147357e661aaSTobias Waldekranz 		}
147457e661aaSTobias Waldekranz 	}
147557e661aaSTobias Waldekranz 
147617a1594eSVivien Didelot 	return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
147717a1594eSVivien Didelot }
147817a1594eSVivien Didelot 
147981228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
148081228996SVivien Didelot {
148117a1594eSVivien Didelot 	int dev, port;
148217a1594eSVivien Didelot 	int err;
148317a1594eSVivien Didelot 
148481228996SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
148581228996SVivien Didelot 		return 0;
148681228996SVivien Didelot 
148781228996SVivien Didelot 	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
148881228996SVivien Didelot 	 * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
148981228996SVivien Didelot 	 */
149017a1594eSVivien Didelot 	err = mv88e6xxx_g2_misc_4_bit_port(chip);
149117a1594eSVivien Didelot 	if (err)
149217a1594eSVivien Didelot 		return err;
149317a1594eSVivien Didelot 
149417a1594eSVivien Didelot 	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) {
149517a1594eSVivien Didelot 		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) {
149617a1594eSVivien Didelot 			err = mv88e6xxx_pvt_map(chip, dev, port);
149717a1594eSVivien Didelot 			if (err)
149817a1594eSVivien Didelot 				return err;
149917a1594eSVivien Didelot 		}
150017a1594eSVivien Didelot 	}
150117a1594eSVivien Didelot 
150217a1594eSVivien Didelot 	return 0;
150381228996SVivien Didelot }
150481228996SVivien Didelot 
1505749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
1506749efcb8SVivien Didelot {
1507749efcb8SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1508749efcb8SVivien Didelot 	int err;
1509749efcb8SVivien Didelot 
1510ffcec3f2STobias Waldekranz 	if (dsa_to_port(ds, port)->lag_dev)
1511ffcec3f2STobias Waldekranz 		/* Hardware is incapable of fast-aging a LAG through a
1512ffcec3f2STobias Waldekranz 		 * regular ATU move operation. Until we have something
1513ffcec3f2STobias Waldekranz 		 * more fancy in place this is a no-op.
1514ffcec3f2STobias Waldekranz 		 */
1515ffcec3f2STobias Waldekranz 		return;
1516ffcec3f2STobias Waldekranz 
1517c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
1518e606ca36SVivien Didelot 	err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
1519c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1520749efcb8SVivien Didelot 
1521749efcb8SVivien Didelot 	if (err)
1522774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to flush ATU\n", port);
1523749efcb8SVivien Didelot }
1524749efcb8SVivien Didelot 
1525b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)
1526b486d7c9SVivien Didelot {
1527e545f865STobias Waldekranz 	if (!mv88e6xxx_max_vid(chip))
1528b486d7c9SVivien Didelot 		return 0;
1529b486d7c9SVivien Didelot 
1530b486d7c9SVivien Didelot 	return mv88e6xxx_g1_vtu_flush(chip);
1531b486d7c9SVivien Didelot }
1532b486d7c9SVivien Didelot 
153334065c58STobias Waldekranz static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
1534f1394b78SVivien Didelot 			     struct mv88e6xxx_vtu_entry *entry)
1535f1394b78SVivien Didelot {
153634065c58STobias Waldekranz 	int err;
153734065c58STobias Waldekranz 
1538f1394b78SVivien Didelot 	if (!chip->info->ops->vtu_getnext)
1539f1394b78SVivien Didelot 		return -EOPNOTSUPP;
1540f1394b78SVivien Didelot 
154134065c58STobias Waldekranz 	entry->vid = vid ? vid - 1 : mv88e6xxx_max_vid(chip);
154234065c58STobias Waldekranz 	entry->valid = false;
154334065c58STobias Waldekranz 
154434065c58STobias Waldekranz 	err = chip->info->ops->vtu_getnext(chip, entry);
154534065c58STobias Waldekranz 
154634065c58STobias Waldekranz 	if (entry->vid != vid)
154734065c58STobias Waldekranz 		entry->valid = false;
154834065c58STobias Waldekranz 
154934065c58STobias Waldekranz 	return err;
1550f1394b78SVivien Didelot }
1551f1394b78SVivien Didelot 
1552d89ef4b8STobias Waldekranz static int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
1553d89ef4b8STobias Waldekranz 			      int (*cb)(struct mv88e6xxx_chip *chip,
1554d89ef4b8STobias Waldekranz 					const struct mv88e6xxx_vtu_entry *entry,
1555d89ef4b8STobias Waldekranz 					void *priv),
1556d89ef4b8STobias Waldekranz 			      void *priv)
1557d89ef4b8STobias Waldekranz {
1558d89ef4b8STobias Waldekranz 	struct mv88e6xxx_vtu_entry entry = {
1559d89ef4b8STobias Waldekranz 		.vid = mv88e6xxx_max_vid(chip),
1560d89ef4b8STobias Waldekranz 		.valid = false,
1561d89ef4b8STobias Waldekranz 	};
1562d89ef4b8STobias Waldekranz 	int err;
1563d89ef4b8STobias Waldekranz 
1564d89ef4b8STobias Waldekranz 	if (!chip->info->ops->vtu_getnext)
1565d89ef4b8STobias Waldekranz 		return -EOPNOTSUPP;
1566d89ef4b8STobias Waldekranz 
1567d89ef4b8STobias Waldekranz 	do {
1568d89ef4b8STobias Waldekranz 		err = chip->info->ops->vtu_getnext(chip, &entry);
1569d89ef4b8STobias Waldekranz 		if (err)
1570d89ef4b8STobias Waldekranz 			return err;
1571d89ef4b8STobias Waldekranz 
1572d89ef4b8STobias Waldekranz 		if (!entry.valid)
1573d89ef4b8STobias Waldekranz 			break;
1574d89ef4b8STobias Waldekranz 
1575d89ef4b8STobias Waldekranz 		err = cb(chip, &entry, priv);
1576d89ef4b8STobias Waldekranz 		if (err)
1577d89ef4b8STobias Waldekranz 			return err;
1578d89ef4b8STobias Waldekranz 	} while (entry.vid < mv88e6xxx_max_vid(chip));
1579d89ef4b8STobias Waldekranz 
1580d89ef4b8STobias Waldekranz 	return 0;
1581d89ef4b8STobias Waldekranz }
1582d89ef4b8STobias Waldekranz 
15830ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
15840ad5daf6SVivien Didelot 				   struct mv88e6xxx_vtu_entry *entry)
15850ad5daf6SVivien Didelot {
15860ad5daf6SVivien Didelot 	if (!chip->info->ops->vtu_loadpurge)
15870ad5daf6SVivien Didelot 		return -EOPNOTSUPP;
15880ad5daf6SVivien Didelot 
15890ad5daf6SVivien Didelot 	return chip->info->ops->vtu_loadpurge(chip, entry);
15900ad5daf6SVivien Didelot }
15910ad5daf6SVivien Didelot 
1592d89ef4b8STobias Waldekranz static int mv88e6xxx_fid_map_vlan(struct mv88e6xxx_chip *chip,
1593d89ef4b8STobias Waldekranz 				  const struct mv88e6xxx_vtu_entry *entry,
1594d89ef4b8STobias Waldekranz 				  void *_fid_bitmap)
1595d89ef4b8STobias Waldekranz {
1596d89ef4b8STobias Waldekranz 	unsigned long *fid_bitmap = _fid_bitmap;
1597d89ef4b8STobias Waldekranz 
1598d89ef4b8STobias Waldekranz 	set_bit(entry->fid, fid_bitmap);
1599d89ef4b8STobias Waldekranz 	return 0;
1600d89ef4b8STobias Waldekranz }
1601d89ef4b8STobias Waldekranz 
160290b6dbdfSAndrew Lunn int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *fid_bitmap)
1603fad09c73SVivien Didelot {
1604fad09c73SVivien Didelot 	int i, err;
160590b6dbdfSAndrew Lunn 	u16 fid;
1606fad09c73SVivien Didelot 
1607fad09c73SVivien Didelot 	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
1608fad09c73SVivien Didelot 
1609fad09c73SVivien Didelot 	/* Set every FID bit used by the (un)bridged ports */
1610370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
161190b6dbdfSAndrew Lunn 		err = mv88e6xxx_port_get_fid(chip, i, &fid);
1612fad09c73SVivien Didelot 		if (err)
1613fad09c73SVivien Didelot 			return err;
1614fad09c73SVivien Didelot 
161590b6dbdfSAndrew Lunn 		set_bit(fid, fid_bitmap);
1616fad09c73SVivien Didelot 	}
1617fad09c73SVivien Didelot 
1618fad09c73SVivien Didelot 	/* Set every FID bit used by the VLAN entries */
1619d89ef4b8STobias Waldekranz 	return mv88e6xxx_vtu_walk(chip, mv88e6xxx_fid_map_vlan, fid_bitmap);
162090b6dbdfSAndrew Lunn }
162190b6dbdfSAndrew Lunn 
162290b6dbdfSAndrew Lunn static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
162390b6dbdfSAndrew Lunn {
162490b6dbdfSAndrew Lunn 	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
162590b6dbdfSAndrew Lunn 	int err;
162690b6dbdfSAndrew Lunn 
162790b6dbdfSAndrew Lunn 	err = mv88e6xxx_fid_map(chip, fid_bitmap);
162890b6dbdfSAndrew Lunn 	if (err)
162990b6dbdfSAndrew Lunn 		return err;
163090b6dbdfSAndrew Lunn 
1631fad09c73SVivien Didelot 	/* The reset value 0x000 is used to indicate that multiple address
1632fad09c73SVivien Didelot 	 * databases are not needed. Return the next positive available.
1633fad09c73SVivien Didelot 	 */
1634fad09c73SVivien Didelot 	*fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1);
1635fad09c73SVivien Didelot 	if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
1636fad09c73SVivien Didelot 		return -ENOSPC;
1637fad09c73SVivien Didelot 
1638fad09c73SVivien Didelot 	/* Clear the database */
1639daefc943SVivien Didelot 	return mv88e6xxx_g1_atu_flush(chip, *fid, true);
1640fad09c73SVivien Didelot }
1641fad09c73SVivien Didelot 
1642fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
1643b7a9e0daSVladimir Oltean 					u16 vid)
1644fad09c73SVivien Didelot {
16450493fa79SVladimir Oltean 	struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
164604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1647425d2d37SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
16480493fa79SVladimir Oltean 	int err;
1649fad09c73SVivien Didelot 
1650db06ae41SAndrew Lunn 	/* DSA and CPU ports have to be members of multiple vlans */
16510493fa79SVladimir Oltean 	if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp))
1652db06ae41SAndrew Lunn 		return 0;
1653db06ae41SAndrew Lunn 
165434065c58STobias Waldekranz 	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
1655fad09c73SVivien Didelot 	if (err)
16567095a4c4SVivien Didelot 		return err;
1657fad09c73SVivien Didelot 
1658fad09c73SVivien Didelot 	if (!vlan.valid)
1659b7a9e0daSVladimir Oltean 		return 0;
1660fad09c73SVivien Didelot 
16610493fa79SVladimir Oltean 	dsa_switch_for_each_user_port(other_dp, ds) {
16620493fa79SVladimir Oltean 		if (vlan.member[other_dp->index] ==
16637ec60d6eSVivien Didelot 		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1664fad09c73SVivien Didelot 			continue;
1665fad09c73SVivien Didelot 
16660493fa79SVladimir Oltean 		if (dp->bridge_dev == other_dp->bridge_dev)
1667fad09c73SVivien Didelot 			break; /* same bridge, check next VLAN */
1668fad09c73SVivien Didelot 
16690493fa79SVladimir Oltean 		if (!other_dp->bridge_dev)
167066e2809dSAndrew Lunn 			continue;
167166e2809dSAndrew Lunn 
1672743fcc28SAndrew Lunn 		dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
16730493fa79SVladimir Oltean 			port, vlan.vid, other_dp->index,
16740493fa79SVladimir Oltean 			netdev_name(other_dp->bridge_dev));
16757095a4c4SVivien Didelot 		return -EOPNOTSUPP;
1676fad09c73SVivien Didelot 	}
1677fad09c73SVivien Didelot 
16787095a4c4SVivien Didelot 	return 0;
1679fad09c73SVivien Didelot }
1680fad09c73SVivien Didelot 
16818b6836d8SVladimir Oltean static int mv88e6xxx_port_commit_pvid(struct mv88e6xxx_chip *chip, int port)
16828b6836d8SVladimir Oltean {
16838b6836d8SVladimir Oltean 	struct dsa_port *dp = dsa_to_port(chip->ds, port);
16848b6836d8SVladimir Oltean 	struct mv88e6xxx_port *p = &chip->ports[port];
16855bded825SVladimir Oltean 	u16 pvid = MV88E6XXX_VID_STANDALONE;
16868b6836d8SVladimir Oltean 	bool drop_untagged = false;
16878b6836d8SVladimir Oltean 	int err;
16888b6836d8SVladimir Oltean 
16895bded825SVladimir Oltean 	if (dp->bridge_dev) {
16905bded825SVladimir Oltean 		if (br_vlan_enabled(dp->bridge_dev)) {
16918b6836d8SVladimir Oltean 			pvid = p->bridge_pvid.vid;
16928b6836d8SVladimir Oltean 			drop_untagged = !p->bridge_pvid.valid;
16935bded825SVladimir Oltean 		} else {
16945bded825SVladimir Oltean 			pvid = MV88E6XXX_VID_BRIDGED;
16955bded825SVladimir Oltean 		}
16968b6836d8SVladimir Oltean 	}
16978b6836d8SVladimir Oltean 
16988b6836d8SVladimir Oltean 	err = mv88e6xxx_port_set_pvid(chip, port, pvid);
16998b6836d8SVladimir Oltean 	if (err)
17008b6836d8SVladimir Oltean 		return err;
17018b6836d8SVladimir Oltean 
17028b6836d8SVladimir Oltean 	return mv88e6xxx_port_drop_untagged(chip, port, drop_untagged);
17038b6836d8SVladimir Oltean }
17048b6836d8SVladimir Oltean 
1705fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
170689153ed6SVladimir Oltean 					 bool vlan_filtering,
170789153ed6SVladimir Oltean 					 struct netlink_ext_ack *extack)
1708fad09c73SVivien Didelot {
170904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
171081c6edb2SVivien Didelot 	u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
171181c6edb2SVivien Didelot 		MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
17120e7b9925SAndrew Lunn 	int err;
1713fad09c73SVivien Didelot 
1714bae33f2bSVladimir Oltean 	if (!mv88e6xxx_max_vid(chip))
1715bae33f2bSVladimir Oltean 		return -EOPNOTSUPP;
1716fad09c73SVivien Didelot 
1717c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
17188b6836d8SVladimir Oltean 
1719385a0995SVivien Didelot 	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
17208b6836d8SVladimir Oltean 	if (err)
17218b6836d8SVladimir Oltean 		goto unlock;
17228b6836d8SVladimir Oltean 
17238b6836d8SVladimir Oltean 	err = mv88e6xxx_port_commit_pvid(chip, port);
17248b6836d8SVladimir Oltean 	if (err)
17258b6836d8SVladimir Oltean 		goto unlock;
17268b6836d8SVladimir Oltean 
17278b6836d8SVladimir Oltean unlock:
1728c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
1729fad09c73SVivien Didelot 
17300e7b9925SAndrew Lunn 	return err;
1731fad09c73SVivien Didelot }
1732fad09c73SVivien Didelot 
1733fad09c73SVivien Didelot static int
1734fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
173580e02360SVivien Didelot 			    const struct switchdev_obj_port_vlan *vlan)
1736fad09c73SVivien Didelot {
173704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1738fad09c73SVivien Didelot 	int err;
1739fad09c73SVivien Didelot 
1740e545f865STobias Waldekranz 	if (!mv88e6xxx_max_vid(chip))
1741fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1742fad09c73SVivien Didelot 
1743fad09c73SVivien Didelot 	/* If the requested port doesn't belong to the same bridge as the VLAN
1744fad09c73SVivien Didelot 	 * members, do not support it (yet) and fallback to software VLAN.
1745fad09c73SVivien Didelot 	 */
17467095a4c4SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1747b7a9e0daSVladimir Oltean 	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid);
17487095a4c4SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1749fad09c73SVivien Didelot 
17507095a4c4SVivien Didelot 	return err;
1751fad09c73SVivien Didelot }
1752fad09c73SVivien Didelot 
1753a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
1754a4c93ae1SAndrew Lunn 					const unsigned char *addr, u16 vid,
1755a4c93ae1SAndrew Lunn 					u8 state)
1756a4c93ae1SAndrew Lunn {
1757a4c93ae1SAndrew Lunn 	struct mv88e6xxx_atu_entry entry;
17585ef8d249SVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
17595ef8d249SVivien Didelot 	u16 fid;
1760a4c93ae1SAndrew Lunn 	int err;
1761a4c93ae1SAndrew Lunn 
17625bded825SVladimir Oltean 	/* Ports have two private address databases: one for when the port is
17635bded825SVladimir Oltean 	 * standalone and one for when the port is under a bridge and the
17645bded825SVladimir Oltean 	 * 802.1Q mode is disabled. When the port is standalone, DSA wants its
17655bded825SVladimir Oltean 	 * address database to remain 100% empty, so we never load an ATU entry
17665bded825SVladimir Oltean 	 * into a standalone port's database. Therefore, translate the null
17675bded825SVladimir Oltean 	 * VLAN ID into the port's database used for VLAN-unaware bridging.
17685bded825SVladimir Oltean 	 */
17695ef8d249SVivien Didelot 	if (vid == 0) {
17705bded825SVladimir Oltean 		fid = MV88E6XXX_FID_BRIDGED;
17715ef8d249SVivien Didelot 	} else {
177234065c58STobias Waldekranz 		err = mv88e6xxx_vtu_get(chip, vid, &vlan);
17735ef8d249SVivien Didelot 		if (err)
17745ef8d249SVivien Didelot 			return err;
17755ef8d249SVivien Didelot 
17765ef8d249SVivien Didelot 		/* switchdev expects -EOPNOTSUPP to honor software VLANs */
177734065c58STobias Waldekranz 		if (!vlan.valid)
17785ef8d249SVivien Didelot 			return -EOPNOTSUPP;
17795ef8d249SVivien Didelot 
17805ef8d249SVivien Didelot 		fid = vlan.fid;
17815ef8d249SVivien Didelot 	}
1782a4c93ae1SAndrew Lunn 
1783d8291a95SVivien Didelot 	entry.state = 0;
1784a4c93ae1SAndrew Lunn 	ether_addr_copy(entry.mac, addr);
1785a4c93ae1SAndrew Lunn 	eth_addr_dec(entry.mac);
1786a4c93ae1SAndrew Lunn 
17875ef8d249SVivien Didelot 	err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry);
1788a4c93ae1SAndrew Lunn 	if (err)
1789a4c93ae1SAndrew Lunn 		return err;
1790a4c93ae1SAndrew Lunn 
1791a4c93ae1SAndrew Lunn 	/* Initialize a fresh ATU entry if it isn't found */
1792d8291a95SVivien Didelot 	if (!entry.state || !ether_addr_equal(entry.mac, addr)) {
1793a4c93ae1SAndrew Lunn 		memset(&entry, 0, sizeof(entry));
1794a4c93ae1SAndrew Lunn 		ether_addr_copy(entry.mac, addr);
1795a4c93ae1SAndrew Lunn 	}
1796a4c93ae1SAndrew Lunn 
1797a4c93ae1SAndrew Lunn 	/* Purge the ATU entry only if no port is using it anymore */
1798d8291a95SVivien Didelot 	if (!state) {
1799a4c93ae1SAndrew Lunn 		entry.portvec &= ~BIT(port);
1800a4c93ae1SAndrew Lunn 		if (!entry.portvec)
1801d8291a95SVivien Didelot 			entry.state = 0;
1802a4c93ae1SAndrew Lunn 	} else {
1803f72f2fb8SDENG Qingfang 		if (state == MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC)
1804f72f2fb8SDENG Qingfang 			entry.portvec = BIT(port);
1805f72f2fb8SDENG Qingfang 		else
1806a4c93ae1SAndrew Lunn 			entry.portvec |= BIT(port);
1807f72f2fb8SDENG Qingfang 
1808a4c93ae1SAndrew Lunn 		entry.state = state;
1809a4c93ae1SAndrew Lunn 	}
1810a4c93ae1SAndrew Lunn 
18115ef8d249SVivien Didelot 	return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry);
1812a4c93ae1SAndrew Lunn }
1813a4c93ae1SAndrew Lunn 
1814da7dc875SVivien Didelot static int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port,
1815da7dc875SVivien Didelot 				  const struct mv88e6xxx_policy *policy)
1816da7dc875SVivien Didelot {
1817da7dc875SVivien Didelot 	enum mv88e6xxx_policy_mapping mapping = policy->mapping;
1818da7dc875SVivien Didelot 	enum mv88e6xxx_policy_action action = policy->action;
1819da7dc875SVivien Didelot 	const u8 *addr = policy->addr;
1820da7dc875SVivien Didelot 	u16 vid = policy->vid;
1821da7dc875SVivien Didelot 	u8 state;
1822da7dc875SVivien Didelot 	int err;
1823da7dc875SVivien Didelot 	int id;
1824da7dc875SVivien Didelot 
1825da7dc875SVivien Didelot 	if (!chip->info->ops->port_set_policy)
1826da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1827da7dc875SVivien Didelot 
1828da7dc875SVivien Didelot 	switch (mapping) {
1829da7dc875SVivien Didelot 	case MV88E6XXX_POLICY_MAPPING_DA:
1830da7dc875SVivien Didelot 	case MV88E6XXX_POLICY_MAPPING_SA:
1831da7dc875SVivien Didelot 		if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
1832da7dc875SVivien Didelot 			state = 0; /* Dissociate the port and address */
1833da7dc875SVivien Didelot 		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
1834da7dc875SVivien Didelot 			 is_multicast_ether_addr(addr))
1835da7dc875SVivien Didelot 			state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY;
1836da7dc875SVivien Didelot 		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
1837da7dc875SVivien Didelot 			 is_unicast_ether_addr(addr))
1838da7dc875SVivien Didelot 			state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY;
1839da7dc875SVivien Didelot 		else
1840da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1841da7dc875SVivien Didelot 
1842da7dc875SVivien Didelot 		err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
1843da7dc875SVivien Didelot 						   state);
1844da7dc875SVivien Didelot 		if (err)
1845da7dc875SVivien Didelot 			return err;
1846da7dc875SVivien Didelot 		break;
1847da7dc875SVivien Didelot 	default:
1848da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1849da7dc875SVivien Didelot 	}
1850da7dc875SVivien Didelot 
1851da7dc875SVivien Didelot 	/* Skip the port's policy clearing if the mapping is still in use */
1852da7dc875SVivien Didelot 	if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
1853da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1854da7dc875SVivien Didelot 			if (policy->port == port &&
1855da7dc875SVivien Didelot 			    policy->mapping == mapping &&
1856da7dc875SVivien Didelot 			    policy->action != action)
1857da7dc875SVivien Didelot 				return 0;
1858da7dc875SVivien Didelot 
1859da7dc875SVivien Didelot 	return chip->info->ops->port_set_policy(chip, port, mapping, action);
1860da7dc875SVivien Didelot }
1861da7dc875SVivien Didelot 
1862da7dc875SVivien Didelot static int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port,
1863da7dc875SVivien Didelot 				   struct ethtool_rx_flow_spec *fs)
1864da7dc875SVivien Didelot {
1865da7dc875SVivien Didelot 	struct ethhdr *mac_entry = &fs->h_u.ether_spec;
1866da7dc875SVivien Didelot 	struct ethhdr *mac_mask = &fs->m_u.ether_spec;
1867da7dc875SVivien Didelot 	enum mv88e6xxx_policy_mapping mapping;
1868da7dc875SVivien Didelot 	enum mv88e6xxx_policy_action action;
1869da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1870da7dc875SVivien Didelot 	u16 vid = 0;
1871da7dc875SVivien Didelot 	u8 *addr;
1872da7dc875SVivien Didelot 	int err;
1873da7dc875SVivien Didelot 	int id;
1874da7dc875SVivien Didelot 
1875da7dc875SVivien Didelot 	if (fs->location != RX_CLS_LOC_ANY)
1876da7dc875SVivien Didelot 		return -EINVAL;
1877da7dc875SVivien Didelot 
1878da7dc875SVivien Didelot 	if (fs->ring_cookie == RX_CLS_FLOW_DISC)
1879da7dc875SVivien Didelot 		action = MV88E6XXX_POLICY_ACTION_DISCARD;
1880da7dc875SVivien Didelot 	else
1881da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1882da7dc875SVivien Didelot 
1883da7dc875SVivien Didelot 	switch (fs->flow_type & ~FLOW_EXT) {
1884da7dc875SVivien Didelot 	case ETHER_FLOW:
1885da7dc875SVivien Didelot 		if (!is_zero_ether_addr(mac_mask->h_dest) &&
1886da7dc875SVivien Didelot 		    is_zero_ether_addr(mac_mask->h_source)) {
1887da7dc875SVivien Didelot 			mapping = MV88E6XXX_POLICY_MAPPING_DA;
1888da7dc875SVivien Didelot 			addr = mac_entry->h_dest;
1889da7dc875SVivien Didelot 		} else if (is_zero_ether_addr(mac_mask->h_dest) &&
1890da7dc875SVivien Didelot 		    !is_zero_ether_addr(mac_mask->h_source)) {
1891da7dc875SVivien Didelot 			mapping = MV88E6XXX_POLICY_MAPPING_SA;
1892da7dc875SVivien Didelot 			addr = mac_entry->h_source;
1893da7dc875SVivien Didelot 		} else {
1894da7dc875SVivien Didelot 			/* Cannot support DA and SA mapping in the same rule */
1895da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1896da7dc875SVivien Didelot 		}
1897da7dc875SVivien Didelot 		break;
1898da7dc875SVivien Didelot 	default:
1899da7dc875SVivien Didelot 		return -EOPNOTSUPP;
1900da7dc875SVivien Didelot 	}
1901da7dc875SVivien Didelot 
1902da7dc875SVivien Didelot 	if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) {
190304844280SAndrew Lunn 		if (fs->m_ext.vlan_tci != htons(0xffff))
1904da7dc875SVivien Didelot 			return -EOPNOTSUPP;
1905da7dc875SVivien Didelot 		vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK;
1906da7dc875SVivien Didelot 	}
1907da7dc875SVivien Didelot 
1908da7dc875SVivien Didelot 	idr_for_each_entry(&chip->policies, policy, id) {
1909da7dc875SVivien Didelot 		if (policy->port == port && policy->mapping == mapping &&
1910da7dc875SVivien Didelot 		    policy->action == action && policy->vid == vid &&
1911da7dc875SVivien Didelot 		    ether_addr_equal(policy->addr, addr))
1912da7dc875SVivien Didelot 			return -EEXIST;
1913da7dc875SVivien Didelot 	}
1914da7dc875SVivien Didelot 
1915da7dc875SVivien Didelot 	policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL);
1916da7dc875SVivien Didelot 	if (!policy)
1917da7dc875SVivien Didelot 		return -ENOMEM;
1918da7dc875SVivien Didelot 
1919da7dc875SVivien Didelot 	fs->location = 0;
1920da7dc875SVivien Didelot 	err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff,
1921da7dc875SVivien Didelot 			    GFP_KERNEL);
1922da7dc875SVivien Didelot 	if (err) {
1923da7dc875SVivien Didelot 		devm_kfree(chip->dev, policy);
1924da7dc875SVivien Didelot 		return err;
1925da7dc875SVivien Didelot 	}
1926da7dc875SVivien Didelot 
1927da7dc875SVivien Didelot 	memcpy(&policy->fs, fs, sizeof(*fs));
1928da7dc875SVivien Didelot 	ether_addr_copy(policy->addr, addr);
1929da7dc875SVivien Didelot 	policy->mapping = mapping;
1930da7dc875SVivien Didelot 	policy->action = action;
1931da7dc875SVivien Didelot 	policy->port = port;
1932da7dc875SVivien Didelot 	policy->vid = vid;
1933da7dc875SVivien Didelot 
1934da7dc875SVivien Didelot 	err = mv88e6xxx_policy_apply(chip, port, policy);
1935da7dc875SVivien Didelot 	if (err) {
1936da7dc875SVivien Didelot 		idr_remove(&chip->policies, fs->location);
1937da7dc875SVivien Didelot 		devm_kfree(chip->dev, policy);
1938da7dc875SVivien Didelot 		return err;
1939da7dc875SVivien Didelot 	}
1940da7dc875SVivien Didelot 
1941da7dc875SVivien Didelot 	return 0;
1942da7dc875SVivien Didelot }
1943da7dc875SVivien Didelot 
1944da7dc875SVivien Didelot static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,
1945da7dc875SVivien Didelot 			       struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
1946da7dc875SVivien Didelot {
1947da7dc875SVivien Didelot 	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
1948da7dc875SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1949da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1950da7dc875SVivien Didelot 	int err;
1951da7dc875SVivien Didelot 	int id;
1952da7dc875SVivien Didelot 
1953da7dc875SVivien Didelot 	mv88e6xxx_reg_lock(chip);
1954da7dc875SVivien Didelot 
1955da7dc875SVivien Didelot 	switch (rxnfc->cmd) {
1956da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRLCNT:
1957da7dc875SVivien Didelot 		rxnfc->data = 0;
1958da7dc875SVivien Didelot 		rxnfc->data |= RX_CLS_LOC_SPECIAL;
1959da7dc875SVivien Didelot 		rxnfc->rule_cnt = 0;
1960da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1961da7dc875SVivien Didelot 			if (policy->port == port)
1962da7dc875SVivien Didelot 				rxnfc->rule_cnt++;
1963da7dc875SVivien Didelot 		err = 0;
1964da7dc875SVivien Didelot 		break;
1965da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRULE:
1966da7dc875SVivien Didelot 		err = -ENOENT;
1967da7dc875SVivien Didelot 		policy = idr_find(&chip->policies, fs->location);
1968da7dc875SVivien Didelot 		if (policy) {
1969da7dc875SVivien Didelot 			memcpy(fs, &policy->fs, sizeof(*fs));
1970da7dc875SVivien Didelot 			err = 0;
1971da7dc875SVivien Didelot 		}
1972da7dc875SVivien Didelot 		break;
1973da7dc875SVivien Didelot 	case ETHTOOL_GRXCLSRLALL:
1974da7dc875SVivien Didelot 		rxnfc->data = 0;
1975da7dc875SVivien Didelot 		rxnfc->rule_cnt = 0;
1976da7dc875SVivien Didelot 		idr_for_each_entry(&chip->policies, policy, id)
1977da7dc875SVivien Didelot 			if (policy->port == port)
1978da7dc875SVivien Didelot 				rule_locs[rxnfc->rule_cnt++] = id;
1979da7dc875SVivien Didelot 		err = 0;
1980da7dc875SVivien Didelot 		break;
1981da7dc875SVivien Didelot 	default:
1982da7dc875SVivien Didelot 		err = -EOPNOTSUPP;
1983da7dc875SVivien Didelot 		break;
1984da7dc875SVivien Didelot 	}
1985da7dc875SVivien Didelot 
1986da7dc875SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
1987da7dc875SVivien Didelot 
1988da7dc875SVivien Didelot 	return err;
1989da7dc875SVivien Didelot }
1990da7dc875SVivien Didelot 
1991da7dc875SVivien Didelot static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port,
1992da7dc875SVivien Didelot 			       struct ethtool_rxnfc *rxnfc)
1993da7dc875SVivien Didelot {
1994da7dc875SVivien Didelot 	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
1995da7dc875SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1996da7dc875SVivien Didelot 	struct mv88e6xxx_policy *policy;
1997da7dc875SVivien Didelot 	int err;
1998da7dc875SVivien Didelot 
1999da7dc875SVivien Didelot 	mv88e6xxx_reg_lock(chip);
2000da7dc875SVivien Didelot 
2001da7dc875SVivien Didelot 	switch (rxnfc->cmd) {
2002da7dc875SVivien Didelot 	case ETHTOOL_SRXCLSRLINS:
2003da7dc875SVivien Didelot 		err = mv88e6xxx_policy_insert(chip, port, fs);
2004da7dc875SVivien Didelot 		break;
2005da7dc875SVivien Didelot 	case ETHTOOL_SRXCLSRLDEL:
2006da7dc875SVivien Didelot 		err = -ENOENT;
2007da7dc875SVivien Didelot 		policy = idr_remove(&chip->policies, fs->location);
2008da7dc875SVivien Didelot 		if (policy) {
2009da7dc875SVivien Didelot 			policy->action = MV88E6XXX_POLICY_ACTION_NORMAL;
2010da7dc875SVivien Didelot 			err = mv88e6xxx_policy_apply(chip, port, policy);
2011da7dc875SVivien Didelot 			devm_kfree(chip->dev, policy);
2012da7dc875SVivien Didelot 		}
2013da7dc875SVivien Didelot 		break;
2014da7dc875SVivien Didelot 	default:
2015da7dc875SVivien Didelot 		err = -EOPNOTSUPP;
2016da7dc875SVivien Didelot 		break;
2017da7dc875SVivien Didelot 	}
2018da7dc875SVivien Didelot 
2019da7dc875SVivien Didelot 	mv88e6xxx_reg_unlock(chip);
2020da7dc875SVivien Didelot 
2021da7dc875SVivien Didelot 	return err;
2022da7dc875SVivien Didelot }
2023da7dc875SVivien Didelot 
202487fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
202587fa886eSAndrew Lunn 					u16 vid)
202687fa886eSAndrew Lunn {
202787fa886eSAndrew Lunn 	u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
20280806dd46STobias Waldekranz 	u8 broadcast[ETH_ALEN];
20290806dd46STobias Waldekranz 
20300806dd46STobias Waldekranz 	eth_broadcast_addr(broadcast);
203187fa886eSAndrew Lunn 
203287fa886eSAndrew Lunn 	return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
203387fa886eSAndrew Lunn }
203487fa886eSAndrew Lunn 
203587fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
203687fa886eSAndrew Lunn {
203787fa886eSAndrew Lunn 	int port;
203887fa886eSAndrew Lunn 	int err;
203987fa886eSAndrew Lunn 
204087fa886eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
20418d1d8298STobias Waldekranz 		struct dsa_port *dp = dsa_to_port(chip->ds, port);
20428d1d8298STobias Waldekranz 		struct net_device *brport;
20438d1d8298STobias Waldekranz 
20448d1d8298STobias Waldekranz 		if (dsa_is_unused_port(chip->ds, port))
20458d1d8298STobias Waldekranz 			continue;
20468d1d8298STobias Waldekranz 
20478d1d8298STobias Waldekranz 		brport = dsa_port_to_bridge_port(dp);
20488d1d8298STobias Waldekranz 		if (brport && !br_port_flag_is_set(brport, BR_BCAST_FLOOD))
20498d1d8298STobias Waldekranz 			/* Skip bridged user ports where broadcast
20508d1d8298STobias Waldekranz 			 * flooding is disabled.
20518d1d8298STobias Waldekranz 			 */
20528d1d8298STobias Waldekranz 			continue;
20538d1d8298STobias Waldekranz 
205487fa886eSAndrew Lunn 		err = mv88e6xxx_port_add_broadcast(chip, port, vid);
205587fa886eSAndrew Lunn 		if (err)
205687fa886eSAndrew Lunn 			return err;
205787fa886eSAndrew Lunn 	}
205887fa886eSAndrew Lunn 
205987fa886eSAndrew Lunn 	return 0;
206087fa886eSAndrew Lunn }
206187fa886eSAndrew Lunn 
20628d1d8298STobias Waldekranz struct mv88e6xxx_port_broadcast_sync_ctx {
20638d1d8298STobias Waldekranz 	int port;
20648d1d8298STobias Waldekranz 	bool flood;
20658d1d8298STobias Waldekranz };
20668d1d8298STobias Waldekranz 
20678d1d8298STobias Waldekranz static int
20688d1d8298STobias Waldekranz mv88e6xxx_port_broadcast_sync_vlan(struct mv88e6xxx_chip *chip,
20698d1d8298STobias Waldekranz 				   const struct mv88e6xxx_vtu_entry *vlan,
20708d1d8298STobias Waldekranz 				   void *_ctx)
20718d1d8298STobias Waldekranz {
20728d1d8298STobias Waldekranz 	struct mv88e6xxx_port_broadcast_sync_ctx *ctx = _ctx;
20738d1d8298STobias Waldekranz 	u8 broadcast[ETH_ALEN];
20748d1d8298STobias Waldekranz 	u8 state;
20758d1d8298STobias Waldekranz 
20768d1d8298STobias Waldekranz 	if (ctx->flood)
20778d1d8298STobias Waldekranz 		state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
20788d1d8298STobias Waldekranz 	else
20798d1d8298STobias Waldekranz 		state = MV88E6XXX_G1_ATU_DATA_STATE_MC_UNUSED;
20808d1d8298STobias Waldekranz 
20818d1d8298STobias Waldekranz 	eth_broadcast_addr(broadcast);
20828d1d8298STobias Waldekranz 
20838d1d8298STobias Waldekranz 	return mv88e6xxx_port_db_load_purge(chip, ctx->port, broadcast,
20848d1d8298STobias Waldekranz 					    vlan->vid, state);
20858d1d8298STobias Waldekranz }
20868d1d8298STobias Waldekranz 
20878d1d8298STobias Waldekranz static int mv88e6xxx_port_broadcast_sync(struct mv88e6xxx_chip *chip, int port,
20888d1d8298STobias Waldekranz 					 bool flood)
20898d1d8298STobias Waldekranz {
20908d1d8298STobias Waldekranz 	struct mv88e6xxx_port_broadcast_sync_ctx ctx = {
20918d1d8298STobias Waldekranz 		.port = port,
20928d1d8298STobias Waldekranz 		.flood = flood,
20938d1d8298STobias Waldekranz 	};
20948d1d8298STobias Waldekranz 	struct mv88e6xxx_vtu_entry vid0 = {
20958d1d8298STobias Waldekranz 		.vid = 0,
20968d1d8298STobias Waldekranz 	};
20978d1d8298STobias Waldekranz 	int err;
20988d1d8298STobias Waldekranz 
20998d1d8298STobias Waldekranz 	/* Update the port's private database... */
21008d1d8298STobias Waldekranz 	err = mv88e6xxx_port_broadcast_sync_vlan(chip, &vid0, &ctx);
21018d1d8298STobias Waldekranz 	if (err)
21028d1d8298STobias Waldekranz 		return err;
21038d1d8298STobias Waldekranz 
21048d1d8298STobias Waldekranz 	/* ...and the database for all VLANs. */
21058d1d8298STobias Waldekranz 	return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_broadcast_sync_vlan,
21068d1d8298STobias Waldekranz 				  &ctx);
21078d1d8298STobias Waldekranz }
21088d1d8298STobias Waldekranz 
2109b1ac6fb4SVivien Didelot static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port,
2110933b4425SRussell King 				    u16 vid, u8 member, bool warn)
2111fad09c73SVivien Didelot {
2112b1ac6fb4SVivien Didelot 	const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
2113b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
2114b1ac6fb4SVivien Didelot 	int i, err;
2115fad09c73SVivien Didelot 
211634065c58STobias Waldekranz 	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
2117fad09c73SVivien Didelot 	if (err)
2118fad09c73SVivien Didelot 		return err;
2119fad09c73SVivien Didelot 
212034065c58STobias Waldekranz 	if (!vlan.valid) {
2121b1ac6fb4SVivien Didelot 		memset(&vlan, 0, sizeof(vlan));
2122b1ac6fb4SVivien Didelot 
2123b1ac6fb4SVivien Didelot 		err = mv88e6xxx_atu_new(chip, &vlan.fid);
2124b1ac6fb4SVivien Didelot 		if (err)
2125b1ac6fb4SVivien Didelot 			return err;
2126b1ac6fb4SVivien Didelot 
2127b1ac6fb4SVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
2128b1ac6fb4SVivien Didelot 			if (i == port)
2129b1ac6fb4SVivien Didelot 				vlan.member[i] = member;
2130b1ac6fb4SVivien Didelot 			else
2131b1ac6fb4SVivien Didelot 				vlan.member[i] = non_member;
2132b1ac6fb4SVivien Didelot 
2133b1ac6fb4SVivien Didelot 		vlan.vid = vid;
21341cb9dfcaSRasmus Villemoes 		vlan.valid = true;
2135fad09c73SVivien Didelot 
213687fa886eSAndrew Lunn 		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
213787fa886eSAndrew Lunn 		if (err)
213887fa886eSAndrew Lunn 			return err;
213987fa886eSAndrew Lunn 
2140b1ac6fb4SVivien Didelot 		err = mv88e6xxx_broadcast_setup(chip, vlan.vid);
2141b1ac6fb4SVivien Didelot 		if (err)
2142b1ac6fb4SVivien Didelot 			return err;
2143b1ac6fb4SVivien Didelot 	} else if (vlan.member[port] != member) {
2144b1ac6fb4SVivien Didelot 		vlan.member[port] = member;
2145b1ac6fb4SVivien Didelot 
2146b1ac6fb4SVivien Didelot 		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
2147b1ac6fb4SVivien Didelot 		if (err)
2148b1ac6fb4SVivien Didelot 			return err;
2149933b4425SRussell King 	} else if (warn) {
2150b1ac6fb4SVivien Didelot 		dev_info(chip->dev, "p%d: already a member of VLAN %d\n",
2151b1ac6fb4SVivien Didelot 			 port, vid);
2152b1ac6fb4SVivien Didelot 	}
2153b1ac6fb4SVivien Didelot 
2154b1ac6fb4SVivien Didelot 	return 0;
2155fad09c73SVivien Didelot }
2156fad09c73SVivien Didelot 
21571958d581SVladimir Oltean static int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
215831046a5fSVladimir Oltean 				   const struct switchdev_obj_port_vlan *vlan,
215931046a5fSVladimir Oltean 				   struct netlink_ext_ack *extack)
2160fad09c73SVivien Didelot {
216104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2162fad09c73SVivien Didelot 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
2163fad09c73SVivien Didelot 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
21648b6836d8SVladimir Oltean 	struct mv88e6xxx_port *p = &chip->ports[port];
2165933b4425SRussell King 	bool warn;
2166c91498e1SVivien Didelot 	u8 member;
21671958d581SVladimir Oltean 	int err;
2168fad09c73SVivien Didelot 
2169b8b79c41SEldar Gasanov 	if (!vlan->vid)
2170b8b79c41SEldar Gasanov 		return 0;
2171b8b79c41SEldar Gasanov 
21721958d581SVladimir Oltean 	err = mv88e6xxx_port_vlan_prepare(ds, port, vlan);
21731958d581SVladimir Oltean 	if (err)
21741958d581SVladimir Oltean 		return err;
2175fad09c73SVivien Didelot 
2176c91498e1SVivien Didelot 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
21777ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED;
2178c91498e1SVivien Didelot 	else if (untagged)
21797ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED;
2180c91498e1SVivien Didelot 	else
21817ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
2182c91498e1SVivien Didelot 
2183933b4425SRussell King 	/* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port
2184933b4425SRussell King 	 * and then the CPU port. Do not warn for duplicates for the CPU port.
2185933b4425SRussell King 	 */
2186933b4425SRussell King 	warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port);
2187933b4425SRussell King 
2188c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2189fad09c73SVivien Didelot 
21901958d581SVladimir Oltean 	err = mv88e6xxx_port_vlan_join(chip, port, vlan->vid, member, warn);
21911958d581SVladimir Oltean 	if (err) {
2192774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
2193b7a9e0daSVladimir Oltean 			vlan->vid, untagged ? 'u' : 't');
21941958d581SVladimir Oltean 		goto out;
21951958d581SVladimir Oltean 	}
2196fad09c73SVivien Didelot 
21971958d581SVladimir Oltean 	if (pvid) {
21988b6836d8SVladimir Oltean 		p->bridge_pvid.vid = vlan->vid;
21998b6836d8SVladimir Oltean 		p->bridge_pvid.valid = true;
22008b6836d8SVladimir Oltean 
22018b6836d8SVladimir Oltean 		err = mv88e6xxx_port_commit_pvid(chip, port);
22028b6836d8SVladimir Oltean 		if (err)
22038b6836d8SVladimir Oltean 			goto out;
22048b6836d8SVladimir Oltean 	} else if (vlan->vid && p->bridge_pvid.vid == vlan->vid) {
22058b6836d8SVladimir Oltean 		/* The old pvid was reinstalled as a non-pvid VLAN */
22068b6836d8SVladimir Oltean 		p->bridge_pvid.valid = false;
22078b6836d8SVladimir Oltean 
22088b6836d8SVladimir Oltean 		err = mv88e6xxx_port_commit_pvid(chip, port);
22098b6836d8SVladimir Oltean 		if (err)
22101958d581SVladimir Oltean 			goto out;
22111958d581SVladimir Oltean 	}
22128b6836d8SVladimir Oltean 
22131958d581SVladimir Oltean out:
2214c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
22151958d581SVladimir Oltean 
22161958d581SVladimir Oltean 	return err;
2217fad09c73SVivien Didelot }
2218fad09c73SVivien Didelot 
221952109892SVivien Didelot static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip,
2220fad09c73SVivien Didelot 				     int port, u16 vid)
2221fad09c73SVivien Didelot {
2222b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
2223fad09c73SVivien Didelot 	int i, err;
2224fad09c73SVivien Didelot 
222552109892SVivien Didelot 	if (!vid)
2226c92c7413SVladimir Oltean 		return 0;
222752109892SVivien Didelot 
222834065c58STobias Waldekranz 	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
2229fad09c73SVivien Didelot 	if (err)
2230fad09c73SVivien Didelot 		return err;
2231fad09c73SVivien Didelot 
223252109892SVivien Didelot 	/* If the VLAN doesn't exist in hardware or the port isn't a member,
223352109892SVivien Didelot 	 * tell switchdev that this VLAN is likely handled in software.
223452109892SVivien Didelot 	 */
223534065c58STobias Waldekranz 	if (!vlan.valid ||
223652109892SVivien Didelot 	    vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
2237fad09c73SVivien Didelot 		return -EOPNOTSUPP;
2238fad09c73SVivien Didelot 
22397ec60d6eSVivien Didelot 	vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
2240fad09c73SVivien Didelot 
2241fad09c73SVivien Didelot 	/* keep the VLAN unless all ports are excluded */
2242fad09c73SVivien Didelot 	vlan.valid = false;
2243370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
22447ec60d6eSVivien Didelot 		if (vlan.member[i] !=
22457ec60d6eSVivien Didelot 		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
2246fad09c73SVivien Didelot 			vlan.valid = true;
2247fad09c73SVivien Didelot 			break;
2248fad09c73SVivien Didelot 		}
2249fad09c73SVivien Didelot 	}
2250fad09c73SVivien Didelot 
22510ad5daf6SVivien Didelot 	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
2252fad09c73SVivien Didelot 	if (err)
2253fad09c73SVivien Didelot 		return err;
2254fad09c73SVivien Didelot 
2255e606ca36SVivien Didelot 	return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
2256fad09c73SVivien Didelot }
2257fad09c73SVivien Didelot 
2258fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
2259fad09c73SVivien Didelot 				   const struct switchdev_obj_port_vlan *vlan)
2260fad09c73SVivien Didelot {
226104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
22628b6836d8SVladimir Oltean 	struct mv88e6xxx_port *p = &chip->ports[port];
2263fad09c73SVivien Didelot 	int err = 0;
2264b7a9e0daSVladimir Oltean 	u16 pvid;
2265fad09c73SVivien Didelot 
2266e545f865STobias Waldekranz 	if (!mv88e6xxx_max_vid(chip))
2267fad09c73SVivien Didelot 		return -EOPNOTSUPP;
2268fad09c73SVivien Didelot 
2269c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2270fad09c73SVivien Didelot 
227177064f37SVivien Didelot 	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
2272fad09c73SVivien Didelot 	if (err)
2273fad09c73SVivien Didelot 		goto unlock;
2274fad09c73SVivien Didelot 
2275b7a9e0daSVladimir Oltean 	err = mv88e6xxx_port_vlan_leave(chip, port, vlan->vid);
2276fad09c73SVivien Didelot 	if (err)
2277fad09c73SVivien Didelot 		goto unlock;
2278fad09c73SVivien Didelot 
2279b7a9e0daSVladimir Oltean 	if (vlan->vid == pvid) {
22808b6836d8SVladimir Oltean 		p->bridge_pvid.valid = false;
22818b6836d8SVladimir Oltean 
22828b6836d8SVladimir Oltean 		err = mv88e6xxx_port_commit_pvid(chip, port);
2283fad09c73SVivien Didelot 		if (err)
2284fad09c73SVivien Didelot 			goto unlock;
2285fad09c73SVivien Didelot 	}
2286fad09c73SVivien Didelot 
2287fad09c73SVivien Didelot unlock:
2288c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2289fad09c73SVivien Didelot 
2290fad09c73SVivien Didelot 	return err;
2291fad09c73SVivien Didelot }
2292fad09c73SVivien Didelot 
22931b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
22946c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
2295fad09c73SVivien Didelot {
229604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
22971b6dd556SArkadi Sharshevsky 	int err;
2298fad09c73SVivien Didelot 
2299c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
23001b6dd556SArkadi Sharshevsky 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
23011b6dd556SArkadi Sharshevsky 					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
2302c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
23031b6dd556SArkadi Sharshevsky 
23041b6dd556SArkadi Sharshevsky 	return err;
2305fad09c73SVivien Didelot }
2306fad09c73SVivien Didelot 
2307fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
23086c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
2309fad09c73SVivien Didelot {
231004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
231183dabd1fSVivien Didelot 	int err;
2312fad09c73SVivien Didelot 
2313c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2314d8291a95SVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
2315c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2316fad09c73SVivien Didelot 
231783dabd1fSVivien Didelot 	return err;
2318fad09c73SVivien Didelot }
2319fad09c73SVivien Didelot 
232083dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
2321fad09c73SVivien Didelot 				      u16 fid, u16 vid, int port,
23222bedde1aSArkadi Sharshevsky 				      dsa_fdb_dump_cb_t *cb, void *data)
2323fad09c73SVivien Didelot {
2324dabc1a96SVivien Didelot 	struct mv88e6xxx_atu_entry addr;
23252bedde1aSArkadi Sharshevsky 	bool is_static;
2326fad09c73SVivien Didelot 	int err;
2327fad09c73SVivien Didelot 
2328d8291a95SVivien Didelot 	addr.state = 0;
2329dabc1a96SVivien Didelot 	eth_broadcast_addr(addr.mac);
2330fad09c73SVivien Didelot 
2331fad09c73SVivien Didelot 	do {
2332dabc1a96SVivien Didelot 		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
2333fad09c73SVivien Didelot 		if (err)
233483dabd1fSVivien Didelot 			return err;
2335fad09c73SVivien Didelot 
2336d8291a95SVivien Didelot 		if (!addr.state)
2337fad09c73SVivien Didelot 			break;
2338fad09c73SVivien Didelot 
233901bd96c8SVivien Didelot 		if (addr.trunk || (addr.portvec & BIT(port)) == 0)
234083dabd1fSVivien Didelot 			continue;
2341fad09c73SVivien Didelot 
234283dabd1fSVivien Didelot 		if (!is_unicast_ether_addr(addr.mac))
234383dabd1fSVivien Didelot 			continue;
234483dabd1fSVivien Didelot 
23452bedde1aSArkadi Sharshevsky 		is_static = (addr.state ==
23462bedde1aSArkadi Sharshevsky 			     MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
23472bedde1aSArkadi Sharshevsky 		err = cb(addr.mac, vid, is_static, data);
234883dabd1fSVivien Didelot 		if (err)
234983dabd1fSVivien Didelot 			return err;
2350fad09c73SVivien Didelot 	} while (!is_broadcast_ether_addr(addr.mac));
2351fad09c73SVivien Didelot 
2352fad09c73SVivien Didelot 	return err;
2353fad09c73SVivien Didelot }
2354fad09c73SVivien Didelot 
2355d89ef4b8STobias Waldekranz struct mv88e6xxx_port_db_dump_vlan_ctx {
2356d89ef4b8STobias Waldekranz 	int port;
2357d89ef4b8STobias Waldekranz 	dsa_fdb_dump_cb_t *cb;
2358d89ef4b8STobias Waldekranz 	void *data;
2359d89ef4b8STobias Waldekranz };
2360d89ef4b8STobias Waldekranz 
2361d89ef4b8STobias Waldekranz static int mv88e6xxx_port_db_dump_vlan(struct mv88e6xxx_chip *chip,
2362d89ef4b8STobias Waldekranz 				       const struct mv88e6xxx_vtu_entry *entry,
2363d89ef4b8STobias Waldekranz 				       void *_data)
2364d89ef4b8STobias Waldekranz {
2365d89ef4b8STobias Waldekranz 	struct mv88e6xxx_port_db_dump_vlan_ctx *ctx = _data;
2366d89ef4b8STobias Waldekranz 
2367d89ef4b8STobias Waldekranz 	return mv88e6xxx_port_db_dump_fid(chip, entry->fid, entry->vid,
2368d89ef4b8STobias Waldekranz 					  ctx->port, ctx->cb, ctx->data);
2369d89ef4b8STobias Waldekranz }
2370d89ef4b8STobias Waldekranz 
237183dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
23722bedde1aSArkadi Sharshevsky 				  dsa_fdb_dump_cb_t *cb, void *data)
237383dabd1fSVivien Didelot {
2374d89ef4b8STobias Waldekranz 	struct mv88e6xxx_port_db_dump_vlan_ctx ctx = {
2375d89ef4b8STobias Waldekranz 		.port = port,
2376d89ef4b8STobias Waldekranz 		.cb = cb,
2377d89ef4b8STobias Waldekranz 		.data = data,
2378d89ef4b8STobias Waldekranz 	};
237983dabd1fSVivien Didelot 	u16 fid;
238083dabd1fSVivien Didelot 	int err;
238183dabd1fSVivien Didelot 
238283dabd1fSVivien Didelot 	/* Dump port's default Filtering Information Database (VLAN ID 0) */
2383b4e48c50SVivien Didelot 	err = mv88e6xxx_port_get_fid(chip, port, &fid);
238483dabd1fSVivien Didelot 	if (err)
238583dabd1fSVivien Didelot 		return err;
238683dabd1fSVivien Didelot 
23872bedde1aSArkadi Sharshevsky 	err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data);
238883dabd1fSVivien Didelot 	if (err)
238983dabd1fSVivien Didelot 		return err;
239083dabd1fSVivien Didelot 
2391d89ef4b8STobias Waldekranz 	return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_db_dump_vlan, &ctx);
239283dabd1fSVivien Didelot }
239383dabd1fSVivien Didelot 
2394fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
23952bedde1aSArkadi Sharshevsky 				   dsa_fdb_dump_cb_t *cb, void *data)
2396fad09c73SVivien Didelot {
239704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2398fcf15367SVivien Didelot 	int err;
2399fad09c73SVivien Didelot 
2400c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2401fcf15367SVivien Didelot 	err = mv88e6xxx_port_db_dump(chip, port, cb, data);
2402c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2403fcf15367SVivien Didelot 
2404fcf15367SVivien Didelot 	return err;
2405fad09c73SVivien Didelot }
2406fad09c73SVivien Didelot 
2407240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
2408240ea3efSVivien Didelot 				struct net_device *br)
2409240ea3efSVivien Didelot {
2410ef2025ecSVivien Didelot 	struct dsa_switch *ds = chip->ds;
2411ef2025ecSVivien Didelot 	struct dsa_switch_tree *dst = ds->dst;
2412ef2025ecSVivien Didelot 	struct dsa_port *dp;
2413240ea3efSVivien Didelot 	int err;
2414240ea3efSVivien Didelot 
2415ef2025ecSVivien Didelot 	list_for_each_entry(dp, &dst->ports, list) {
2416ef2025ecSVivien Didelot 		if (dp->bridge_dev == br) {
2417ef2025ecSVivien Didelot 			if (dp->ds == ds) {
2418ef2025ecSVivien Didelot 				/* This is a local bridge group member,
2419ef2025ecSVivien Didelot 				 * remap its Port VLAN Map.
2420ef2025ecSVivien Didelot 				 */
2421ef2025ecSVivien Didelot 				err = mv88e6xxx_port_vlan_map(chip, dp->index);
2422240ea3efSVivien Didelot 				if (err)
2423240ea3efSVivien Didelot 					return err;
2424ef2025ecSVivien Didelot 			} else {
2425ef2025ecSVivien Didelot 				/* This is an external bridge group member,
2426ef2025ecSVivien Didelot 				 * remap its cross-chip Port VLAN Table entry.
2427ef2025ecSVivien Didelot 				 */
2428ef2025ecSVivien Didelot 				err = mv88e6xxx_pvt_map(chip, dp->ds->index,
2429ef2025ecSVivien Didelot 							dp->index);
2430e96a6e02SVivien Didelot 				if (err)
2431e96a6e02SVivien Didelot 					return err;
2432e96a6e02SVivien Didelot 			}
2433e96a6e02SVivien Didelot 		}
2434e96a6e02SVivien Didelot 	}
2435e96a6e02SVivien Didelot 
2436240ea3efSVivien Didelot 	return 0;
2437240ea3efSVivien Didelot }
2438240ea3efSVivien Didelot 
2439fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
2440fae8a25eSVivien Didelot 				      struct net_device *br)
2441fad09c73SVivien Didelot {
244204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2443240ea3efSVivien Didelot 	int err;
2444fad09c73SVivien Didelot 
2445c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
24465bded825SVladimir Oltean 
2447240ea3efSVivien Didelot 	err = mv88e6xxx_bridge_map(chip, br);
24485bded825SVladimir Oltean 	if (err)
24495bded825SVladimir Oltean 		goto unlock;
24505bded825SVladimir Oltean 
24515bded825SVladimir Oltean 	err = mv88e6xxx_port_commit_pvid(chip, port);
24525bded825SVladimir Oltean 	if (err)
24535bded825SVladimir Oltean 		goto unlock;
24545bded825SVladimir Oltean 
24555bded825SVladimir Oltean unlock:
2456c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2457fad09c73SVivien Didelot 
2458fad09c73SVivien Didelot 	return err;
2459fad09c73SVivien Didelot }
2460fad09c73SVivien Didelot 
2461f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
2462f123f2fbSVivien Didelot 					struct net_device *br)
2463fad09c73SVivien Didelot {
246404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
24655bded825SVladimir Oltean 	int err;
2466fad09c73SVivien Didelot 
2467c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
24685bded825SVladimir Oltean 
2469240ea3efSVivien Didelot 	if (mv88e6xxx_bridge_map(chip, br) ||
2470240ea3efSVivien Didelot 	    mv88e6xxx_port_vlan_map(chip, port))
2471240ea3efSVivien Didelot 		dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
24725bded825SVladimir Oltean 
24735bded825SVladimir Oltean 	err = mv88e6xxx_port_commit_pvid(chip, port);
24745bded825SVladimir Oltean 	if (err)
24755bded825SVladimir Oltean 		dev_err(ds->dev,
24765bded825SVladimir Oltean 			"port %d failed to restore standalone pvid: %pe\n",
24775bded825SVladimir Oltean 			port, ERR_PTR(err));
24785bded825SVladimir Oltean 
2479c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2480fad09c73SVivien Didelot }
2481fad09c73SVivien Didelot 
2482f66a6a69SVladimir Oltean static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds,
2483f66a6a69SVladimir Oltean 					   int tree_index, int sw_index,
2484aec5ac88SVivien Didelot 					   int port, struct net_device *br)
2485aec5ac88SVivien Didelot {
2486aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2487aec5ac88SVivien Didelot 	int err;
2488aec5ac88SVivien Didelot 
2489f66a6a69SVladimir Oltean 	if (tree_index != ds->dst->index)
2490f66a6a69SVladimir Oltean 		return 0;
2491f66a6a69SVladimir Oltean 
2492c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2493f66a6a69SVladimir Oltean 	err = mv88e6xxx_pvt_map(chip, sw_index, port);
2494c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2495aec5ac88SVivien Didelot 
2496aec5ac88SVivien Didelot 	return err;
2497aec5ac88SVivien Didelot }
2498aec5ac88SVivien Didelot 
2499f66a6a69SVladimir Oltean static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds,
2500f66a6a69SVladimir Oltean 					     int tree_index, int sw_index,
2501aec5ac88SVivien Didelot 					     int port, struct net_device *br)
2502aec5ac88SVivien Didelot {
2503aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2504aec5ac88SVivien Didelot 
2505f66a6a69SVladimir Oltean 	if (tree_index != ds->dst->index)
2506f66a6a69SVladimir Oltean 		return;
2507f66a6a69SVladimir Oltean 
2508c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
2509f66a6a69SVladimir Oltean 	if (mv88e6xxx_pvt_map(chip, sw_index, port))
2510aec5ac88SVivien Didelot 		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
2511c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
2512aec5ac88SVivien Didelot }
2513aec5ac88SVivien Didelot 
2514ce5df689SVladimir Oltean /* Treat the software bridge as a virtual single-port switch behind the
2515ce5df689SVladimir Oltean  * CPU and map in the PVT. First dst->last_switch elements are taken by
2516ce5df689SVladimir Oltean  * physical switches, so start from beyond that range.
2517ce5df689SVladimir Oltean  */
2518ce5df689SVladimir Oltean static int mv88e6xxx_map_virtual_bridge_to_pvt(struct dsa_switch *ds,
25193f9bb030SVladimir Oltean 					       unsigned int bridge_num)
2520ce5df689SVladimir Oltean {
25213f9bb030SVladimir Oltean 	u8 dev = bridge_num + ds->dst->last_switch;
2522ce5df689SVladimir Oltean 	struct mv88e6xxx_chip *chip = ds->priv;
2523ce5df689SVladimir Oltean 	int err;
2524ce5df689SVladimir Oltean 
2525ce5df689SVladimir Oltean 	mv88e6xxx_reg_lock(chip);
2526ce5df689SVladimir Oltean 	err = mv88e6xxx_pvt_map(chip, dev, 0);
2527ce5df689SVladimir Oltean 	mv88e6xxx_reg_unlock(chip);
2528ce5df689SVladimir Oltean 
2529ce5df689SVladimir Oltean 	return err;
2530ce5df689SVladimir Oltean }
2531ce5df689SVladimir Oltean 
2532ce5df689SVladimir Oltean static int mv88e6xxx_bridge_tx_fwd_offload(struct dsa_switch *ds, int port,
2533ce5df689SVladimir Oltean 					   struct net_device *br,
25343f9bb030SVladimir Oltean 					   unsigned int bridge_num)
2535ce5df689SVladimir Oltean {
2536ce5df689SVladimir Oltean 	return mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge_num);
2537ce5df689SVladimir Oltean }
2538ce5df689SVladimir Oltean 
2539ce5df689SVladimir Oltean static void mv88e6xxx_bridge_tx_fwd_unoffload(struct dsa_switch *ds, int port,
2540ce5df689SVladimir Oltean 					      struct net_device *br,
25413f9bb030SVladimir Oltean 					      unsigned int bridge_num)
2542ce5df689SVladimir Oltean {
2543ce5df689SVladimir Oltean 	int err;
2544ce5df689SVladimir Oltean 
2545ce5df689SVladimir Oltean 	err = mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge_num);
2546ce5df689SVladimir Oltean 	if (err) {
2547ce5df689SVladimir Oltean 		dev_err(ds->dev, "failed to remap cross-chip Port VLAN: %pe\n",
2548ce5df689SVladimir Oltean 			ERR_PTR(err));
2549ce5df689SVladimir Oltean 	}
2550ce5df689SVladimir Oltean }
2551ce5df689SVladimir Oltean 
255217e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
255317e708baSVivien Didelot {
255417e708baSVivien Didelot 	if (chip->info->ops->reset)
255517e708baSVivien Didelot 		return chip->info->ops->reset(chip);
255617e708baSVivien Didelot 
255717e708baSVivien Didelot 	return 0;
255817e708baSVivien Didelot }
255917e708baSVivien Didelot 
2560309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
2561309eca6dSVivien Didelot {
2562309eca6dSVivien Didelot 	struct gpio_desc *gpiod = chip->reset;
2563309eca6dSVivien Didelot 
2564309eca6dSVivien Didelot 	/* If there is a GPIO connected to the reset pin, toggle it */
2565309eca6dSVivien Didelot 	if (gpiod) {
2566309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 1);
2567309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2568309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 0);
2569309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2570a3dcb3e7SAndrew Lunn 
2571a3dcb3e7SAndrew Lunn 		mv88e6xxx_g1_wait_eeprom_done(chip);
2572309eca6dSVivien Didelot 	}
2573309eca6dSVivien Didelot }
2574309eca6dSVivien Didelot 
25754ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
25764ac4b5a6SVivien Didelot {
25774ac4b5a6SVivien Didelot 	int i, err;
25784ac4b5a6SVivien Didelot 
25794ac4b5a6SVivien Didelot 	/* Set all ports to the Disabled state */
25804ac4b5a6SVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2581f894c29cSVivien Didelot 		err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED);
25824ac4b5a6SVivien Didelot 		if (err)
25834ac4b5a6SVivien Didelot 			return err;
25844ac4b5a6SVivien Didelot 	}
25854ac4b5a6SVivien Didelot 
25864ac4b5a6SVivien Didelot 	/* Wait for transmit queues to drain,
25874ac4b5a6SVivien Didelot 	 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
25884ac4b5a6SVivien Didelot 	 */
25894ac4b5a6SVivien Didelot 	usleep_range(2000, 4000);
25904ac4b5a6SVivien Didelot 
25914ac4b5a6SVivien Didelot 	return 0;
25924ac4b5a6SVivien Didelot }
25934ac4b5a6SVivien Didelot 
2594fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
2595fad09c73SVivien Didelot {
2596a935c052SVivien Didelot 	int err;
2597fad09c73SVivien Didelot 
25984ac4b5a6SVivien Didelot 	err = mv88e6xxx_disable_ports(chip);
25990e7b9925SAndrew Lunn 	if (err)
26000e7b9925SAndrew Lunn 		return err;
2601fad09c73SVivien Didelot 
2602309eca6dSVivien Didelot 	mv88e6xxx_hardware_reset(chip);
2603fad09c73SVivien Didelot 
260417e708baSVivien Didelot 	return mv88e6xxx_software_reset(chip);
2605fad09c73SVivien Didelot }
2606fad09c73SVivien Didelot 
26074314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
260831bef4e9SVivien Didelot 				   enum mv88e6xxx_frame_mode frame,
260931bef4e9SVivien Didelot 				   enum mv88e6xxx_egress_mode egress, u16 etype)
261056995cbcSAndrew Lunn {
261156995cbcSAndrew Lunn 	int err;
261256995cbcSAndrew Lunn 
26134314557cSVivien Didelot 	if (!chip->info->ops->port_set_frame_mode)
26144314557cSVivien Didelot 		return -EOPNOTSUPP;
26154314557cSVivien Didelot 
26164314557cSVivien Didelot 	err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
261756995cbcSAndrew Lunn 	if (err)
261856995cbcSAndrew Lunn 		return err;
261956995cbcSAndrew Lunn 
26204314557cSVivien Didelot 	err = chip->info->ops->port_set_frame_mode(chip, port, frame);
26214314557cSVivien Didelot 	if (err)
26224314557cSVivien Didelot 		return err;
26234314557cSVivien Didelot 
26244314557cSVivien Didelot 	if (chip->info->ops->port_set_ether_type)
26254314557cSVivien Didelot 		return chip->info->ops->port_set_ether_type(chip, port, etype);
26264314557cSVivien Didelot 
26274314557cSVivien Didelot 	return 0;
26284314557cSVivien Didelot }
26294314557cSVivien Didelot 
26304314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
26314314557cSVivien Didelot {
26324314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
263331bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2634b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
26354314557cSVivien Didelot }
26364314557cSVivien Didelot 
26374314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
26384314557cSVivien Didelot {
26394314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
264031bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2641b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
26424314557cSVivien Didelot }
26434314557cSVivien Didelot 
26444314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
26454314557cSVivien Didelot {
26464314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port,
26474314557cSVivien Didelot 				       MV88E6XXX_FRAME_MODE_ETHERTYPE,
264831bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_ETHERTYPE,
264931bef4e9SVivien Didelot 				       ETH_P_EDSA);
26504314557cSVivien Didelot }
26514314557cSVivien Didelot 
26524314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port)
26534314557cSVivien Didelot {
26544314557cSVivien Didelot 	if (dsa_is_dsa_port(chip->ds, port))
26554314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
26564314557cSVivien Didelot 
26572b3e9891SVivien Didelot 	if (dsa_is_user_port(chip->ds, port))
26584314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_normal(chip, port);
26594314557cSVivien Didelot 
26604314557cSVivien Didelot 	/* Setup CPU port mode depending on its supported tag format */
2661670bb80fSTobias Waldekranz 	if (chip->tag_protocol == DSA_TAG_PROTO_DSA)
26624314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
26634314557cSVivien Didelot 
2664670bb80fSTobias Waldekranz 	if (chip->tag_protocol == DSA_TAG_PROTO_EDSA)
26654314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_edsa(chip, port);
26664314557cSVivien Didelot 
26674314557cSVivien Didelot 	return -EINVAL;
26684314557cSVivien Didelot }
26694314557cSVivien Didelot 
2670ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
2671ea698f4fSVivien Didelot {
2672ea698f4fSVivien Didelot 	bool message = dsa_is_dsa_port(chip->ds, port);
2673ea698f4fSVivien Didelot 
2674ea698f4fSVivien Didelot 	return mv88e6xxx_port_set_message_port(chip, port, message);
2675ea698f4fSVivien Didelot }
2676ea698f4fSVivien Didelot 
2677601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
2678601aeed3SVivien Didelot {
2679a8b659e7SVladimir Oltean 	int err;
2680601aeed3SVivien Didelot 
2681a8b659e7SVladimir Oltean 	if (chip->info->ops->port_set_ucast_flood) {
26827b9f16feSTobias Waldekranz 		err = chip->info->ops->port_set_ucast_flood(chip, port, true);
2683a8b659e7SVladimir Oltean 		if (err)
2684a8b659e7SVladimir Oltean 			return err;
2685a8b659e7SVladimir Oltean 	}
2686a8b659e7SVladimir Oltean 	if (chip->info->ops->port_set_mcast_flood) {
26877b9f16feSTobias Waldekranz 		err = chip->info->ops->port_set_mcast_flood(chip, port, true);
2688a8b659e7SVladimir Oltean 		if (err)
2689a8b659e7SVladimir Oltean 			return err;
2690a8b659e7SVladimir Oltean 	}
2691407308f6SDavid S. Miller 
2692601aeed3SVivien Didelot 	return 0;
2693601aeed3SVivien Didelot }
2694601aeed3SVivien Didelot 
269545de77ffSVivien Didelot static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
269645de77ffSVivien Didelot {
269745de77ffSVivien Didelot 	struct mv88e6xxx_port *mvp = dev_id;
269845de77ffSVivien Didelot 	struct mv88e6xxx_chip *chip = mvp->chip;
269945de77ffSVivien Didelot 	irqreturn_t ret = IRQ_NONE;
270045de77ffSVivien Didelot 	int port = mvp->port;
2701193c5b26SPavana Sharma 	int lane;
270245de77ffSVivien Didelot 
270345de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
270445de77ffSVivien Didelot 	lane = mv88e6xxx_serdes_get_lane(chip, port);
2705193c5b26SPavana Sharma 	if (lane >= 0)
270645de77ffSVivien Didelot 		ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
270745de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
270845de77ffSVivien Didelot 
270945de77ffSVivien Didelot 	return ret;
271045de77ffSVivien Didelot }
271145de77ffSVivien Didelot 
271245de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
2713193c5b26SPavana Sharma 					int lane)
271445de77ffSVivien Didelot {
271545de77ffSVivien Didelot 	struct mv88e6xxx_port *dev_id = &chip->ports[port];
271645de77ffSVivien Didelot 	unsigned int irq;
271745de77ffSVivien Didelot 	int err;
271845de77ffSVivien Didelot 
271945de77ffSVivien Didelot 	/* Nothing to request if this SERDES port has no IRQ */
272045de77ffSVivien Didelot 	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
272145de77ffSVivien Didelot 	if (!irq)
272245de77ffSVivien Didelot 		return 0;
272345de77ffSVivien Didelot 
2724e6f2f6b8SAndrew Lunn 	snprintf(dev_id->serdes_irq_name, sizeof(dev_id->serdes_irq_name),
2725e6f2f6b8SAndrew Lunn 		 "mv88e6xxx-%s-serdes-%d", dev_name(chip->dev), port);
2726e6f2f6b8SAndrew Lunn 
272745de77ffSVivien Didelot 	/* Requesting the IRQ will trigger IRQ callbacks, so release the lock */
272845de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
272945de77ffSVivien Didelot 	err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn,
2730e6f2f6b8SAndrew Lunn 				   IRQF_ONESHOT, dev_id->serdes_irq_name,
2731e6f2f6b8SAndrew Lunn 				   dev_id);
273245de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
273345de77ffSVivien Didelot 	if (err)
273445de77ffSVivien Didelot 		return err;
273545de77ffSVivien Didelot 
273645de77ffSVivien Didelot 	dev_id->serdes_irq = irq;
273745de77ffSVivien Didelot 
273845de77ffSVivien Didelot 	return mv88e6xxx_serdes_irq_enable(chip, port, lane);
273945de77ffSVivien Didelot }
274045de77ffSVivien Didelot 
274145de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
2742193c5b26SPavana Sharma 				     int lane)
274345de77ffSVivien Didelot {
274445de77ffSVivien Didelot 	struct mv88e6xxx_port *dev_id = &chip->ports[port];
274545de77ffSVivien Didelot 	unsigned int irq = dev_id->serdes_irq;
274645de77ffSVivien Didelot 	int err;
274745de77ffSVivien Didelot 
274845de77ffSVivien Didelot 	/* Nothing to free if no IRQ has been requested */
274945de77ffSVivien Didelot 	if (!irq)
275045de77ffSVivien Didelot 		return 0;
275145de77ffSVivien Didelot 
275245de77ffSVivien Didelot 	err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
275345de77ffSVivien Didelot 
275445de77ffSVivien Didelot 	/* Freeing the IRQ will trigger IRQ callbacks, so release the lock */
275545de77ffSVivien Didelot 	mv88e6xxx_reg_unlock(chip);
275645de77ffSVivien Didelot 	free_irq(irq, dev_id);
275745de77ffSVivien Didelot 	mv88e6xxx_reg_lock(chip);
275845de77ffSVivien Didelot 
275945de77ffSVivien Didelot 	dev_id->serdes_irq = 0;
276045de77ffSVivien Didelot 
276145de77ffSVivien Didelot 	return err;
276245de77ffSVivien Didelot }
276345de77ffSVivien Didelot 
27646d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
27656d91782fSAndrew Lunn 				  bool on)
27666d91782fSAndrew Lunn {
2767193c5b26SPavana Sharma 	int lane;
2768fc0bc019SVivien Didelot 	int err;
27696d91782fSAndrew Lunn 
2770dc272f60SVivien Didelot 	lane = mv88e6xxx_serdes_get_lane(chip, port);
2771193c5b26SPavana Sharma 	if (lane < 0)
2772523a8904SVivien Didelot 		return 0;
2773fc0bc019SVivien Didelot 
2774fc0bc019SVivien Didelot 	if (on) {
2775dc272f60SVivien Didelot 		err = mv88e6xxx_serdes_power_up(chip, port, lane);
2776fc0bc019SVivien Didelot 		if (err)
2777fc0bc019SVivien Didelot 			return err;
2778fc0bc019SVivien Didelot 
277945de77ffSVivien Didelot 		err = mv88e6xxx_serdes_irq_request(chip, port, lane);
2780fc0bc019SVivien Didelot 	} else {
278145de77ffSVivien Didelot 		err = mv88e6xxx_serdes_irq_free(chip, port, lane);
278245de77ffSVivien Didelot 		if (err)
278345de77ffSVivien Didelot 			return err;
2784fc0bc019SVivien Didelot 
2785dc272f60SVivien Didelot 		err = mv88e6xxx_serdes_power_down(chip, port, lane);
2786fc0bc019SVivien Didelot 	}
2787fc0bc019SVivien Didelot 
2788fc0bc019SVivien Didelot 	return err;
27896d91782fSAndrew Lunn }
27906d91782fSAndrew Lunn 
27912fda45f0SMarek Behún static int mv88e6xxx_set_egress_port(struct mv88e6xxx_chip *chip,
27922fda45f0SMarek Behún 				     enum mv88e6xxx_egress_direction direction,
27932fda45f0SMarek Behún 				     int port)
27942fda45f0SMarek Behún {
27952fda45f0SMarek Behún 	int err;
27962fda45f0SMarek Behún 
27972fda45f0SMarek Behún 	if (!chip->info->ops->set_egress_port)
27982fda45f0SMarek Behún 		return -EOPNOTSUPP;
27992fda45f0SMarek Behún 
28002fda45f0SMarek Behún 	err = chip->info->ops->set_egress_port(chip, direction, port);
28012fda45f0SMarek Behún 	if (err)
28022fda45f0SMarek Behún 		return err;
28032fda45f0SMarek Behún 
28042fda45f0SMarek Behún 	if (direction == MV88E6XXX_EGRESS_DIR_INGRESS)
28052fda45f0SMarek Behún 		chip->ingress_dest_port = port;
28062fda45f0SMarek Behún 	else
28072fda45f0SMarek Behún 		chip->egress_dest_port = port;
28082fda45f0SMarek Behún 
28092fda45f0SMarek Behún 	return 0;
28102fda45f0SMarek Behún }
28112fda45f0SMarek Behún 
2812fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
2813fa371c80SVivien Didelot {
2814fa371c80SVivien Didelot 	struct dsa_switch *ds = chip->ds;
2815fa371c80SVivien Didelot 	int upstream_port;
2816fa371c80SVivien Didelot 	int err;
2817fa371c80SVivien Didelot 
281807073c79SVivien Didelot 	upstream_port = dsa_upstream_port(ds, port);
2819fa371c80SVivien Didelot 	if (chip->info->ops->port_set_upstream_port) {
2820fa371c80SVivien Didelot 		err = chip->info->ops->port_set_upstream_port(chip, port,
2821fa371c80SVivien Didelot 							      upstream_port);
2822fa371c80SVivien Didelot 		if (err)
2823fa371c80SVivien Didelot 			return err;
2824fa371c80SVivien Didelot 	}
2825fa371c80SVivien Didelot 
28260ea54ddaSVivien Didelot 	if (port == upstream_port) {
28270ea54ddaSVivien Didelot 		if (chip->info->ops->set_cpu_port) {
28280ea54ddaSVivien Didelot 			err = chip->info->ops->set_cpu_port(chip,
28290ea54ddaSVivien Didelot 							    upstream_port);
28300ea54ddaSVivien Didelot 			if (err)
28310ea54ddaSVivien Didelot 				return err;
28320ea54ddaSVivien Didelot 		}
28330ea54ddaSVivien Didelot 
28342fda45f0SMarek Behún 		err = mv88e6xxx_set_egress_port(chip,
28355c74c54cSIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS,
28365c74c54cSIwan R Timmer 						upstream_port);
28372fda45f0SMarek Behún 		if (err && err != -EOPNOTSUPP)
28385c74c54cSIwan R Timmer 			return err;
28395c74c54cSIwan R Timmer 
28402fda45f0SMarek Behún 		err = mv88e6xxx_set_egress_port(chip,
28415c74c54cSIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS,
28420ea54ddaSVivien Didelot 						upstream_port);
28432fda45f0SMarek Behún 		if (err && err != -EOPNOTSUPP)
28440ea54ddaSVivien Didelot 			return err;
28450ea54ddaSVivien Didelot 	}
28460ea54ddaSVivien Didelot 
2847fa371c80SVivien Didelot 	return 0;
2848fa371c80SVivien Didelot }
2849fa371c80SVivien Didelot 
2850fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
2851fad09c73SVivien Didelot {
2852fad09c73SVivien Didelot 	struct dsa_switch *ds = chip->ds;
28530e7b9925SAndrew Lunn 	int err;
2854fad09c73SVivien Didelot 	u16 reg;
2855fad09c73SVivien Didelot 
28567b898469SAndrew Lunn 	chip->ports[port].chip = chip;
28577b898469SAndrew Lunn 	chip->ports[port].port = port;
28587b898469SAndrew Lunn 
2859d78343d2SVivien Didelot 	/* MAC Forcing register: don't force link, speed, duplex or flow control
2860d78343d2SVivien Didelot 	 * state to any particular values on physical ports, but force the CPU
2861d78343d2SVivien Didelot 	 * port and all DSA ports to their maximum bandwidth and full duplex.
2862fad09c73SVivien Didelot 	 */
2863d78343d2SVivien Didelot 	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
2864d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
2865d78343d2SVivien Didelot 					       SPEED_MAX, DUPLEX_FULL,
286654186b91SAndrew Lunn 					       PAUSE_OFF,
2867d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
2868fad09c73SVivien Didelot 	else
2869d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
2870d78343d2SVivien Didelot 					       SPEED_UNFORCED, DUPLEX_UNFORCED,
287154186b91SAndrew Lunn 					       PAUSE_ON,
2872d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
28730e7b9925SAndrew Lunn 	if (err)
28740e7b9925SAndrew Lunn 		return err;
2875fad09c73SVivien Didelot 
2876fad09c73SVivien Didelot 	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
2877fad09c73SVivien Didelot 	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
2878fad09c73SVivien Didelot 	 * tunneling, determine priority by looking at 802.1p and IP
2879fad09c73SVivien Didelot 	 * priority fields (IP prio has precedence), and set STP state
2880fad09c73SVivien Didelot 	 * to Forwarding.
2881fad09c73SVivien Didelot 	 *
2882fad09c73SVivien Didelot 	 * If this is the CPU link, use DSA or EDSA tagging depending
2883fad09c73SVivien Didelot 	 * on which tagging mode was configured.
2884fad09c73SVivien Didelot 	 *
2885fad09c73SVivien Didelot 	 * If this is a link to another switch, use DSA tagging mode.
2886fad09c73SVivien Didelot 	 *
2887fad09c73SVivien Didelot 	 * If this is the upstream port for this switch, enable
2888fad09c73SVivien Didelot 	 * forwarding of unknown unicasts and multicasts.
2889fad09c73SVivien Didelot 	 */
2890a89b433bSVivien Didelot 	reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP |
2891a89b433bSVivien Didelot 		MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
2892a89b433bSVivien Didelot 		MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
2893a89b433bSVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
28940e7b9925SAndrew Lunn 	if (err)
28950e7b9925SAndrew Lunn 		return err;
289656995cbcSAndrew Lunn 
2897601aeed3SVivien Didelot 	err = mv88e6xxx_setup_port_mode(chip, port);
289856995cbcSAndrew Lunn 	if (err)
289956995cbcSAndrew Lunn 		return err;
2900fad09c73SVivien Didelot 
2901601aeed3SVivien Didelot 	err = mv88e6xxx_setup_egress_floods(chip, port);
29024314557cSVivien Didelot 	if (err)
29034314557cSVivien Didelot 		return err;
29044314557cSVivien Didelot 
2905b92ce2f5SAndrew Lunn 	/* Port Control 2: don't force a good FCS, set the MTU size to
2906b92ce2f5SAndrew Lunn 	 * 10222 bytes, disable 802.1q tags checking, don't discard tagged or
2907fad09c73SVivien Didelot 	 * untagged frames on this port, do a destination address lookup on all
2908fad09c73SVivien Didelot 	 * received packets as usual, disable ARP mirroring and don't send a
2909fad09c73SVivien Didelot 	 * copy of all transmitted/received frames on this port to the CPU.
2910fad09c73SVivien Didelot 	 */
2911a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_map_da(chip, port);
2912a23b2961SAndrew Lunn 	if (err)
2913a23b2961SAndrew Lunn 		return err;
2914a23b2961SAndrew Lunn 
2915fa371c80SVivien Didelot 	err = mv88e6xxx_setup_upstream_port(chip, port);
29160e7b9925SAndrew Lunn 	if (err)
29170e7b9925SAndrew Lunn 		return err;
2918fad09c73SVivien Didelot 
2919a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_8021q_mode(chip, port,
292081c6edb2SVivien Didelot 				MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED);
2921a23b2961SAndrew Lunn 	if (err)
2922a23b2961SAndrew Lunn 		return err;
2923a23b2961SAndrew Lunn 
29245bded825SVladimir Oltean 	/* Associate MV88E6XXX_VID_BRIDGED with MV88E6XXX_FID_BRIDGED in the
29255bded825SVladimir Oltean 	 * ATU by virtue of the fact that mv88e6xxx_atu_new() will pick it as
29265bded825SVladimir Oltean 	 * the first free FID after MV88E6XXX_FID_STANDALONE. This will be used
29275bded825SVladimir Oltean 	 * as the private PVID on ports under a VLAN-unaware bridge.
29285bded825SVladimir Oltean 	 * Shared (DSA and CPU) ports must also be members of it, to translate
29295bded825SVladimir Oltean 	 * the VID from the DSA tag into MV88E6XXX_FID_BRIDGED, instead of
29305bded825SVladimir Oltean 	 * relying on their port default FID.
29315bded825SVladimir Oltean 	 */
29325bded825SVladimir Oltean 	err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_BRIDGED,
29335bded825SVladimir Oltean 				       MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED,
29345bded825SVladimir Oltean 				       false);
29355bded825SVladimir Oltean 	if (err)
29365bded825SVladimir Oltean 		return err;
29375bded825SVladimir Oltean 
2938cd782656SVivien Didelot 	if (chip->info->ops->port_set_jumbo_size) {
2939b92ce2f5SAndrew Lunn 		err = chip->info->ops->port_set_jumbo_size(chip, port, 10218);
29405f436666SAndrew Lunn 		if (err)
29415f436666SAndrew Lunn 			return err;
29425f436666SAndrew Lunn 	}
29435f436666SAndrew Lunn 
2944041bd545STobias Waldekranz 	/* Port Association Vector: disable automatic address learning
2945041bd545STobias Waldekranz 	 * on all user ports since they start out in standalone
2946041bd545STobias Waldekranz 	 * mode. When joining a bridge, learning will be configured to
2947041bd545STobias Waldekranz 	 * match the bridge port settings. Enable learning on all
2948041bd545STobias Waldekranz 	 * DSA/CPU ports. NOTE: FROM_CPU frames always bypass the
2949041bd545STobias Waldekranz 	 * learning process.
2950041bd545STobias Waldekranz 	 *
2951041bd545STobias Waldekranz 	 * Disable HoldAt1, IntOnAgeOut, LockedPort, IgnoreWrongData,
2952041bd545STobias Waldekranz 	 * and RefreshLocked. I.e. setup standard automatic learning.
2953fad09c73SVivien Didelot 	 */
2954041bd545STobias Waldekranz 	if (dsa_is_user_port(ds, port))
2955fad09c73SVivien Didelot 		reg = 0;
2956041bd545STobias Waldekranz 	else
2957041bd545STobias Waldekranz 		reg = 1 << port;
2958fad09c73SVivien Didelot 
29592a4614e4SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
29602a4614e4SVivien Didelot 				   reg);
29610e7b9925SAndrew Lunn 	if (err)
29620e7b9925SAndrew Lunn 		return err;
2963fad09c73SVivien Didelot 
2964fad09c73SVivien Didelot 	/* Egress rate control 2: disable egress rate control. */
29652cb8cb14SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2,
29662cb8cb14SVivien Didelot 				   0x0000);
29670e7b9925SAndrew Lunn 	if (err)
29680e7b9925SAndrew Lunn 		return err;
2969fad09c73SVivien Didelot 
29700898432cSVivien Didelot 	if (chip->info->ops->port_pause_limit) {
29710898432cSVivien Didelot 		err = chip->info->ops->port_pause_limit(chip, port, 0, 0);
2972b35d322aSAndrew Lunn 		if (err)
2973b35d322aSAndrew Lunn 			return err;
2974b35d322aSAndrew Lunn 	}
2975b35d322aSAndrew Lunn 
2976c8c94891SVivien Didelot 	if (chip->info->ops->port_disable_learn_limit) {
2977c8c94891SVivien Didelot 		err = chip->info->ops->port_disable_learn_limit(chip, port);
2978c8c94891SVivien Didelot 		if (err)
2979c8c94891SVivien Didelot 			return err;
2980c8c94891SVivien Didelot 	}
2981c8c94891SVivien Didelot 
29829dbfb4e1SVivien Didelot 	if (chip->info->ops->port_disable_pri_override) {
29839dbfb4e1SVivien Didelot 		err = chip->info->ops->port_disable_pri_override(chip, port);
29840e7b9925SAndrew Lunn 		if (err)
29850e7b9925SAndrew Lunn 			return err;
2986ef0a7318SAndrew Lunn 	}
29872bbb33beSAndrew Lunn 
2988ef0a7318SAndrew Lunn 	if (chip->info->ops->port_tag_remap) {
2989ef0a7318SAndrew Lunn 		err = chip->info->ops->port_tag_remap(chip, port);
29900e7b9925SAndrew Lunn 		if (err)
29910e7b9925SAndrew Lunn 			return err;
2992fad09c73SVivien Didelot 	}
2993fad09c73SVivien Didelot 
2994ef70b111SAndrew Lunn 	if (chip->info->ops->port_egress_rate_limiting) {
2995ef70b111SAndrew Lunn 		err = chip->info->ops->port_egress_rate_limiting(chip, port);
29960e7b9925SAndrew Lunn 		if (err)
29970e7b9925SAndrew Lunn 			return err;
2998fad09c73SVivien Didelot 	}
2999fad09c73SVivien Didelot 
3000121b8fe2SHubert Feurstein 	if (chip->info->ops->port_setup_message_port) {
3001121b8fe2SHubert Feurstein 		err = chip->info->ops->port_setup_message_port(chip, port);
30020e7b9925SAndrew Lunn 		if (err)
30030e7b9925SAndrew Lunn 			return err;
3004121b8fe2SHubert Feurstein 	}
3005fad09c73SVivien Didelot 
3006fad09c73SVivien Didelot 	/* Port based VLAN map: give each port the same default address
3007fad09c73SVivien Didelot 	 * database, and allow bidirectional communication between the
3008fad09c73SVivien Didelot 	 * CPU and DSA port(s), and the other ports.
3009fad09c73SVivien Didelot 	 */
30105bded825SVladimir Oltean 	err = mv88e6xxx_port_set_fid(chip, port, MV88E6XXX_FID_STANDALONE);
30110e7b9925SAndrew Lunn 	if (err)
30120e7b9925SAndrew Lunn 		return err;
3013fad09c73SVivien Didelot 
3014240ea3efSVivien Didelot 	err = mv88e6xxx_port_vlan_map(chip, port);
30150e7b9925SAndrew Lunn 	if (err)
30160e7b9925SAndrew Lunn 		return err;
3017fad09c73SVivien Didelot 
3018fad09c73SVivien Didelot 	/* Default VLAN ID and priority: don't set a default VLAN
3019fad09c73SVivien Didelot 	 * ID, and set the default packet priority to zero.
3020fad09c73SVivien Didelot 	 */
3021b7929fb3SVivien Didelot 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0);
3022fad09c73SVivien Didelot }
3023fad09c73SVivien Didelot 
30242a550aecSAndrew Lunn static int mv88e6xxx_get_max_mtu(struct dsa_switch *ds, int port)
30252a550aecSAndrew Lunn {
30262a550aecSAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
30272a550aecSAndrew Lunn 
30282a550aecSAndrew Lunn 	if (chip->info->ops->port_set_jumbo_size)
3029b9c587feSAndrew Lunn 		return 10240 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN;
30301baf0facSChris Packham 	else if (chip->info->ops->set_max_frame_size)
3031b9c587feSAndrew Lunn 		return 1632 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN;
3032b9c587feSAndrew Lunn 	return 1522 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN;
30332a550aecSAndrew Lunn }
30342a550aecSAndrew Lunn 
30352a550aecSAndrew Lunn static int mv88e6xxx_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
30362a550aecSAndrew Lunn {
30372a550aecSAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
30382a550aecSAndrew Lunn 	int ret = 0;
30392a550aecSAndrew Lunn 
3040b9c587feSAndrew Lunn 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
3041b9c587feSAndrew Lunn 		new_mtu += EDSA_HLEN;
3042b9c587feSAndrew Lunn 
30432a550aecSAndrew Lunn 	mv88e6xxx_reg_lock(chip);
30442a550aecSAndrew Lunn 	if (chip->info->ops->port_set_jumbo_size)
30452a550aecSAndrew Lunn 		ret = chip->info->ops->port_set_jumbo_size(chip, port, new_mtu);
30461baf0facSChris Packham 	else if (chip->info->ops->set_max_frame_size)
30471baf0facSChris Packham 		ret = chip->info->ops->set_max_frame_size(chip, new_mtu);
30482a550aecSAndrew Lunn 	else
30492a550aecSAndrew Lunn 		if (new_mtu > 1522)
30502a550aecSAndrew Lunn 			ret = -EINVAL;
30512a550aecSAndrew Lunn 	mv88e6xxx_reg_unlock(chip);
30522a550aecSAndrew Lunn 
30532a550aecSAndrew Lunn 	return ret;
30542a550aecSAndrew Lunn }
30552a550aecSAndrew Lunn 
305604aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
305704aca993SAndrew Lunn 				 struct phy_device *phydev)
305804aca993SAndrew Lunn {
305904aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
3060523a8904SVivien Didelot 	int err;
306104aca993SAndrew Lunn 
3062c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3063523a8904SVivien Didelot 	err = mv88e6xxx_serdes_power(chip, port, true);
3064c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
306504aca993SAndrew Lunn 
306604aca993SAndrew Lunn 	return err;
306704aca993SAndrew Lunn }
306804aca993SAndrew Lunn 
306975104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
307004aca993SAndrew Lunn {
307104aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
307204aca993SAndrew Lunn 
3073c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3074523a8904SVivien Didelot 	if (mv88e6xxx_serdes_power(chip, port, false))
3075523a8904SVivien Didelot 		dev_err(chip->dev, "failed to power off SERDES\n");
3076c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
307704aca993SAndrew Lunn }
307804aca993SAndrew Lunn 
30792cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
30802cfcd964SVivien Didelot 				     unsigned int ageing_time)
30812cfcd964SVivien Didelot {
308204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
30832cfcd964SVivien Didelot 	int err;
30842cfcd964SVivien Didelot 
3085c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3086720c6343SVivien Didelot 	err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
3087c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
30882cfcd964SVivien Didelot 
30892cfcd964SVivien Didelot 	return err;
30902cfcd964SVivien Didelot }
30912cfcd964SVivien Didelot 
3092447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
3093fad09c73SVivien Didelot {
3094fad09c73SVivien Didelot 	int err;
3095fad09c73SVivien Didelot 
3096de227387SAndrew Lunn 	/* Initialize the statistics unit */
3097447b1bb8SVivien Didelot 	if (chip->info->ops->stats_set_histogram) {
3098447b1bb8SVivien Didelot 		err = chip->info->ops->stats_set_histogram(chip);
3099de227387SAndrew Lunn 		if (err)
3100de227387SAndrew Lunn 			return err;
3101447b1bb8SVivien Didelot 	}
3102de227387SAndrew Lunn 
310340cff8fcSAndrew Lunn 	return mv88e6xxx_g1_stats_clear(chip);
31049729934cSVivien Didelot }
31059729934cSVivien Didelot 
3106ea89098eSAndrew Lunn /* Check if the errata has already been applied. */
3107ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
3108ea89098eSAndrew Lunn {
3109ea89098eSAndrew Lunn 	int port;
3110ea89098eSAndrew Lunn 	int err;
3111ea89098eSAndrew Lunn 	u16 val;
3112ea89098eSAndrew Lunn 
3113ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
311460907013SMarek Behún 		err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val);
3115ea89098eSAndrew Lunn 		if (err) {
3116ea89098eSAndrew Lunn 			dev_err(chip->dev,
3117ea89098eSAndrew Lunn 				"Error reading hidden register: %d\n", err);
3118ea89098eSAndrew Lunn 			return false;
3119ea89098eSAndrew Lunn 		}
3120ea89098eSAndrew Lunn 		if (val != 0x01c0)
3121ea89098eSAndrew Lunn 			return false;
3122ea89098eSAndrew Lunn 	}
3123ea89098eSAndrew Lunn 
3124ea89098eSAndrew Lunn 	return true;
3125ea89098eSAndrew Lunn }
3126ea89098eSAndrew Lunn 
3127ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic
3128ea89098eSAndrew Lunn  * values into undocumented hidden registers and then performing a
3129ea89098eSAndrew Lunn  * software reset.
3130ea89098eSAndrew Lunn  */
3131ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
3132ea89098eSAndrew Lunn {
3133ea89098eSAndrew Lunn 	int port;
3134ea89098eSAndrew Lunn 	int err;
3135ea89098eSAndrew Lunn 
3136ea89098eSAndrew Lunn 	if (mv88e6390_setup_errata_applied(chip))
3137ea89098eSAndrew Lunn 		return 0;
3138ea89098eSAndrew Lunn 
3139ea89098eSAndrew Lunn 	/* Set the ports into blocking mode */
3140ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
3141ea89098eSAndrew Lunn 		err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED);
3142ea89098eSAndrew Lunn 		if (err)
3143ea89098eSAndrew Lunn 			return err;
3144ea89098eSAndrew Lunn 	}
3145ea89098eSAndrew Lunn 
3146ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
314760907013SMarek Behún 		err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0);
3148ea89098eSAndrew Lunn 		if (err)
3149ea89098eSAndrew Lunn 			return err;
3150ea89098eSAndrew Lunn 	}
3151ea89098eSAndrew Lunn 
3152ea89098eSAndrew Lunn 	return mv88e6xxx_software_reset(chip);
3153ea89098eSAndrew Lunn }
3154ea89098eSAndrew Lunn 
315523e8b470SAndrew Lunn static void mv88e6xxx_teardown(struct dsa_switch *ds)
315623e8b470SAndrew Lunn {
315723e8b470SAndrew Lunn 	mv88e6xxx_teardown_devlink_params(ds);
3158e0c69ca7SAndrew Lunn 	dsa_devlink_resources_unregister(ds);
3159fd292c18SVladimir Oltean 	mv88e6xxx_teardown_devlink_regions_global(ds);
316023e8b470SAndrew Lunn }
316123e8b470SAndrew Lunn 
3162fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds)
3163fad09c73SVivien Didelot {
316404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
31652d2e1dd2SAndrew Lunn 	u8 cmode;
3166fad09c73SVivien Didelot 	int err;
3167fad09c73SVivien Didelot 	int i;
3168fad09c73SVivien Didelot 
3169fad09c73SVivien Didelot 	chip->ds = ds;
3170a3c53be5SAndrew Lunn 	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
3171fad09c73SVivien Didelot 
3172ce5df689SVladimir Oltean 	/* Since virtual bridges are mapped in the PVT, the number we support
3173ce5df689SVladimir Oltean 	 * depends on the physical switch topology. We need to let DSA figure
3174ce5df689SVladimir Oltean 	 * that out and therefore we cannot set this at dsa_register_switch()
3175ce5df689SVladimir Oltean 	 * time.
3176ce5df689SVladimir Oltean 	 */
3177ce5df689SVladimir Oltean 	if (mv88e6xxx_has_pvt(chip))
3178947c8746SVladimir Oltean 		ds->max_num_bridges = MV88E6XXX_MAX_PVT_SWITCHES -
3179ce5df689SVladimir Oltean 				      ds->dst->last_switch - 1;
3180ce5df689SVladimir Oltean 
3181c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3182fad09c73SVivien Didelot 
3183ea89098eSAndrew Lunn 	if (chip->info->ops->setup_errata) {
3184ea89098eSAndrew Lunn 		err = chip->info->ops->setup_errata(chip);
3185ea89098eSAndrew Lunn 		if (err)
3186ea89098eSAndrew Lunn 			goto unlock;
3187ea89098eSAndrew Lunn 	}
3188ea89098eSAndrew Lunn 
31892d2e1dd2SAndrew Lunn 	/* Cache the cmode of each port. */
31902d2e1dd2SAndrew Lunn 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
31912d2e1dd2SAndrew Lunn 		if (chip->info->ops->port_get_cmode) {
31922d2e1dd2SAndrew Lunn 			err = chip->info->ops->port_get_cmode(chip, i, &cmode);
31932d2e1dd2SAndrew Lunn 			if (err)
3194e29129fcSDan Carpenter 				goto unlock;
31952d2e1dd2SAndrew Lunn 
31962d2e1dd2SAndrew Lunn 			chip->ports[i].cmode = cmode;
31972d2e1dd2SAndrew Lunn 		}
31982d2e1dd2SAndrew Lunn 	}
31992d2e1dd2SAndrew Lunn 
32005bded825SVladimir Oltean 	err = mv88e6xxx_vtu_setup(chip);
32015bded825SVladimir Oltean 	if (err)
32025bded825SVladimir Oltean 		goto unlock;
32035bded825SVladimir Oltean 
32049729934cSVivien Didelot 	/* Setup Switch Port Registers */
3205370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
3206b759f528SVivien Didelot 		if (dsa_is_unused_port(ds, i))
3207b759f528SVivien Didelot 			continue;
3208b759f528SVivien Didelot 
3209c857486aSHubert Feurstein 		/* Prevent the use of an invalid port. */
3210b759f528SVivien Didelot 		if (mv88e6xxx_is_invalid_port(chip, i)) {
3211c857486aSHubert Feurstein 			dev_err(chip->dev, "port %d is invalid\n", i);
3212c857486aSHubert Feurstein 			err = -EINVAL;
3213c857486aSHubert Feurstein 			goto unlock;
3214c857486aSHubert Feurstein 		}
3215c857486aSHubert Feurstein 
32169729934cSVivien Didelot 		err = mv88e6xxx_setup_port(chip, i);
32179729934cSVivien Didelot 		if (err)
32189729934cSVivien Didelot 			goto unlock;
32199729934cSVivien Didelot 	}
32209729934cSVivien Didelot 
3221cd8da8bbSVivien Didelot 	err = mv88e6xxx_irl_setup(chip);
3222cd8da8bbSVivien Didelot 	if (err)
3223cd8da8bbSVivien Didelot 		goto unlock;
3224cd8da8bbSVivien Didelot 
322504a69a17SVivien Didelot 	err = mv88e6xxx_mac_setup(chip);
322604a69a17SVivien Didelot 	if (err)
322704a69a17SVivien Didelot 		goto unlock;
322804a69a17SVivien Didelot 
32291b17aedfSVivien Didelot 	err = mv88e6xxx_phy_setup(chip);
32301b17aedfSVivien Didelot 	if (err)
32311b17aedfSVivien Didelot 		goto unlock;
32321b17aedfSVivien Didelot 
323381228996SVivien Didelot 	err = mv88e6xxx_pvt_setup(chip);
323481228996SVivien Didelot 	if (err)
323581228996SVivien Didelot 		goto unlock;
323681228996SVivien Didelot 
3237a2ac29d2SVivien Didelot 	err = mv88e6xxx_atu_setup(chip);
3238a2ac29d2SVivien Didelot 	if (err)
3239a2ac29d2SVivien Didelot 		goto unlock;
3240a2ac29d2SVivien Didelot 
324187fa886eSAndrew Lunn 	err = mv88e6xxx_broadcast_setup(chip, 0);
324287fa886eSAndrew Lunn 	if (err)
324387fa886eSAndrew Lunn 		goto unlock;
324487fa886eSAndrew Lunn 
32459e907d73SVivien Didelot 	err = mv88e6xxx_pot_setup(chip);
32469e907d73SVivien Didelot 	if (err)
32479e907d73SVivien Didelot 		goto unlock;
32489e907d73SVivien Didelot 
32499e5baf9bSVivien Didelot 	err = mv88e6xxx_rmu_setup(chip);
32509e5baf9bSVivien Didelot 	if (err)
32519e5baf9bSVivien Didelot 		goto unlock;
32529e5baf9bSVivien Didelot 
325351c901a7SVivien Didelot 	err = mv88e6xxx_rsvd2cpu_setup(chip);
32546e55f698SAndrew Lunn 	if (err)
32556e55f698SAndrew Lunn 		goto unlock;
32566e55f698SAndrew Lunn 
3257b28f872dSVivien Didelot 	err = mv88e6xxx_trunk_setup(chip);
3258b28f872dSVivien Didelot 	if (err)
3259b28f872dSVivien Didelot 		goto unlock;
3260b28f872dSVivien Didelot 
3261c7f047b6SVivien Didelot 	err = mv88e6xxx_devmap_setup(chip);
3262c7f047b6SVivien Didelot 	if (err)
3263c7f047b6SVivien Didelot 		goto unlock;
3264c7f047b6SVivien Didelot 
326593e18d61SVivien Didelot 	err = mv88e6xxx_pri_setup(chip);
326693e18d61SVivien Didelot 	if (err)
326793e18d61SVivien Didelot 		goto unlock;
326893e18d61SVivien Didelot 
3269c6fe0ad2SBrandon Streiff 	/* Setup PTP Hardware Clock and timestamping */
32702fa8d3afSBrandon Streiff 	if (chip->info->ptp_support) {
32712fa8d3afSBrandon Streiff 		err = mv88e6xxx_ptp_setup(chip);
32722fa8d3afSBrandon Streiff 		if (err)
32732fa8d3afSBrandon Streiff 			goto unlock;
3274c6fe0ad2SBrandon Streiff 
3275c6fe0ad2SBrandon Streiff 		err = mv88e6xxx_hwtstamp_setup(chip);
3276c6fe0ad2SBrandon Streiff 		if (err)
3277c6fe0ad2SBrandon Streiff 			goto unlock;
32782fa8d3afSBrandon Streiff 	}
32792fa8d3afSBrandon Streiff 
3280447b1bb8SVivien Didelot 	err = mv88e6xxx_stats_setup(chip);
3281447b1bb8SVivien Didelot 	if (err)
3282447b1bb8SVivien Didelot 		goto unlock;
3283447b1bb8SVivien Didelot 
3284fad09c73SVivien Didelot unlock:
3285c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3286fad09c73SVivien Didelot 
3287e0c69ca7SAndrew Lunn 	if (err)
3288e0c69ca7SAndrew Lunn 		return err;
3289e0c69ca7SAndrew Lunn 
3290e0c69ca7SAndrew Lunn 	/* Have to be called without holding the register lock, since
3291e0c69ca7SAndrew Lunn 	 * they take the devlink lock, and we later take the locks in
3292e0c69ca7SAndrew Lunn 	 * the reverse order when getting/setting parameters or
3293e0c69ca7SAndrew Lunn 	 * resource occupancy.
329423e8b470SAndrew Lunn 	 */
3295e0c69ca7SAndrew Lunn 	err = mv88e6xxx_setup_devlink_resources(ds);
3296e0c69ca7SAndrew Lunn 	if (err)
3297e0c69ca7SAndrew Lunn 		return err;
3298e0c69ca7SAndrew Lunn 
3299e0c69ca7SAndrew Lunn 	err = mv88e6xxx_setup_devlink_params(ds);
3300e0c69ca7SAndrew Lunn 	if (err)
3301bfb25542SAndrew Lunn 		goto out_resources;
3302bfb25542SAndrew Lunn 
3303fd292c18SVladimir Oltean 	err = mv88e6xxx_setup_devlink_regions_global(ds);
3304bfb25542SAndrew Lunn 	if (err)
3305bfb25542SAndrew Lunn 		goto out_params;
3306bfb25542SAndrew Lunn 
3307bfb25542SAndrew Lunn 	return 0;
3308bfb25542SAndrew Lunn 
3309bfb25542SAndrew Lunn out_params:
3310bfb25542SAndrew Lunn 	mv88e6xxx_teardown_devlink_params(ds);
3311bfb25542SAndrew Lunn out_resources:
3312e0c69ca7SAndrew Lunn 	dsa_devlink_resources_unregister(ds);
3313e0c69ca7SAndrew Lunn 
3314e0c69ca7SAndrew Lunn 	return err;
3315fad09c73SVivien Didelot }
3316fad09c73SVivien Didelot 
3317fd292c18SVladimir Oltean static int mv88e6xxx_port_setup(struct dsa_switch *ds, int port)
3318fd292c18SVladimir Oltean {
3319fd292c18SVladimir Oltean 	return mv88e6xxx_setup_devlink_regions_port(ds, port);
3320fd292c18SVladimir Oltean }
3321fd292c18SVladimir Oltean 
3322fd292c18SVladimir Oltean static void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port)
3323fd292c18SVladimir Oltean {
3324fd292c18SVladimir Oltean 	mv88e6xxx_teardown_devlink_regions_port(ds, port);
3325fd292c18SVladimir Oltean }
3326fd292c18SVladimir Oltean 
33271fe976d3SPali Rohár /* prod_id for switch families which do not have a PHY model number */
33281fe976d3SPali Rohár static const u16 family_prod_id_table[] = {
33291fe976d3SPali Rohár 	[MV88E6XXX_FAMILY_6341] = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
33301fe976d3SPali Rohár 	[MV88E6XXX_FAMILY_6390] = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
3331c5d015b0SMarek Behún 	[MV88E6XXX_FAMILY_6393] = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
33321fe976d3SPali Rohár };
33331fe976d3SPali Rohár 
3334e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
3335fad09c73SVivien Didelot {
33360dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
33370dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
33381fe976d3SPali Rohár 	u16 prod_id;
3339e57e5e77SVivien Didelot 	u16 val;
3340e57e5e77SVivien Didelot 	int err;
3341fad09c73SVivien Didelot 
3342ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_read)
3343ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
3344ee26a228SAndrew Lunn 
3345c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3346ee26a228SAndrew Lunn 	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
3347c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3348e57e5e77SVivien Didelot 
3349ddc49acbSAndrew Lunn 	/* Some internal PHYs don't have a model number. */
33501fe976d3SPali Rohár 	if (reg == MII_PHYSID2 && !(val & 0x3f0) &&
33511fe976d3SPali Rohár 	    chip->info->family < ARRAY_SIZE(family_prod_id_table)) {
33521fe976d3SPali Rohár 		prod_id = family_prod_id_table[chip->info->family];
33531fe976d3SPali Rohár 		if (prod_id)
33541fe976d3SPali Rohár 			val |= prod_id >> 4;
3355da9f3301SAndrew Lunn 	}
3356da9f3301SAndrew Lunn 
3357e57e5e77SVivien Didelot 	return err ? err : val;
3358fad09c73SVivien Didelot }
3359fad09c73SVivien Didelot 
3360e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
3361fad09c73SVivien Didelot {
33620dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
33630dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
3364e57e5e77SVivien Didelot 	int err;
3365fad09c73SVivien Didelot 
3366ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_write)
3367ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
3368ee26a228SAndrew Lunn 
3369c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3370ee26a228SAndrew Lunn 	err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
3371c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3372e57e5e77SVivien Didelot 
3373e57e5e77SVivien Didelot 	return err;
3374fad09c73SVivien Didelot }
3375fad09c73SVivien Didelot 
3376fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
3377a3c53be5SAndrew Lunn 				   struct device_node *np,
3378a3c53be5SAndrew Lunn 				   bool external)
3379fad09c73SVivien Didelot {
3380fad09c73SVivien Didelot 	static int index;
33810dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
3382fad09c73SVivien Didelot 	struct mii_bus *bus;
3383fad09c73SVivien Didelot 	int err;
3384fad09c73SVivien Didelot 
33852510babcSAndrew Lunn 	if (external) {
3386c9acece0SRasmus Villemoes 		mv88e6xxx_reg_lock(chip);
33872510babcSAndrew Lunn 		err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
3388c9acece0SRasmus Villemoes 		mv88e6xxx_reg_unlock(chip);
33892510babcSAndrew Lunn 
33902510babcSAndrew Lunn 		if (err)
33912510babcSAndrew Lunn 			return err;
33922510babcSAndrew Lunn 	}
33932510babcSAndrew Lunn 
33940dd12d54SAndrew Lunn 	bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
3395fad09c73SVivien Didelot 	if (!bus)
3396fad09c73SVivien Didelot 		return -ENOMEM;
3397fad09c73SVivien Didelot 
33980dd12d54SAndrew Lunn 	mdio_bus = bus->priv;
3399a3c53be5SAndrew Lunn 	mdio_bus->bus = bus;
34000dd12d54SAndrew Lunn 	mdio_bus->chip = chip;
3401a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&mdio_bus->list);
3402a3c53be5SAndrew Lunn 	mdio_bus->external = external;
34030dd12d54SAndrew Lunn 
3404fad09c73SVivien Didelot 	if (np) {
3405fad09c73SVivien Didelot 		bus->name = np->full_name;
3406f7ce9103SRob Herring 		snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np);
3407fad09c73SVivien Didelot 	} else {
3408fad09c73SVivien Didelot 		bus->name = "mv88e6xxx SMI";
3409fad09c73SVivien Didelot 		snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
3410fad09c73SVivien Didelot 	}
3411fad09c73SVivien Didelot 
3412fad09c73SVivien Didelot 	bus->read = mv88e6xxx_mdio_read;
3413fad09c73SVivien Didelot 	bus->write = mv88e6xxx_mdio_write;
3414fad09c73SVivien Didelot 	bus->parent = chip->dev;
3415fad09c73SVivien Didelot 
34166f88284fSAndrew Lunn 	if (!external) {
34176f88284fSAndrew Lunn 		err = mv88e6xxx_g2_irq_mdio_setup(chip, bus);
34186f88284fSAndrew Lunn 		if (err)
34196f88284fSAndrew Lunn 			return err;
34206f88284fSAndrew Lunn 	}
34216f88284fSAndrew Lunn 
3422a3c53be5SAndrew Lunn 	err = of_mdiobus_register(bus, np);
3423fad09c73SVivien Didelot 	if (err) {
3424fad09c73SVivien Didelot 		dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
34256f88284fSAndrew Lunn 		mv88e6xxx_g2_irq_mdio_free(chip, bus);
3426fad09c73SVivien Didelot 		return err;
3427fad09c73SVivien Didelot 	}
3428fad09c73SVivien Didelot 
3429a3c53be5SAndrew Lunn 	if (external)
3430a3c53be5SAndrew Lunn 		list_add_tail(&mdio_bus->list, &chip->mdios);
3431a3c53be5SAndrew Lunn 	else
3432a3c53be5SAndrew Lunn 		list_add(&mdio_bus->list, &chip->mdios);
3433a3c53be5SAndrew Lunn 
3434a3c53be5SAndrew Lunn 	return 0;
3435a3c53be5SAndrew Lunn }
3436a3c53be5SAndrew Lunn 
34373126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
34383126aeecSAndrew Lunn 
34393126aeecSAndrew Lunn {
34403126aeecSAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
34413126aeecSAndrew Lunn 	struct mii_bus *bus;
34423126aeecSAndrew Lunn 
34433126aeecSAndrew Lunn 	list_for_each_entry(mdio_bus, &chip->mdios, list) {
34443126aeecSAndrew Lunn 		bus = mdio_bus->bus;
34453126aeecSAndrew Lunn 
34466f88284fSAndrew Lunn 		if (!mdio_bus->external)
34476f88284fSAndrew Lunn 			mv88e6xxx_g2_irq_mdio_free(chip, bus);
34486f88284fSAndrew Lunn 
34493126aeecSAndrew Lunn 		mdiobus_unregister(bus);
34503126aeecSAndrew Lunn 	}
34513126aeecSAndrew Lunn }
34523126aeecSAndrew Lunn 
3453a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
3454a3c53be5SAndrew Lunn 				    struct device_node *np)
3455a3c53be5SAndrew Lunn {
3456a3c53be5SAndrew Lunn 	struct device_node *child;
3457a3c53be5SAndrew Lunn 	int err;
3458a3c53be5SAndrew Lunn 
3459a3c53be5SAndrew Lunn 	/* Always register one mdio bus for the internal/default mdio
3460a3c53be5SAndrew Lunn 	 * bus. This maybe represented in the device tree, but is
3461a3c53be5SAndrew Lunn 	 * optional.
3462a3c53be5SAndrew Lunn 	 */
3463a3c53be5SAndrew Lunn 	child = of_get_child_by_name(np, "mdio");
3464a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdio_register(chip, child, false);
3465a3c53be5SAndrew Lunn 	if (err)
3466a3c53be5SAndrew Lunn 		return err;
3467a3c53be5SAndrew Lunn 
3468a3c53be5SAndrew Lunn 	/* Walk the device tree, and see if there are any other nodes
3469a3c53be5SAndrew Lunn 	 * which say they are compatible with the external mdio
3470a3c53be5SAndrew Lunn 	 * bus.
3471a3c53be5SAndrew Lunn 	 */
3472a3c53be5SAndrew Lunn 	for_each_available_child_of_node(np, child) {
3473ceb96faeSAndrew Lunn 		if (of_device_is_compatible(
3474ceb96faeSAndrew Lunn 			    child, "marvell,mv88e6xxx-mdio-external")) {
3475a3c53be5SAndrew Lunn 			err = mv88e6xxx_mdio_register(chip, child, true);
34763126aeecSAndrew Lunn 			if (err) {
34773126aeecSAndrew Lunn 				mv88e6xxx_mdios_unregister(chip);
347878e42040SNishka Dasgupta 				of_node_put(child);
3479a3c53be5SAndrew Lunn 				return err;
3480a3c53be5SAndrew Lunn 			}
3481a3c53be5SAndrew Lunn 		}
34823126aeecSAndrew Lunn 	}
3483a3c53be5SAndrew Lunn 
3484a3c53be5SAndrew Lunn 	return 0;
3485a3c53be5SAndrew Lunn }
3486a3c53be5SAndrew Lunn 
3487855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
3488855b1932SVivien Didelot {
348904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3490855b1932SVivien Didelot 
3491855b1932SVivien Didelot 	return chip->eeprom_len;
3492855b1932SVivien Didelot }
3493855b1932SVivien Didelot 
3494855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
3495855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
3496855b1932SVivien Didelot {
349704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3498855b1932SVivien Didelot 	int err;
3499855b1932SVivien Didelot 
3500ee4dc2e7SVivien Didelot 	if (!chip->info->ops->get_eeprom)
3501ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
3502ee4dc2e7SVivien Didelot 
3503c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3504ee4dc2e7SVivien Didelot 	err = chip->info->ops->get_eeprom(chip, eeprom, data);
3505c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3506855b1932SVivien Didelot 
3507855b1932SVivien Didelot 	if (err)
3508855b1932SVivien Didelot 		return err;
3509855b1932SVivien Didelot 
3510855b1932SVivien Didelot 	eeprom->magic = 0xc3ec4951;
3511855b1932SVivien Didelot 
3512855b1932SVivien Didelot 	return 0;
3513855b1932SVivien Didelot }
3514855b1932SVivien Didelot 
3515855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
3516855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
3517855b1932SVivien Didelot {
351804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
3519855b1932SVivien Didelot 	int err;
3520855b1932SVivien Didelot 
3521ee4dc2e7SVivien Didelot 	if (!chip->info->ops->set_eeprom)
3522ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
3523ee4dc2e7SVivien Didelot 
3524855b1932SVivien Didelot 	if (eeprom->magic != 0xc3ec4951)
3525855b1932SVivien Didelot 		return -EINVAL;
3526855b1932SVivien Didelot 
3527c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
3528ee4dc2e7SVivien Didelot 	err = chip->info->ops->set_eeprom(chip, eeprom, data);
3529c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
3530855b1932SVivien Didelot 
3531855b1932SVivien Didelot 	return err;
3532855b1932SVivien Didelot }
3533855b1932SVivien Didelot 
3534b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = {
35354b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6097 */
353693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
353793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3538cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3539b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
35407e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
35417e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
354208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
35434efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
3544f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3545ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
354656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3547a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
3548a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
354956995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3550ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
35510898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3552c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
35539dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35542d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3555121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3556a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
355740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3558dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3559dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3560052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3561fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3562fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3563fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
356451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
35659e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
3566a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3567a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
356817e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
35699e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
3570f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
35710ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
35726c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
35731baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
3574b3469dd8SVivien Didelot };
3575b3469dd8SVivien Didelot 
3576b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = {
35774b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6095 */
357893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
357993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3580b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
35817e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
35827e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
358308ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
35844efe7662SChris Packham 	.port_sync_link = mv88e6185_port_sync_link,
3585f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
358656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3587a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6185_port_set_forward_unknown,
3588a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6185_port_set_default_forward,
3589a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
35902d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3591121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3592a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
359340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3594dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3595dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3596052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
359751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3598f5be107cSChris Packham 	.serdes_power = mv88e6185_serdes_power,
3599f5be107cSChris Packham 	.serdes_get_lane = mv88e6185_serdes_get_lane,
3600f5be107cSChris Packham 	.serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
3601a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3602a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
360317e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3604f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
36050ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
36066c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
36071baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
3608b3469dd8SVivien Didelot };
3609b3469dd8SVivien Didelot 
36107d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = {
361115da3cc8SStefan Eichenberger 	/* MV88E6XXX_FAMILY_6097 */
361293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
361393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3614cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
36157d381a02SStefan Eichenberger 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
36167d381a02SStefan Eichenberger 	.phy_read = mv88e6xxx_g2_smi_phy_read,
36177d381a02SStefan Eichenberger 	.phy_write = mv88e6xxx_g2_smi_phy_write,
36187d381a02SStefan Eichenberger 	.port_set_link = mv88e6xxx_port_set_link,
36194efe7662SChris Packham 	.port_sync_link = mv88e6185_port_sync_link,
3620f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3621ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
362256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3623a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
3624a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
362556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3626ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
36270898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3628c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36299dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36302d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3631121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
36327d381a02SStefan Eichenberger 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
363340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
36347d381a02SStefan Eichenberger 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
36357d381a02SStefan Eichenberger 	.stats_get_strings = mv88e6095_stats_get_strings,
36367d381a02SStefan Eichenberger 	.stats_get_stats = mv88e6095_stats_get_stats,
3637fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3638fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
363991eaa475SVolodymyr Bendiuga 	.watchdog_ops = &mv88e6097_watchdog_ops,
364051c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
3641f5be107cSChris Packham 	.serdes_power = mv88e6185_serdes_power,
3642f5be107cSChris Packham 	.serdes_get_lane = mv88e6185_serdes_get_lane,
3643f5be107cSChris Packham 	.serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
36445c19bc8bSChris Packham 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
36455c19bc8bSChris Packham 	.serdes_irq_enable = mv88e6097_serdes_irq_enable,
36465c19bc8bSChris Packham 	.serdes_irq_status = mv88e6097_serdes_irq_status,
36479e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
364817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
36499e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
3650f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
36510ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
36526c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
36531baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
36547d381a02SStefan Eichenberger };
36557d381a02SStefan Eichenberger 
3656b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = {
36574b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
365893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
365993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3660cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3661b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3662ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3663ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
366408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
36654efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
3666f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
366756995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3668a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
3669a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
3670c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36719dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36722d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3673121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
36740ac64c39SAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
367540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3676dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3677dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3678052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3679fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3680fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3681fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
368251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
36839e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
368417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
368523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
368623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3687f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
36880ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
36896c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
36901baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
3691b3469dd8SVivien Didelot };
3692b3469dd8SVivien Didelot 
3693b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = {
36944b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
369593e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
369693e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3697b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
36987e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
36997e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
370008ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
37014efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
3702f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3703ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
370456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3705a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6185_port_set_forward_unknown,
3706a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6185_port_set_default_forward,
370756995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3708a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
3709cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3710ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37110898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
371254186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
37132d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3714121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3715a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
371640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3717dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3718dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3719052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3720fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3721fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3722fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
372351c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3724a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
372502317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3726a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
372717e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3728f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
37290ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
37306c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3731b3469dd8SVivien Didelot };
3732b3469dd8SVivien Didelot 
3733990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = {
3734990e27b0SVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
373593e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
373693e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3737cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3738990e27b0SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
3739990e27b0SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3740990e27b0SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3741990e27b0SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3742990e27b0SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
3743990e27b0SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
37444efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
3745990e27b0SVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3746f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
37477cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
3748990e27b0SVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
37497da467d8SMarek Behún 	.port_set_policy = mv88e6352_port_set_policy,
3750990e27b0SVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3751a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
3752a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
3753990e27b0SVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3754cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3755990e27b0SVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37560898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3757990e27b0SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3758990e27b0SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37592d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
37607a3007d2SMarek Behún 	.port_set_cmode = mv88e6341_port_set_cmode,
3761121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3762990e27b0SVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
376311527f3cSMarek Behún 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3764990e27b0SVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3765990e27b0SVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
3766990e27b0SVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
3767fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3768fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
3769990e27b0SVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
3770990e27b0SVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
37719e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
3772990e27b0SVivien Didelot 	.reset = mv88e6352_g1_reset,
377337094887SMarek Behún 	.rmu_disable = mv88e6390_g1_rmu_disable,
3774c07fff34SMarek Behún 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
3775c07fff34SMarek Behún 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3776f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37770ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3778d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
3779d3cf7d8fSMarek Behún 	.serdes_get_lane = mv88e6341_serdes_get_lane,
3780a5a6858bSRussell King 	/* Check status register pause & lpa register */
3781a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
3782a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
3783a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
3784a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
37854241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
378661a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3787907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
3788a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
3789a03b98d6SMarek Behún 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
3790a03b98d6SMarek Behún 	.serdes_get_strings = mv88e6390_serdes_get_strings,
3791a03b98d6SMarek Behún 	.serdes_get_stats = mv88e6390_serdes_get_stats,
3792953b0dcbSMarek Behún 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
3793953b0dcbSMarek Behún 	.serdes_get_regs = mv88e6390_serdes_get_regs,
3794e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
3795990e27b0SVivien Didelot };
3796990e27b0SVivien Didelot 
3797b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = {
37984b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
379993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
380093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3801cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3802b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3803ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3804ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
380508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
38064efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
3807f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3808ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
380956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3810a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
3811a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
381256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3813ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
38140898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3815c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38169dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38172d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3818121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3819a6da21bbSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
382040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3821dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3822dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3823052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3824fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3825fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3826fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
382751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
38289e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
382917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
383023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
383123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3832f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
38330ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3834a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3835dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
38366c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3837fe230361SAndrew Lunn 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
3838b3469dd8SVivien Didelot };
3839b3469dd8SVivien Didelot 
3840b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = {
38414b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
384293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
384393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3844cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3845b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3846efb3e74dSAndrew Lunn 	.phy_read = mv88e6165_phy_read,
3847efb3e74dSAndrew Lunn 	.phy_write = mv88e6165_phy_write,
384808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
38494efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
3850f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3851c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38529dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38532d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3854121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3855a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
385640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3857dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3858dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3859052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3860fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3861fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3862fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
386351c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
38649e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
386517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
386623e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
386723e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3868f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
38690ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3870a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3871dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
38726c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3873b3469dd8SVivien Didelot };
3874b3469dd8SVivien Didelot 
3875b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = {
38764b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
387793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
387893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3879cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3880b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3881b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3882b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
388308ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
38844efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
388594d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3886f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3887ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
388856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3889a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
3890a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
389156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3892cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3893ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
38940898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3895c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38969dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38972d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3898121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3899a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
390040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3901dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3902dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3903052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3904fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3905fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3906fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
390751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
39089e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
390917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
391023e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
391123e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3912f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
39130ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
39146c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3915b3469dd8SVivien Didelot };
3916b3469dd8SVivien Didelot 
3917b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = {
39184b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
391993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
392093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3921cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3922ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3923ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3924b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3925b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3926b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
392708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
39284efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
3929a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3930f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
3931ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
3932f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
393356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3934a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
3935a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
393656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3937cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3938ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
39390898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3940c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
39419dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
39422d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3943121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3944a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
394540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3946dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3947dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3948052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3949fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3950fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3951fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
395251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
39539e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
395417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
39559e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
395623e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
395723e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3958f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
39590ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
39609db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
3961a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
3962a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
3963a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
3964a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
39656d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
3966d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
3967d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
3968a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
39696c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3970b3469dd8SVivien Didelot };
3971b3469dd8SVivien Didelot 
3972b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = {
39734b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
397493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
397593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3976cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3977b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3978b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3979b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
398008ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
39814efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
398294d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3983f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3984ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
398556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3986a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
3987a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
398856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3989cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3990ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
39910898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3992c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
39939dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
39942d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3995121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
3996a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
399740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3998dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3999dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4000052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4001fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4002fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4003fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
400451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
40059e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
400617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
400723e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
400823e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4009f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
40100ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
40116c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4012b3469dd8SVivien Didelot };
4013b3469dd8SVivien Didelot 
4014b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = {
40154b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
401693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
401793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4018cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4019ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4020ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4021b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4022b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4023b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
402408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
40254efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4026a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4027f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
4028ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
4029f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
403056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4031a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4032a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
403356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4034cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4035ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
40360898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4037c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
40389dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
40392d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4040121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4041a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
404240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4043dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4044dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4045052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4046fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4047fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4048fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
404951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
40509e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
405117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
40529e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
405323e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
405423e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4055f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
40560ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
40579db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
4058a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
4059a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
4060a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
4061a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
40626d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
40634241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
406461a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4065907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
4066d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
4067d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
4068a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
40696c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
4070b3469dd8SVivien Didelot };
4071b3469dd8SVivien Didelot 
4072b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = {
40734b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
407493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
407593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4076b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
40777e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
40787e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
407908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
40804efe7662SChris Packham 	.port_sync_link = mv88e6185_port_sync_link,
4081f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
408256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
4083a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6185_port_set_forward_unknown,
4084a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6185_port_set_default_forward,
4085ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
4086a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
408754186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
40882d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
4089121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4090a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
409140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4092dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4093dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4094052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4095fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4096fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4097fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
409851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
4099f5be107cSChris Packham 	.serdes_power = mv88e6185_serdes_power,
4100f5be107cSChris Packham 	.serdes_get_lane = mv88e6185_serdes_get_lane,
4101f5be107cSChris Packham 	.serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
410202317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
4103a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
4104a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
410517e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
4106f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
41070ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
41086c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
41091baf0facSChris Packham 	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
4110b3469dd8SVivien Didelot };
4111b3469dd8SVivien Didelot 
41121a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = {
41134b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4114ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4115cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
411698fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
411798fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
41181a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
41191a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
41201a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
41211a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
41224efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
41231a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4124f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
41257cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4126ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4127f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
412856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4129a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4130a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
413156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4132e8b34c67SChris Packham 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
41330898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4134c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
41359dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
41362d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4137fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4138121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
413979523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4140de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4141dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4142dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4143e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4144fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4145fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
414661303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
41476e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
41489e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
414917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
41509e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
415123e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
415223e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4153931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4154931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
41556335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
415617deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
4157a5a6858bSRussell King 	/* Check status register pause & lpa register */
4158a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4159a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4160a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4161a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
41624241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
416361a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4164907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
41654262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
41664262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4167bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4168bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
4169a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
41706c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
41711a3b39ecSAndrew Lunn };
41721a3b39ecSAndrew Lunn 
41731a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = {
41744b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4175ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4176cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
417798fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
417898fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
41791a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
41801a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
41811a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
41821a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
41834efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
41841a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4185f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
41867cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
4187ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4188f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
418956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4190a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4191a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
419256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4193e8b34c67SChris Packham 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
41940898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4195c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
41969dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
41972d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4198fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
4199121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
420079523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4201de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4202dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4203dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4204e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4205fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4206fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
420761303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
42086e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
42099e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
421017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
42119e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
421223e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
421323e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4214931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4215931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4216d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
421717deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390x_serdes_get_lane,
4218a5a6858bSRussell King 	/* Check status register pause & lpa register */
4219a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4220a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4221a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4222a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
42234241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
422461a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4225907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
42264262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
42274262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4228bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4229bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
4230a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
42316c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
42321a3b39ecSAndrew Lunn };
42331a3b39ecSAndrew Lunn 
42341a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = {
42354b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4236ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4237cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
423898fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
423998fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
42401a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
42411a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
42421a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
42431a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
42444efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
42451a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4246f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
42477cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4248ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
424956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4250a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4251a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
425256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
42530898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4254c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
42559dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
42562d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4257fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4258121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
425979523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4260de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4261dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4262dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4263e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4264fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4265fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
426661303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
42676e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
42689e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
426917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
42709e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
427123e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
427223e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4273931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4274931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
42756335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
427617deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
4277a5a6858bSRussell King 	/* Check status register pause & lpa register */
4278a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4279a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4280a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4281a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
42824241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
428361a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4284907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
42854262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
42864262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4287bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4288bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
42896d2ac8eeSAndrew Lunn 	.avb_ops = &mv88e6390_avb_ops,
42906d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
42916c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
42921a3b39ecSAndrew Lunn };
42931a3b39ecSAndrew Lunn 
4294b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = {
42954b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
429693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
429793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4298cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4299ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4300ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4301b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4302b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4303b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
430408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
43054efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4306a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4307f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
4308ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
4309f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
431056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4311a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4312a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
431356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4314cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4315ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
43160898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4317c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
43189dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
43192d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4320121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4321a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
432240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4323dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4324dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4325052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4326fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4327fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4328fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
432951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
43309e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
433117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
43329e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
433323e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
433423e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4335f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
43360ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
43379db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
4338a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
4339a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
4340a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
4341a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
43426d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
43434241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
434461a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4345907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
4346d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
4347d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
4348a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
43490d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
43506d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
43516c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
4352b3469dd8SVivien Didelot };
4353b3469dd8SVivien Didelot 
43541f71836fSRasmus Villemoes static const struct mv88e6xxx_ops mv88e6250_ops = {
43551f71836fSRasmus Villemoes 	/* MV88E6XXX_FAMILY_6250 */
43561f71836fSRasmus Villemoes 	.ieee_pri_map = mv88e6250_g1_ieee_pri_map,
43571f71836fSRasmus Villemoes 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
43581f71836fSRasmus Villemoes 	.irl_init_all = mv88e6352_g2_irl_init_all,
43591f71836fSRasmus Villemoes 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
43601f71836fSRasmus Villemoes 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
43611f71836fSRasmus Villemoes 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
43621f71836fSRasmus Villemoes 	.phy_read = mv88e6xxx_g2_smi_phy_read,
43631f71836fSRasmus Villemoes 	.phy_write = mv88e6xxx_g2_smi_phy_write,
43641f71836fSRasmus Villemoes 	.port_set_link = mv88e6xxx_port_set_link,
43654efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
43661f71836fSRasmus Villemoes 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4367f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6250_port_set_speed_duplex,
43681f71836fSRasmus Villemoes 	.port_tag_remap = mv88e6095_port_tag_remap,
43691f71836fSRasmus Villemoes 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4370a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4371a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
43721f71836fSRasmus Villemoes 	.port_set_ether_type = mv88e6351_port_set_ether_type,
43731f71836fSRasmus Villemoes 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
43741f71836fSRasmus Villemoes 	.port_pause_limit = mv88e6097_port_pause_limit,
43751f71836fSRasmus Villemoes 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
43761f71836fSRasmus Villemoes 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
43771f71836fSRasmus Villemoes 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
43781f71836fSRasmus Villemoes 	.stats_get_sset_count = mv88e6250_stats_get_sset_count,
43791f71836fSRasmus Villemoes 	.stats_get_strings = mv88e6250_stats_get_strings,
43801f71836fSRasmus Villemoes 	.stats_get_stats = mv88e6250_stats_get_stats,
43811f71836fSRasmus Villemoes 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
43821f71836fSRasmus Villemoes 	.set_egress_port = mv88e6095_g1_set_egress_port,
43831f71836fSRasmus Villemoes 	.watchdog_ops = &mv88e6250_watchdog_ops,
43841f71836fSRasmus Villemoes 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
43851f71836fSRasmus Villemoes 	.pot_clear = mv88e6xxx_g2_pot_clear,
43861f71836fSRasmus Villemoes 	.reset = mv88e6250_g1_reset,
438767c9ed1cSRasmus Villemoes 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
4388b28f3f3cSRasmus Villemoes 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
438971509614SHubert Feurstein 	.avb_ops = &mv88e6352_avb_ops,
439071509614SHubert Feurstein 	.ptp_ops = &mv88e6250_ptp_ops,
43911f71836fSRasmus Villemoes 	.phylink_validate = mv88e6065_phylink_validate,
43921f71836fSRasmus Villemoes };
43931f71836fSRasmus Villemoes 
43941a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = {
43954b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4396ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4397cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
439898fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
439998fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
44001a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
44011a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
44021a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
44031a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
44044efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
44051a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4406f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
44077cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4408ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4409f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
441056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4411a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4412a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
441356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
44140898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4415c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
44169dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
44172d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4418fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4419121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
442079523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4421de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4422dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4423dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4424e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4425fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4426fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
442761303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
44286e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
44299e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
443017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
44319e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
443223e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
443323e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4434931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4435931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
44366335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
443717deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
4438a5a6858bSRussell King 	/* Check status register pause & lpa register */
4439a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4440a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4441a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4442a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
44434241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
444461a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4445907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
44464262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
44474262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4448bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4449bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
4450a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
44510d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
44526d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
44536c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
44541a3b39ecSAndrew Lunn };
44551a3b39ecSAndrew Lunn 
4456b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = {
44574b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6320 */
445893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
445993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4460cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4461ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4462ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4463b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4464b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4465b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
446608ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
44674efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4468f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4469ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
447056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4471a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4472a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
447356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4474cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4475ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
44760898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4477c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
44789dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
44792d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4480121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4481a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
448240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4483dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4484dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4485052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
4486fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4487fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
44889c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
448951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
44909e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
449117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
4492f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
44930ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4494a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
44950d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
44966d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
44976c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4498b3469dd8SVivien Didelot };
4499b3469dd8SVivien Didelot 
4500b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = {
4501bd807204SVivien Didelot 	/* MV88E6XXX_FAMILY_6320 */
450293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
450393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4504cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4505ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4506ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4507b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4508b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4509b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
451008ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
45114efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4512f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4513ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
451456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4515a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4516a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
451756995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4518cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4519ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
45200898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4521c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
45229dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
45232d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4524121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4525a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
452640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4527dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4528dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4529052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
4530fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4531fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
45329c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
453317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
4534f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
45350ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4536a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
45370d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
45386d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
45396c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4540b3469dd8SVivien Didelot };
4541b3469dd8SVivien Didelot 
454216e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = {
454316e329aeSVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
454493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
454593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4546cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
454716e329aeSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
454816e329aeSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
454916e329aeSVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
455016e329aeSVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
455116e329aeSVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
455216e329aeSVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
45534efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
455416e329aeSVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4555f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
45567cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
455716e329aeSVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
45587da467d8SMarek Behún 	.port_set_policy = mv88e6352_port_set_policy,
455916e329aeSVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4560a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4561a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
456216e329aeSVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4563cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
456416e329aeSVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
45650898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
456616e329aeSVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
456716e329aeSVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
45682d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
45697a3007d2SMarek Behún 	.port_set_cmode = mv88e6341_port_set_cmode,
4570121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
457116e329aeSVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
457211527f3cSMarek Behún 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
457316e329aeSVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
457416e329aeSVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
457516e329aeSVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
4576fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4577fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
457816e329aeSVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
457916e329aeSVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
45809e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
458116e329aeSVivien Didelot 	.reset = mv88e6352_g1_reset,
458237094887SMarek Behún 	.rmu_disable = mv88e6390_g1_rmu_disable,
4583c07fff34SMarek Behún 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
4584c07fff34SMarek Behún 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4585f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
45860ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4587d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
4588d3cf7d8fSMarek Behún 	.serdes_get_lane = mv88e6341_serdes_get_lane,
4589a5a6858bSRussell King 	/* Check status register pause & lpa register */
4590a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4591a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4592a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4593a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
45944241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
459561a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4596907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
4597a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
45980d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
45996d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
4600a03b98d6SMarek Behún 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
4601a03b98d6SMarek Behún 	.serdes_get_strings = mv88e6390_serdes_get_strings,
4602a03b98d6SMarek Behún 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4603953b0dcbSMarek Behún 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4604953b0dcbSMarek Behún 	.serdes_get_regs = mv88e6390_serdes_get_regs,
4605e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
460616e329aeSVivien Didelot };
460716e329aeSVivien Didelot 
4608b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = {
46094b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
461093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
461193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4612cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4613b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4614b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4615b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
461608ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
46174efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
461894d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4619f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4620ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
462156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4622a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4623a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
462456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4625cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4626ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
46270898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4628c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
46299dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
46302d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4631121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4632a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
463340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4634dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4635dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4636052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4637fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4638fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4639fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
464051c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
46419e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
464217e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
464323e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
464423e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4645f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
46460ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
46476c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4648b3469dd8SVivien Didelot };
4649b3469dd8SVivien Didelot 
4650b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = {
46514b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
465293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
465393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4654cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4655b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4656b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4657b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
465808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
46594efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
466094d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4661f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4662ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
466356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4664a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4665a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
466656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4667cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4668ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
46690898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4670c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
46719dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
46722d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4673121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4674a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
467540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4676dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4677dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4678052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4679fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4680fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4681fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
468251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
46839e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
468417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
468523e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
468623e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4687f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
46880ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
46890d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
46906d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
46916c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
4692b3469dd8SVivien Didelot };
4693b3469dd8SVivien Didelot 
4694b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = {
46954b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
469693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
469793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4698cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
4699ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
4700ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4701b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4702b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4703b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
470408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
47054efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
4706a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4707f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
4708ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
4709f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
471056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4711a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4712a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
471356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4714cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4715ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
47160898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
4717c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
47189dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
47192d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4720121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4721a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
472240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4723dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
4724dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
4725052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
4726fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
4727fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
4728fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
472951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
47309e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
473117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
47329e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
473323e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
473423e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4735f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
47360ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
47379db4a725SVivien Didelot 	.serdes_get_lane = mv88e6352_serdes_get_lane,
4738a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
4739a5a6858bSRussell King 	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
4740a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
4741a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
47426d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
47434241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
474461a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4745907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6352_serdes_irq_status,
4746a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
47470d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
47486d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
4749cda9f4aaSAndrew Lunn 	.serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
4750cda9f4aaSAndrew Lunn 	.serdes_get_strings = mv88e6352_serdes_get_strings,
4751cda9f4aaSAndrew Lunn 	.serdes_get_stats = mv88e6352_serdes_get_stats,
4752d3f88a24SAndrew Lunn 	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
4753d3f88a24SAndrew Lunn 	.serdes_get_regs = mv88e6352_serdes_get_regs,
47546c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
4755b3469dd8SVivien Didelot };
4756b3469dd8SVivien Didelot 
47571a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = {
47584b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4759ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4760cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
476198fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
476298fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
47631a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
47641a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
47651a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
47661a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
47674efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
47681a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4769f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
47707cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4771ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4772f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
477356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4774a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4775a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
477656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4777cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4778ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
47790898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4780c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
47819dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
47822d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4783fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
4784121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
478579523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4786de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4787dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4788dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4789e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4790fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4791fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
479261303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
47936e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
47949e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
479517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
47969e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
479723e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
479823e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4799931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4800931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
48016335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
480217deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390_serdes_get_lane,
4803a5a6858bSRussell King 	/* Check status register pause & lpa register */
4804a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4805a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4806a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4807a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
48084241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
480961a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4810907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
4811a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
48120d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
48136d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
48140df95287SNikita Yushchenko 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
48150df95287SNikita Yushchenko 	.serdes_get_strings = mv88e6390_serdes_get_strings,
48160df95287SNikita Yushchenko 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4817bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4818bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
48196c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
48201a3b39ecSAndrew Lunn };
48211a3b39ecSAndrew Lunn 
48221a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = {
48234b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
4824ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
4825cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
482698fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
482798fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
48281a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
48291a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
48301a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
48311a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
48324efe7662SChris Packham 	.port_sync_link = mv88e6xxx_port_sync_link,
48331a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4834f365c6f7SRussell King 	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
48357cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
4836ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
4837f3a2cd32SVivien Didelot 	.port_set_policy = mv88e6352_port_set_policy,
483856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4839a8b659e7SVladimir Oltean 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4840a8b659e7SVladimir Oltean 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
484156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
4842cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4843ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
48440898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
4845c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
48469dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
48472d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
4848b3dce4daSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
4849121b8fe2SHubert Feurstein 	.port_setup_message_port = mv88e6xxx_setup_message_port,
485079523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4851de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4852dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4853dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
4854e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
4855fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
4856fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
485761303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
48586e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
48599e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
486017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
48619e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
486223e8b470SAndrew Lunn 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
486323e8b470SAndrew Lunn 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4864931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4865931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4866d3cf7d8fSMarek Behún 	.serdes_power = mv88e6390_serdes_power,
486717deaf5cSMarek Behún 	.serdes_get_lane = mv88e6390x_serdes_get_lane,
4868a5a6858bSRussell King 	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
4869a5a6858bSRussell King 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4870a5a6858bSRussell King 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4871a5a6858bSRussell King 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
48724241ef52SVivien Didelot 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
487361a46b41SVivien Didelot 	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4874907b9b9fSVivien Didelot 	.serdes_irq_status = mv88e6390_serdes_irq_status,
48754262c38dSAndrew Lunn 	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
48764262c38dSAndrew Lunn 	.serdes_get_strings = mv88e6390_serdes_get_strings,
48774262c38dSAndrew Lunn 	.serdes_get_stats = mv88e6390_serdes_get_stats,
4878bf3504ceSAndrew Lunn 	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
4879bf3504ceSAndrew Lunn 	.serdes_get_regs = mv88e6390_serdes_get_regs,
4880a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
48810d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
48826d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
48836c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
48841a3b39ecSAndrew Lunn };
48851a3b39ecSAndrew Lunn 
4886de776d0dSPavana Sharma static const struct mv88e6xxx_ops mv88e6393x_ops = {
4887de776d0dSPavana Sharma 	/* MV88E6XXX_FAMILY_6393 */
4888de776d0dSPavana Sharma 	.setup_errata = mv88e6393x_serdes_setup_errata,
4889de776d0dSPavana Sharma 	.irl_init_all = mv88e6390_g2_irl_init_all,
4890de776d0dSPavana Sharma 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
4891de776d0dSPavana Sharma 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
4892de776d0dSPavana Sharma 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4893de776d0dSPavana Sharma 	.phy_read = mv88e6xxx_g2_smi_phy_read,
4894de776d0dSPavana Sharma 	.phy_write = mv88e6xxx_g2_smi_phy_write,
4895de776d0dSPavana Sharma 	.port_set_link = mv88e6xxx_port_set_link,
4896de776d0dSPavana Sharma 	.port_sync_link = mv88e6xxx_port_sync_link,
4897de776d0dSPavana Sharma 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4898de776d0dSPavana Sharma 	.port_set_speed_duplex = mv88e6393x_port_set_speed_duplex,
4899de776d0dSPavana Sharma 	.port_max_speed_mode = mv88e6393x_port_max_speed_mode,
4900de776d0dSPavana Sharma 	.port_tag_remap = mv88e6390_port_tag_remap,
49016584b260SMarek Behún 	.port_set_policy = mv88e6393x_port_set_policy,
4902de776d0dSPavana Sharma 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4903de776d0dSPavana Sharma 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
4904de776d0dSPavana Sharma 	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4905de776d0dSPavana Sharma 	.port_set_ether_type = mv88e6393x_port_set_ether_type,
4906de776d0dSPavana Sharma 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4907de776d0dSPavana Sharma 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
4908de776d0dSPavana Sharma 	.port_pause_limit = mv88e6390_port_pause_limit,
4909de776d0dSPavana Sharma 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4910de776d0dSPavana Sharma 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4911de776d0dSPavana Sharma 	.port_get_cmode = mv88e6352_port_get_cmode,
4912de776d0dSPavana Sharma 	.port_set_cmode = mv88e6393x_port_set_cmode,
4913de776d0dSPavana Sharma 	.port_setup_message_port = mv88e6xxx_setup_message_port,
4914de776d0dSPavana Sharma 	.port_set_upstream_port = mv88e6393x_port_set_upstream_port,
4915de776d0dSPavana Sharma 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4916de776d0dSPavana Sharma 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4917de776d0dSPavana Sharma 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
4918de776d0dSPavana Sharma 	.stats_get_strings = mv88e6320_stats_get_strings,
4919de776d0dSPavana Sharma 	.stats_get_stats = mv88e6390_stats_get_stats,
4920de776d0dSPavana Sharma 	/* .set_cpu_port is missing because this family does not support a global
4921de776d0dSPavana Sharma 	 * CPU port, only per port CPU port which is set via
4922de776d0dSPavana Sharma 	 * .port_set_upstream_port method.
4923de776d0dSPavana Sharma 	 */
4924de776d0dSPavana Sharma 	.set_egress_port = mv88e6393x_set_egress_port,
4925de776d0dSPavana Sharma 	.watchdog_ops = &mv88e6390_watchdog_ops,
4926de776d0dSPavana Sharma 	.mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu,
4927de776d0dSPavana Sharma 	.pot_clear = mv88e6xxx_g2_pot_clear,
4928de776d0dSPavana Sharma 	.reset = mv88e6352_g1_reset,
4929de776d0dSPavana Sharma 	.rmu_disable = mv88e6390_g1_rmu_disable,
4930de776d0dSPavana Sharma 	.atu_get_hash = mv88e6165_g1_atu_get_hash,
4931de776d0dSPavana Sharma 	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4932de776d0dSPavana Sharma 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
4933de776d0dSPavana Sharma 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4934de776d0dSPavana Sharma 	.serdes_power = mv88e6393x_serdes_power,
4935de776d0dSPavana Sharma 	.serdes_get_lane = mv88e6393x_serdes_get_lane,
4936de776d0dSPavana Sharma 	.serdes_pcs_get_state = mv88e6393x_serdes_pcs_get_state,
4937de776d0dSPavana Sharma 	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
4938de776d0dSPavana Sharma 	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
4939de776d0dSPavana Sharma 	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
4940de776d0dSPavana Sharma 	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
4941de776d0dSPavana Sharma 	.serdes_irq_enable = mv88e6393x_serdes_irq_enable,
4942de776d0dSPavana Sharma 	.serdes_irq_status = mv88e6393x_serdes_irq_status,
4943de776d0dSPavana Sharma 	/* TODO: serdes stats */
4944de776d0dSPavana Sharma 	.gpio_ops = &mv88e6352_gpio_ops,
4945de776d0dSPavana Sharma 	.avb_ops = &mv88e6390_avb_ops,
4946de776d0dSPavana Sharma 	.ptp_ops = &mv88e6352_ptp_ops,
4947de776d0dSPavana Sharma 	.phylink_validate = mv88e6393x_phylink_validate,
4948de776d0dSPavana Sharma };
4949de776d0dSPavana Sharma 
4950fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = {
4951fad09c73SVivien Didelot 	[MV88E6085] = {
4952107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
4953fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6097,
4954fad09c73SVivien Didelot 		.name = "Marvell 88E6085",
4955fad09c73SVivien Didelot 		.num_databases = 4096,
4956d9ea5620SAndrew Lunn 		.num_macs = 8192,
4957fad09c73SVivien Didelot 		.num_ports = 10,
4958bc393155SAndrew Lunn 		.num_internal_phys = 5,
49593cf3c846SVivien Didelot 		.max_vid = 4095,
4960fad09c73SVivien Didelot 		.port_base_addr = 0x10,
49619255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4962a935c052SVivien Didelot 		.global1_addr = 0x1b,
49639069c13aSVivien Didelot 		.global2_addr = 0x1c,
4964acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4965dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4966d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4967e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4968f3645652SVivien Didelot 		.pvt = true,
4969b3e05aa1SVivien Didelot 		.multi_chip = true,
4970b3469dd8SVivien Didelot 		.ops = &mv88e6085_ops,
4971fad09c73SVivien Didelot 	},
4972fad09c73SVivien Didelot 
4973fad09c73SVivien Didelot 	[MV88E6095] = {
4974107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095,
4975fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6095,
4976fad09c73SVivien Didelot 		.name = "Marvell 88E6095/88E6095F",
4977fad09c73SVivien Didelot 		.num_databases = 256,
4978d9ea5620SAndrew Lunn 		.num_macs = 8192,
4979fad09c73SVivien Didelot 		.num_ports = 11,
4980bc393155SAndrew Lunn 		.num_internal_phys = 0,
49813cf3c846SVivien Didelot 		.max_vid = 4095,
4982fad09c73SVivien Didelot 		.port_base_addr = 0x10,
49839255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4984a935c052SVivien Didelot 		.global1_addr = 0x1b,
49859069c13aSVivien Didelot 		.global2_addr = 0x1c,
4986acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4987dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4988e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4989b3e05aa1SVivien Didelot 		.multi_chip = true,
4990b3469dd8SVivien Didelot 		.ops = &mv88e6095_ops,
4991fad09c73SVivien Didelot 	},
4992fad09c73SVivien Didelot 
49937d381a02SStefan Eichenberger 	[MV88E6097] = {
4994107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097,
49957d381a02SStefan Eichenberger 		.family = MV88E6XXX_FAMILY_6097,
49967d381a02SStefan Eichenberger 		.name = "Marvell 88E6097/88E6097F",
49977d381a02SStefan Eichenberger 		.num_databases = 4096,
4998d9ea5620SAndrew Lunn 		.num_macs = 8192,
49997d381a02SStefan Eichenberger 		.num_ports = 11,
5000bc393155SAndrew Lunn 		.num_internal_phys = 8,
50013cf3c846SVivien Didelot 		.max_vid = 4095,
50027d381a02SStefan Eichenberger 		.port_base_addr = 0x10,
50039255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
50047d381a02SStefan Eichenberger 		.global1_addr = 0x1b,
50059069c13aSVivien Didelot 		.global2_addr = 0x1c,
50067d381a02SStefan Eichenberger 		.age_time_coeff = 15000,
5007c534178bSStefan Eichenberger 		.g1_irqs = 8,
5008d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5009e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5010f3645652SVivien Didelot 		.pvt = true,
5011b3e05aa1SVivien Didelot 		.multi_chip = true,
5012670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
50137d381a02SStefan Eichenberger 		.ops = &mv88e6097_ops,
50147d381a02SStefan Eichenberger 	},
50157d381a02SStefan Eichenberger 
5016fad09c73SVivien Didelot 	[MV88E6123] = {
5017107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123,
5018fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
5019fad09c73SVivien Didelot 		.name = "Marvell 88E6123",
5020fad09c73SVivien Didelot 		.num_databases = 4096,
5021d9ea5620SAndrew Lunn 		.num_macs = 1024,
5022fad09c73SVivien Didelot 		.num_ports = 3,
5023bc393155SAndrew Lunn 		.num_internal_phys = 5,
50243cf3c846SVivien Didelot 		.max_vid = 4095,
5025fad09c73SVivien Didelot 		.port_base_addr = 0x10,
50269255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5027a935c052SVivien Didelot 		.global1_addr = 0x1b,
50289069c13aSVivien Didelot 		.global2_addr = 0x1c,
5029acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5030dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5031d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5032e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5033f3645652SVivien Didelot 		.pvt = true,
5034b3e05aa1SVivien Didelot 		.multi_chip = true,
5035670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5036b3469dd8SVivien Didelot 		.ops = &mv88e6123_ops,
5037fad09c73SVivien Didelot 	},
5038fad09c73SVivien Didelot 
5039fad09c73SVivien Didelot 	[MV88E6131] = {
5040107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131,
5041fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
5042fad09c73SVivien Didelot 		.name = "Marvell 88E6131",
5043fad09c73SVivien Didelot 		.num_databases = 256,
5044d9ea5620SAndrew Lunn 		.num_macs = 8192,
5045fad09c73SVivien Didelot 		.num_ports = 8,
5046bc393155SAndrew Lunn 		.num_internal_phys = 0,
50473cf3c846SVivien Didelot 		.max_vid = 4095,
5048fad09c73SVivien Didelot 		.port_base_addr = 0x10,
50499255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5050a935c052SVivien Didelot 		.global1_addr = 0x1b,
50519069c13aSVivien Didelot 		.global2_addr = 0x1c,
5052acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5053dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5054e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5055b3e05aa1SVivien Didelot 		.multi_chip = true,
5056b3469dd8SVivien Didelot 		.ops = &mv88e6131_ops,
5057fad09c73SVivien Didelot 	},
5058fad09c73SVivien Didelot 
5059990e27b0SVivien Didelot 	[MV88E6141] = {
5060107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141,
5061990e27b0SVivien Didelot 		.family = MV88E6XXX_FAMILY_6341,
506279a68b26SUwe Kleine-König 		.name = "Marvell 88E6141",
5063990e27b0SVivien Didelot 		.num_databases = 4096,
5064d9ea5620SAndrew Lunn 		.num_macs = 2048,
5065990e27b0SVivien Didelot 		.num_ports = 6,
5066bc393155SAndrew Lunn 		.num_internal_phys = 5,
5067a73ccd61SBrandon Streiff 		.num_gpio = 11,
50683cf3c846SVivien Didelot 		.max_vid = 4095,
5069990e27b0SVivien Didelot 		.port_base_addr = 0x10,
50709255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
5071990e27b0SVivien Didelot 		.global1_addr = 0x1b,
50729069c13aSVivien Didelot 		.global2_addr = 0x1c,
5073990e27b0SVivien Didelot 		.age_time_coeff = 3750,
5074990e27b0SVivien Didelot 		.atu_move_port_mask = 0x1f,
5075adfccf11SAndrew Lunn 		.g1_irqs = 9,
5076d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5077f3645652SVivien Didelot 		.pvt = true,
5078b3e05aa1SVivien Didelot 		.multi_chip = true,
5079670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5080990e27b0SVivien Didelot 		.ops = &mv88e6141_ops,
5081990e27b0SVivien Didelot 	},
5082990e27b0SVivien Didelot 
5083fad09c73SVivien Didelot 	[MV88E6161] = {
5084107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161,
5085fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
5086fad09c73SVivien Didelot 		.name = "Marvell 88E6161",
5087fad09c73SVivien Didelot 		.num_databases = 4096,
5088d9ea5620SAndrew Lunn 		.num_macs = 1024,
5089fad09c73SVivien Didelot 		.num_ports = 6,
5090bc393155SAndrew Lunn 		.num_internal_phys = 5,
50913cf3c846SVivien Didelot 		.max_vid = 4095,
5092fad09c73SVivien Didelot 		.port_base_addr = 0x10,
50939255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5094a935c052SVivien Didelot 		.global1_addr = 0x1b,
50959069c13aSVivien Didelot 		.global2_addr = 0x1c,
5096acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5097dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5098d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5099e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5100f3645652SVivien Didelot 		.pvt = true,
5101b3e05aa1SVivien Didelot 		.multi_chip = true,
5102670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5103dfa54348SAndrew Lunn 		.ptp_support = true,
5104b3469dd8SVivien Didelot 		.ops = &mv88e6161_ops,
5105fad09c73SVivien Didelot 	},
5106fad09c73SVivien Didelot 
5107fad09c73SVivien Didelot 	[MV88E6165] = {
5108107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165,
5109fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
5110fad09c73SVivien Didelot 		.name = "Marvell 88E6165",
5111fad09c73SVivien Didelot 		.num_databases = 4096,
5112d9ea5620SAndrew Lunn 		.num_macs = 8192,
5113fad09c73SVivien Didelot 		.num_ports = 6,
5114bc393155SAndrew Lunn 		.num_internal_phys = 0,
51153cf3c846SVivien Didelot 		.max_vid = 4095,
5116fad09c73SVivien Didelot 		.port_base_addr = 0x10,
51179255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5118a935c052SVivien Didelot 		.global1_addr = 0x1b,
51199069c13aSVivien Didelot 		.global2_addr = 0x1c,
5120acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5121dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5122d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5123e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5124f3645652SVivien Didelot 		.pvt = true,
5125b3e05aa1SVivien Didelot 		.multi_chip = true,
5126dfa54348SAndrew Lunn 		.ptp_support = true,
5127b3469dd8SVivien Didelot 		.ops = &mv88e6165_ops,
5128fad09c73SVivien Didelot 	},
5129fad09c73SVivien Didelot 
5130fad09c73SVivien Didelot 	[MV88E6171] = {
5131107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171,
5132fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5133fad09c73SVivien Didelot 		.name = "Marvell 88E6171",
5134fad09c73SVivien Didelot 		.num_databases = 4096,
5135d9ea5620SAndrew Lunn 		.num_macs = 8192,
5136fad09c73SVivien Didelot 		.num_ports = 7,
5137bc393155SAndrew Lunn 		.num_internal_phys = 5,
51383cf3c846SVivien Didelot 		.max_vid = 4095,
5139fad09c73SVivien Didelot 		.port_base_addr = 0x10,
51409255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5141a935c052SVivien Didelot 		.global1_addr = 0x1b,
51429069c13aSVivien Didelot 		.global2_addr = 0x1c,
5143acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5144dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5145d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5146e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5147f3645652SVivien Didelot 		.pvt = true,
5148b3e05aa1SVivien Didelot 		.multi_chip = true,
5149670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5150b3469dd8SVivien Didelot 		.ops = &mv88e6171_ops,
5151fad09c73SVivien Didelot 	},
5152fad09c73SVivien Didelot 
5153fad09c73SVivien Didelot 	[MV88E6172] = {
5154107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172,
5155fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
5156fad09c73SVivien Didelot 		.name = "Marvell 88E6172",
5157fad09c73SVivien Didelot 		.num_databases = 4096,
5158d9ea5620SAndrew Lunn 		.num_macs = 8192,
5159fad09c73SVivien Didelot 		.num_ports = 7,
5160bc393155SAndrew Lunn 		.num_internal_phys = 5,
5161a73ccd61SBrandon Streiff 		.num_gpio = 15,
51623cf3c846SVivien Didelot 		.max_vid = 4095,
5163fad09c73SVivien Didelot 		.port_base_addr = 0x10,
51649255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5165a935c052SVivien Didelot 		.global1_addr = 0x1b,
51669069c13aSVivien Didelot 		.global2_addr = 0x1c,
5167acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5168dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5169d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5170e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5171f3645652SVivien Didelot 		.pvt = true,
5172b3e05aa1SVivien Didelot 		.multi_chip = true,
5173670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5174b3469dd8SVivien Didelot 		.ops = &mv88e6172_ops,
5175fad09c73SVivien Didelot 	},
5176fad09c73SVivien Didelot 
5177fad09c73SVivien Didelot 	[MV88E6175] = {
5178107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175,
5179fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5180fad09c73SVivien Didelot 		.name = "Marvell 88E6175",
5181fad09c73SVivien Didelot 		.num_databases = 4096,
5182d9ea5620SAndrew Lunn 		.num_macs = 8192,
5183fad09c73SVivien Didelot 		.num_ports = 7,
5184bc393155SAndrew Lunn 		.num_internal_phys = 5,
51853cf3c846SVivien Didelot 		.max_vid = 4095,
5186fad09c73SVivien Didelot 		.port_base_addr = 0x10,
51879255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5188a935c052SVivien Didelot 		.global1_addr = 0x1b,
51899069c13aSVivien Didelot 		.global2_addr = 0x1c,
5190acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5191dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5192d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5193e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5194f3645652SVivien Didelot 		.pvt = true,
5195b3e05aa1SVivien Didelot 		.multi_chip = true,
5196670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5197b3469dd8SVivien Didelot 		.ops = &mv88e6175_ops,
5198fad09c73SVivien Didelot 	},
5199fad09c73SVivien Didelot 
5200fad09c73SVivien Didelot 	[MV88E6176] = {
5201107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176,
5202fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
5203fad09c73SVivien Didelot 		.name = "Marvell 88E6176",
5204fad09c73SVivien Didelot 		.num_databases = 4096,
5205d9ea5620SAndrew Lunn 		.num_macs = 8192,
5206fad09c73SVivien Didelot 		.num_ports = 7,
5207bc393155SAndrew Lunn 		.num_internal_phys = 5,
5208a73ccd61SBrandon Streiff 		.num_gpio = 15,
52093cf3c846SVivien Didelot 		.max_vid = 4095,
5210fad09c73SVivien Didelot 		.port_base_addr = 0x10,
52119255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5212a935c052SVivien Didelot 		.global1_addr = 0x1b,
52139069c13aSVivien Didelot 		.global2_addr = 0x1c,
5214acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5215dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5216d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5217e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5218f3645652SVivien Didelot 		.pvt = true,
5219b3e05aa1SVivien Didelot 		.multi_chip = true,
5220670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5221b3469dd8SVivien Didelot 		.ops = &mv88e6176_ops,
5222fad09c73SVivien Didelot 	},
5223fad09c73SVivien Didelot 
5224fad09c73SVivien Didelot 	[MV88E6185] = {
5225107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185,
5226fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
5227fad09c73SVivien Didelot 		.name = "Marvell 88E6185",
5228fad09c73SVivien Didelot 		.num_databases = 256,
5229d9ea5620SAndrew Lunn 		.num_macs = 8192,
5230fad09c73SVivien Didelot 		.num_ports = 10,
5231bc393155SAndrew Lunn 		.num_internal_phys = 0,
52323cf3c846SVivien Didelot 		.max_vid = 4095,
5233fad09c73SVivien Didelot 		.port_base_addr = 0x10,
52349255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5235a935c052SVivien Didelot 		.global1_addr = 0x1b,
52369069c13aSVivien Didelot 		.global2_addr = 0x1c,
5237acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5238dc30c35bSAndrew Lunn 		.g1_irqs = 8,
5239e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5240b3e05aa1SVivien Didelot 		.multi_chip = true,
5241670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5242b3469dd8SVivien Didelot 		.ops = &mv88e6185_ops,
5243fad09c73SVivien Didelot 	},
5244fad09c73SVivien Didelot 
52451a3b39ecSAndrew Lunn 	[MV88E6190] = {
5246107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190,
52471a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
52481a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190",
52491a3b39ecSAndrew Lunn 		.num_databases = 4096,
5250d9ea5620SAndrew Lunn 		.num_macs = 16384,
52511a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
525295150f29SHeiner Kallweit 		.num_internal_phys = 9,
5253a73ccd61SBrandon Streiff 		.num_gpio = 16,
5254931d1822SVivien Didelot 		.max_vid = 8191,
52551a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
52569255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
52571a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
52589069c13aSVivien Didelot 		.global2_addr = 0x1c,
5259b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
52601a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5261d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5262f3645652SVivien Didelot 		.pvt = true,
5263b3e05aa1SVivien Didelot 		.multi_chip = true,
5264e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
52651a3b39ecSAndrew Lunn 		.ops = &mv88e6190_ops,
52661a3b39ecSAndrew Lunn 	},
52671a3b39ecSAndrew Lunn 
52681a3b39ecSAndrew Lunn 	[MV88E6190X] = {
5269107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X,
52701a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
52711a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190X",
52721a3b39ecSAndrew Lunn 		.num_databases = 4096,
5273d9ea5620SAndrew Lunn 		.num_macs = 16384,
52741a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
527595150f29SHeiner Kallweit 		.num_internal_phys = 9,
5276a73ccd61SBrandon Streiff 		.num_gpio = 16,
5277931d1822SVivien Didelot 		.max_vid = 8191,
52781a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
52799255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
52801a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
52819069c13aSVivien Didelot 		.global2_addr = 0x1c,
5282b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
52831a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5284d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5285e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5286f3645652SVivien Didelot 		.pvt = true,
5287b3e05aa1SVivien Didelot 		.multi_chip = true,
52881a3b39ecSAndrew Lunn 		.ops = &mv88e6190x_ops,
52891a3b39ecSAndrew Lunn 	},
52901a3b39ecSAndrew Lunn 
52911a3b39ecSAndrew Lunn 	[MV88E6191] = {
5292107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191,
52931a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
52941a3b39ecSAndrew Lunn 		.name = "Marvell 88E6191",
52951a3b39ecSAndrew Lunn 		.num_databases = 4096,
5296d9ea5620SAndrew Lunn 		.num_macs = 16384,
52971a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
529895150f29SHeiner Kallweit 		.num_internal_phys = 9,
5299931d1822SVivien Didelot 		.max_vid = 8191,
53001a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
53019255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
53021a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
53039069c13aSVivien Didelot 		.global2_addr = 0x1c,
5304b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
5305443d5a1bSAndrew Lunn 		.g1_irqs = 9,
5306d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5307e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5308f3645652SVivien Didelot 		.pvt = true,
5309b3e05aa1SVivien Didelot 		.multi_chip = true,
53102fa8d3afSBrandon Streiff 		.ptp_support = true,
53112cf4cefbSVivien Didelot 		.ops = &mv88e6191_ops,
53121a3b39ecSAndrew Lunn 	},
53131a3b39ecSAndrew Lunn 
5314de776d0dSPavana Sharma 	[MV88E6191X] = {
5315de776d0dSPavana Sharma 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X,
5316de776d0dSPavana Sharma 		.family = MV88E6XXX_FAMILY_6393,
5317de776d0dSPavana Sharma 		.name = "Marvell 88E6191X",
5318de776d0dSPavana Sharma 		.num_databases = 4096,
5319de776d0dSPavana Sharma 		.num_ports = 11,	/* 10 + Z80 */
5320de776d0dSPavana Sharma 		.num_internal_phys = 9,
5321de776d0dSPavana Sharma 		.max_vid = 8191,
5322de776d0dSPavana Sharma 		.port_base_addr = 0x0,
5323de776d0dSPavana Sharma 		.phy_base_addr = 0x0,
5324de776d0dSPavana Sharma 		.global1_addr = 0x1b,
5325de776d0dSPavana Sharma 		.global2_addr = 0x1c,
5326de776d0dSPavana Sharma 		.age_time_coeff = 3750,
5327de776d0dSPavana Sharma 		.g1_irqs = 10,
5328de776d0dSPavana Sharma 		.g2_irqs = 14,
5329de776d0dSPavana Sharma 		.atu_move_port_mask = 0x1f,
5330de776d0dSPavana Sharma 		.pvt = true,
5331de776d0dSPavana Sharma 		.multi_chip = true,
5332de776d0dSPavana Sharma 		.ptp_support = true,
5333de776d0dSPavana Sharma 		.ops = &mv88e6393x_ops,
5334de776d0dSPavana Sharma 	},
5335de776d0dSPavana Sharma 
5336de776d0dSPavana Sharma 	[MV88E6193X] = {
5337de776d0dSPavana Sharma 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6193X,
5338de776d0dSPavana Sharma 		.family = MV88E6XXX_FAMILY_6393,
5339de776d0dSPavana Sharma 		.name = "Marvell 88E6193X",
5340de776d0dSPavana Sharma 		.num_databases = 4096,
5341de776d0dSPavana Sharma 		.num_ports = 11,	/* 10 + Z80 */
5342de776d0dSPavana Sharma 		.num_internal_phys = 9,
5343de776d0dSPavana Sharma 		.max_vid = 8191,
5344de776d0dSPavana Sharma 		.port_base_addr = 0x0,
5345de776d0dSPavana Sharma 		.phy_base_addr = 0x0,
5346de776d0dSPavana Sharma 		.global1_addr = 0x1b,
5347de776d0dSPavana Sharma 		.global2_addr = 0x1c,
5348de776d0dSPavana Sharma 		.age_time_coeff = 3750,
5349de776d0dSPavana Sharma 		.g1_irqs = 10,
5350de776d0dSPavana Sharma 		.g2_irqs = 14,
5351de776d0dSPavana Sharma 		.atu_move_port_mask = 0x1f,
5352de776d0dSPavana Sharma 		.pvt = true,
5353de776d0dSPavana Sharma 		.multi_chip = true,
5354de776d0dSPavana Sharma 		.ptp_support = true,
5355de776d0dSPavana Sharma 		.ops = &mv88e6393x_ops,
5356de776d0dSPavana Sharma 	},
5357de776d0dSPavana Sharma 
535849022647SHubert Feurstein 	[MV88E6220] = {
535949022647SHubert Feurstein 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
536049022647SHubert Feurstein 		.family = MV88E6XXX_FAMILY_6250,
536149022647SHubert Feurstein 		.name = "Marvell 88E6220",
536249022647SHubert Feurstein 		.num_databases = 64,
536349022647SHubert Feurstein 
536449022647SHubert Feurstein 		/* Ports 2-4 are not routed to pins
536549022647SHubert Feurstein 		 * => usable ports 0, 1, 5, 6
536649022647SHubert Feurstein 		 */
536749022647SHubert Feurstein 		.num_ports = 7,
536849022647SHubert Feurstein 		.num_internal_phys = 2,
5369c857486aSHubert Feurstein 		.invalid_port_mask = BIT(2) | BIT(3) | BIT(4),
537049022647SHubert Feurstein 		.max_vid = 4095,
537149022647SHubert Feurstein 		.port_base_addr = 0x08,
537249022647SHubert Feurstein 		.phy_base_addr = 0x00,
537349022647SHubert Feurstein 		.global1_addr = 0x0f,
537449022647SHubert Feurstein 		.global2_addr = 0x07,
537549022647SHubert Feurstein 		.age_time_coeff = 15000,
537649022647SHubert Feurstein 		.g1_irqs = 9,
537749022647SHubert Feurstein 		.g2_irqs = 10,
537849022647SHubert Feurstein 		.atu_move_port_mask = 0xf,
537949022647SHubert Feurstein 		.dual_chip = true,
538071509614SHubert Feurstein 		.ptp_support = true,
538149022647SHubert Feurstein 		.ops = &mv88e6250_ops,
538249022647SHubert Feurstein 	},
538349022647SHubert Feurstein 
5384fad09c73SVivien Didelot 	[MV88E6240] = {
5385107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240,
5386fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
5387fad09c73SVivien Didelot 		.name = "Marvell 88E6240",
5388fad09c73SVivien Didelot 		.num_databases = 4096,
5389d9ea5620SAndrew Lunn 		.num_macs = 8192,
5390fad09c73SVivien Didelot 		.num_ports = 7,
5391bc393155SAndrew Lunn 		.num_internal_phys = 5,
5392a73ccd61SBrandon Streiff 		.num_gpio = 15,
53933cf3c846SVivien Didelot 		.max_vid = 4095,
5394fad09c73SVivien Didelot 		.port_base_addr = 0x10,
53959255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5396a935c052SVivien Didelot 		.global1_addr = 0x1b,
53979069c13aSVivien Didelot 		.global2_addr = 0x1c,
5398acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5399dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5400d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5401e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5402f3645652SVivien Didelot 		.pvt = true,
5403b3e05aa1SVivien Didelot 		.multi_chip = true,
5404670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
54052fa8d3afSBrandon Streiff 		.ptp_support = true,
5406b3469dd8SVivien Didelot 		.ops = &mv88e6240_ops,
5407fad09c73SVivien Didelot 	},
5408fad09c73SVivien Didelot 
54091f71836fSRasmus Villemoes 	[MV88E6250] = {
54101f71836fSRasmus Villemoes 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250,
54111f71836fSRasmus Villemoes 		.family = MV88E6XXX_FAMILY_6250,
54121f71836fSRasmus Villemoes 		.name = "Marvell 88E6250",
54131f71836fSRasmus Villemoes 		.num_databases = 64,
54141f71836fSRasmus Villemoes 		.num_ports = 7,
54151f71836fSRasmus Villemoes 		.num_internal_phys = 5,
54161f71836fSRasmus Villemoes 		.max_vid = 4095,
54171f71836fSRasmus Villemoes 		.port_base_addr = 0x08,
54181f71836fSRasmus Villemoes 		.phy_base_addr = 0x00,
54191f71836fSRasmus Villemoes 		.global1_addr = 0x0f,
54201f71836fSRasmus Villemoes 		.global2_addr = 0x07,
54211f71836fSRasmus Villemoes 		.age_time_coeff = 15000,
54221f71836fSRasmus Villemoes 		.g1_irqs = 9,
54231f71836fSRasmus Villemoes 		.g2_irqs = 10,
54241f71836fSRasmus Villemoes 		.atu_move_port_mask = 0xf,
54251f71836fSRasmus Villemoes 		.dual_chip = true,
542671509614SHubert Feurstein 		.ptp_support = true,
54271f71836fSRasmus Villemoes 		.ops = &mv88e6250_ops,
54281f71836fSRasmus Villemoes 	},
54291f71836fSRasmus Villemoes 
54301a3b39ecSAndrew Lunn 	[MV88E6290] = {
5431107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
54321a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
54331a3b39ecSAndrew Lunn 		.name = "Marvell 88E6290",
54341a3b39ecSAndrew Lunn 		.num_databases = 4096,
54351a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
543695150f29SHeiner Kallweit 		.num_internal_phys = 9,
5437a73ccd61SBrandon Streiff 		.num_gpio = 16,
5438931d1822SVivien Didelot 		.max_vid = 8191,
54391a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
54409255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
54411a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
54429069c13aSVivien Didelot 		.global2_addr = 0x1c,
5443b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
54441a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5445d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5446e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5447f3645652SVivien Didelot 		.pvt = true,
5448b3e05aa1SVivien Didelot 		.multi_chip = true,
54492fa8d3afSBrandon Streiff 		.ptp_support = true,
54501a3b39ecSAndrew Lunn 		.ops = &mv88e6290_ops,
54511a3b39ecSAndrew Lunn 	},
54521a3b39ecSAndrew Lunn 
5453fad09c73SVivien Didelot 	[MV88E6320] = {
5454107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320,
5455fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
5456fad09c73SVivien Didelot 		.name = "Marvell 88E6320",
5457fad09c73SVivien Didelot 		.num_databases = 4096,
5458d9ea5620SAndrew Lunn 		.num_macs = 8192,
5459fad09c73SVivien Didelot 		.num_ports = 7,
5460bc393155SAndrew Lunn 		.num_internal_phys = 5,
5461a73ccd61SBrandon Streiff 		.num_gpio = 15,
54623cf3c846SVivien Didelot 		.max_vid = 4095,
5463fad09c73SVivien Didelot 		.port_base_addr = 0x10,
54649255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5465a935c052SVivien Didelot 		.global1_addr = 0x1b,
54669069c13aSVivien Didelot 		.global2_addr = 0x1c,
5467acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5468dc30c35bSAndrew Lunn 		.g1_irqs = 8,
5469bc393155SAndrew Lunn 		.g2_irqs = 10,
5470e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5471f3645652SVivien Didelot 		.pvt = true,
5472b3e05aa1SVivien Didelot 		.multi_chip = true,
5473670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
54742fa8d3afSBrandon Streiff 		.ptp_support = true,
5475b3469dd8SVivien Didelot 		.ops = &mv88e6320_ops,
5476fad09c73SVivien Didelot 	},
5477fad09c73SVivien Didelot 
5478fad09c73SVivien Didelot 	[MV88E6321] = {
5479107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321,
5480fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
5481fad09c73SVivien Didelot 		.name = "Marvell 88E6321",
5482fad09c73SVivien Didelot 		.num_databases = 4096,
5483d9ea5620SAndrew Lunn 		.num_macs = 8192,
5484fad09c73SVivien Didelot 		.num_ports = 7,
5485bc393155SAndrew Lunn 		.num_internal_phys = 5,
5486a73ccd61SBrandon Streiff 		.num_gpio = 15,
54873cf3c846SVivien Didelot 		.max_vid = 4095,
5488fad09c73SVivien Didelot 		.port_base_addr = 0x10,
54899255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5490a935c052SVivien Didelot 		.global1_addr = 0x1b,
54919069c13aSVivien Didelot 		.global2_addr = 0x1c,
5492acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5493dc30c35bSAndrew Lunn 		.g1_irqs = 8,
5494bc393155SAndrew Lunn 		.g2_irqs = 10,
5495e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5496b3e05aa1SVivien Didelot 		.multi_chip = true,
5497670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
54982fa8d3afSBrandon Streiff 		.ptp_support = true,
5499b3469dd8SVivien Didelot 		.ops = &mv88e6321_ops,
5500fad09c73SVivien Didelot 	},
5501fad09c73SVivien Didelot 
5502a75961d0SGregory CLEMENT 	[MV88E6341] = {
5503107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
5504a75961d0SGregory CLEMENT 		.family = MV88E6XXX_FAMILY_6341,
5505a75961d0SGregory CLEMENT 		.name = "Marvell 88E6341",
5506a75961d0SGregory CLEMENT 		.num_databases = 4096,
5507d9ea5620SAndrew Lunn 		.num_macs = 2048,
5508bc393155SAndrew Lunn 		.num_internal_phys = 5,
5509a75961d0SGregory CLEMENT 		.num_ports = 6,
5510a73ccd61SBrandon Streiff 		.num_gpio = 11,
55113cf3c846SVivien Didelot 		.max_vid = 4095,
5512a75961d0SGregory CLEMENT 		.port_base_addr = 0x10,
55139255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
5514a75961d0SGregory CLEMENT 		.global1_addr = 0x1b,
55159069c13aSVivien Didelot 		.global2_addr = 0x1c,
5516a75961d0SGregory CLEMENT 		.age_time_coeff = 3750,
5517e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5518adfccf11SAndrew Lunn 		.g1_irqs = 9,
5519d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5520f3645652SVivien Didelot 		.pvt = true,
5521b3e05aa1SVivien Didelot 		.multi_chip = true,
5522670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
55232fa8d3afSBrandon Streiff 		.ptp_support = true,
5524a75961d0SGregory CLEMENT 		.ops = &mv88e6341_ops,
5525a75961d0SGregory CLEMENT 	},
5526a75961d0SGregory CLEMENT 
5527fad09c73SVivien Didelot 	[MV88E6350] = {
5528107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350,
5529fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5530fad09c73SVivien Didelot 		.name = "Marvell 88E6350",
5531fad09c73SVivien Didelot 		.num_databases = 4096,
5532d9ea5620SAndrew Lunn 		.num_macs = 8192,
5533fad09c73SVivien Didelot 		.num_ports = 7,
5534bc393155SAndrew Lunn 		.num_internal_phys = 5,
55353cf3c846SVivien Didelot 		.max_vid = 4095,
5536fad09c73SVivien Didelot 		.port_base_addr = 0x10,
55379255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5538a935c052SVivien Didelot 		.global1_addr = 0x1b,
55399069c13aSVivien Didelot 		.global2_addr = 0x1c,
5540acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5541dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5542d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5543e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5544f3645652SVivien Didelot 		.pvt = true,
5545b3e05aa1SVivien Didelot 		.multi_chip = true,
5546670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5547b3469dd8SVivien Didelot 		.ops = &mv88e6350_ops,
5548fad09c73SVivien Didelot 	},
5549fad09c73SVivien Didelot 
5550fad09c73SVivien Didelot 	[MV88E6351] = {
5551107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351,
5552fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
5553fad09c73SVivien Didelot 		.name = "Marvell 88E6351",
5554fad09c73SVivien Didelot 		.num_databases = 4096,
5555d9ea5620SAndrew Lunn 		.num_macs = 8192,
5556fad09c73SVivien Didelot 		.num_ports = 7,
5557bc393155SAndrew Lunn 		.num_internal_phys = 5,
55583cf3c846SVivien Didelot 		.max_vid = 4095,
5559fad09c73SVivien Didelot 		.port_base_addr = 0x10,
55609255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5561a935c052SVivien Didelot 		.global1_addr = 0x1b,
55629069c13aSVivien Didelot 		.global2_addr = 0x1c,
5563acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5564dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5565d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5566e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5567f3645652SVivien Didelot 		.pvt = true,
5568b3e05aa1SVivien Didelot 		.multi_chip = true,
5569670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5570b3469dd8SVivien Didelot 		.ops = &mv88e6351_ops,
5571fad09c73SVivien Didelot 	},
5572fad09c73SVivien Didelot 
5573fad09c73SVivien Didelot 	[MV88E6352] = {
5574107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352,
5575fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
5576fad09c73SVivien Didelot 		.name = "Marvell 88E6352",
5577fad09c73SVivien Didelot 		.num_databases = 4096,
5578d9ea5620SAndrew Lunn 		.num_macs = 8192,
5579fad09c73SVivien Didelot 		.num_ports = 7,
5580bc393155SAndrew Lunn 		.num_internal_phys = 5,
5581a73ccd61SBrandon Streiff 		.num_gpio = 15,
55823cf3c846SVivien Didelot 		.max_vid = 4095,
5583fad09c73SVivien Didelot 		.port_base_addr = 0x10,
55849255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
5585a935c052SVivien Didelot 		.global1_addr = 0x1b,
55869069c13aSVivien Didelot 		.global2_addr = 0x1c,
5587acddbd21SVivien Didelot 		.age_time_coeff = 15000,
5588dc30c35bSAndrew Lunn 		.g1_irqs = 9,
5589d6c5e6afSVivien Didelot 		.g2_irqs = 10,
5590e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
5591f3645652SVivien Didelot 		.pvt = true,
5592b3e05aa1SVivien Didelot 		.multi_chip = true,
5593670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
55942fa8d3afSBrandon Streiff 		.ptp_support = true,
5595b3469dd8SVivien Didelot 		.ops = &mv88e6352_ops,
5596fad09c73SVivien Didelot 	},
55971a3b39ecSAndrew Lunn 	[MV88E6390] = {
5598107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
55991a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
56001a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390",
56011a3b39ecSAndrew Lunn 		.num_databases = 4096,
5602d9ea5620SAndrew Lunn 		.num_macs = 16384,
56031a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
560495150f29SHeiner Kallweit 		.num_internal_phys = 9,
5605a73ccd61SBrandon Streiff 		.num_gpio = 16,
5606931d1822SVivien Didelot 		.max_vid = 8191,
56071a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
56089255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
56091a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
56109069c13aSVivien Didelot 		.global2_addr = 0x1c,
5611b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
56121a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5613d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5614e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5615f3645652SVivien Didelot 		.pvt = true,
5616b3e05aa1SVivien Didelot 		.multi_chip = true,
5617670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED,
56182fa8d3afSBrandon Streiff 		.ptp_support = true,
56191a3b39ecSAndrew Lunn 		.ops = &mv88e6390_ops,
56201a3b39ecSAndrew Lunn 	},
56211a3b39ecSAndrew Lunn 	[MV88E6390X] = {
5622107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X,
56231a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
56241a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390X",
56251a3b39ecSAndrew Lunn 		.num_databases = 4096,
5626d9ea5620SAndrew Lunn 		.num_macs = 16384,
56271a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
562895150f29SHeiner Kallweit 		.num_internal_phys = 9,
5629a73ccd61SBrandon Streiff 		.num_gpio = 16,
5630931d1822SVivien Didelot 		.max_vid = 8191,
56311a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
56329255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
56331a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
56349069c13aSVivien Didelot 		.global2_addr = 0x1c,
5635b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
56361a3b39ecSAndrew Lunn 		.g1_irqs = 9,
5637d6c5e6afSVivien Didelot 		.g2_irqs = 14,
5638e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
5639f3645652SVivien Didelot 		.pvt = true,
5640b3e05aa1SVivien Didelot 		.multi_chip = true,
5641670bb80fSTobias Waldekranz 		.edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED,
56422fa8d3afSBrandon Streiff 		.ptp_support = true,
56431a3b39ecSAndrew Lunn 		.ops = &mv88e6390x_ops,
56441a3b39ecSAndrew Lunn 	},
5645de776d0dSPavana Sharma 
5646de776d0dSPavana Sharma 	[MV88E6393X] = {
5647de776d0dSPavana Sharma 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
5648de776d0dSPavana Sharma 		.family = MV88E6XXX_FAMILY_6393,
5649de776d0dSPavana Sharma 		.name = "Marvell 88E6393X",
5650de776d0dSPavana Sharma 		.num_databases = 4096,
5651de776d0dSPavana Sharma 		.num_ports = 11,	/* 10 + Z80 */
5652de776d0dSPavana Sharma 		.num_internal_phys = 9,
5653de776d0dSPavana Sharma 		.max_vid = 8191,
5654de776d0dSPavana Sharma 		.port_base_addr = 0x0,
5655de776d0dSPavana Sharma 		.phy_base_addr = 0x0,
5656de776d0dSPavana Sharma 		.global1_addr = 0x1b,
5657de776d0dSPavana Sharma 		.global2_addr = 0x1c,
5658de776d0dSPavana Sharma 		.age_time_coeff = 3750,
5659de776d0dSPavana Sharma 		.g1_irqs = 10,
5660de776d0dSPavana Sharma 		.g2_irqs = 14,
5661de776d0dSPavana Sharma 		.atu_move_port_mask = 0x1f,
5662de776d0dSPavana Sharma 		.pvt = true,
5663de776d0dSPavana Sharma 		.multi_chip = true,
5664de776d0dSPavana Sharma 		.ptp_support = true,
5665de776d0dSPavana Sharma 		.ops = &mv88e6393x_ops,
5666de776d0dSPavana Sharma 	},
5667fad09c73SVivien Didelot };
5668fad09c73SVivien Didelot 
5669fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
5670fad09c73SVivien Didelot {
5671fad09c73SVivien Didelot 	int i;
5672fad09c73SVivien Didelot 
5673fad09c73SVivien Didelot 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
5674fad09c73SVivien Didelot 		if (mv88e6xxx_table[i].prod_num == prod_num)
5675fad09c73SVivien Didelot 			return &mv88e6xxx_table[i];
5676fad09c73SVivien Didelot 
5677fad09c73SVivien Didelot 	return NULL;
5678fad09c73SVivien Didelot }
5679fad09c73SVivien Didelot 
5680fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
5681fad09c73SVivien Didelot {
5682fad09c73SVivien Didelot 	const struct mv88e6xxx_info *info;
56838f6345b2SVivien Didelot 	unsigned int prod_num, rev;
56848f6345b2SVivien Didelot 	u16 id;
56858f6345b2SVivien Didelot 	int err;
5686fad09c73SVivien Didelot 
5687c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5688107fcc10SVivien Didelot 	err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
5689c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
56908f6345b2SVivien Didelot 	if (err)
56918f6345b2SVivien Didelot 		return err;
5692fad09c73SVivien Didelot 
5693107fcc10SVivien Didelot 	prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK;
5694107fcc10SVivien Didelot 	rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK;
5695fad09c73SVivien Didelot 
5696fad09c73SVivien Didelot 	info = mv88e6xxx_lookup_info(prod_num);
5697fad09c73SVivien Didelot 	if (!info)
5698fad09c73SVivien Didelot 		return -ENODEV;
5699fad09c73SVivien Didelot 
5700fad09c73SVivien Didelot 	/* Update the compatible info with the probed one */
5701fad09c73SVivien Didelot 	chip->info = info;
5702fad09c73SVivien Didelot 
5703fad09c73SVivien Didelot 	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
5704fad09c73SVivien Didelot 		 chip->info->prod_num, chip->info->name, rev);
5705fad09c73SVivien Didelot 
5706fad09c73SVivien Didelot 	return 0;
5707fad09c73SVivien Didelot }
5708fad09c73SVivien Didelot 
5709fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
5710fad09c73SVivien Didelot {
5711fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
5712fad09c73SVivien Didelot 
5713fad09c73SVivien Didelot 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
5714fad09c73SVivien Didelot 	if (!chip)
5715fad09c73SVivien Didelot 		return NULL;
5716fad09c73SVivien Didelot 
5717fad09c73SVivien Didelot 	chip->dev = dev;
5718fad09c73SVivien Didelot 
5719fad09c73SVivien Didelot 	mutex_init(&chip->reg_lock);
5720a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&chip->mdios);
5721da7dc875SVivien Didelot 	idr_init(&chip->policies);
5722fad09c73SVivien Didelot 
5723fad09c73SVivien Didelot 	return chip;
5724fad09c73SVivien Didelot }
5725fad09c73SVivien Didelot 
57265ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
57274d776482SFlorian Fainelli 							int port,
57284d776482SFlorian Fainelli 							enum dsa_tag_protocol m)
57297b314362SAndrew Lunn {
573004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
57312bbb33beSAndrew Lunn 
5732670bb80fSTobias Waldekranz 	return chip->tag_protocol;
57337b314362SAndrew Lunn }
57347b314362SAndrew Lunn 
57359a99bef5STobias Waldekranz static int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds, int port,
57369a99bef5STobias Waldekranz 					 enum dsa_tag_protocol proto)
57379a99bef5STobias Waldekranz {
57389a99bef5STobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
57399a99bef5STobias Waldekranz 	enum dsa_tag_protocol old_protocol;
57409a99bef5STobias Waldekranz 	int err;
57419a99bef5STobias Waldekranz 
57429a99bef5STobias Waldekranz 	switch (proto) {
57439a99bef5STobias Waldekranz 	case DSA_TAG_PROTO_EDSA:
57449a99bef5STobias Waldekranz 		switch (chip->info->edsa_support) {
57459a99bef5STobias Waldekranz 		case MV88E6XXX_EDSA_UNSUPPORTED:
57469a99bef5STobias Waldekranz 			return -EPROTONOSUPPORT;
57479a99bef5STobias Waldekranz 		case MV88E6XXX_EDSA_UNDOCUMENTED:
57489a99bef5STobias Waldekranz 			dev_warn(chip->dev, "Relying on undocumented EDSA tagging behavior\n");
57499a99bef5STobias Waldekranz 			fallthrough;
57509a99bef5STobias Waldekranz 		case MV88E6XXX_EDSA_SUPPORTED:
57519a99bef5STobias Waldekranz 			break;
57529a99bef5STobias Waldekranz 		}
57539a99bef5STobias Waldekranz 		break;
57549a99bef5STobias Waldekranz 	case DSA_TAG_PROTO_DSA:
57559a99bef5STobias Waldekranz 		break;
57569a99bef5STobias Waldekranz 	default:
57579a99bef5STobias Waldekranz 		return -EPROTONOSUPPORT;
57589a99bef5STobias Waldekranz 	}
57599a99bef5STobias Waldekranz 
57609a99bef5STobias Waldekranz 	old_protocol = chip->tag_protocol;
57619a99bef5STobias Waldekranz 	chip->tag_protocol = proto;
57629a99bef5STobias Waldekranz 
57639a99bef5STobias Waldekranz 	mv88e6xxx_reg_lock(chip);
57649a99bef5STobias Waldekranz 	err = mv88e6xxx_setup_port_mode(chip, port);
57659a99bef5STobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
57669a99bef5STobias Waldekranz 
57679a99bef5STobias Waldekranz 	if (err)
57689a99bef5STobias Waldekranz 		chip->tag_protocol = old_protocol;
57699a99bef5STobias Waldekranz 
57709a99bef5STobias Waldekranz 	return err;
57719a99bef5STobias Waldekranz }
57729a99bef5STobias Waldekranz 
5773a52b2da7SVladimir Oltean static int mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
57743709aadcSVivien Didelot 				  const struct switchdev_obj_port_mdb *mdb)
57757df8fbddSVivien Didelot {
577604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
5777a52b2da7SVladimir Oltean 	int err;
57787df8fbddSVivien Didelot 
5779c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5780a52b2da7SVladimir Oltean 	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
5781a52b2da7SVladimir Oltean 					   MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC);
5782c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
5783a52b2da7SVladimir Oltean 
5784a52b2da7SVladimir Oltean 	return err;
57857df8fbddSVivien Didelot }
57867df8fbddSVivien Didelot 
57877df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
57887df8fbddSVivien Didelot 				  const struct switchdev_obj_port_mdb *mdb)
57897df8fbddSVivien Didelot {
579004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
57917df8fbddSVivien Didelot 	int err;
57927df8fbddSVivien Didelot 
5793c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5794d8291a95SVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0);
5795c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
57967df8fbddSVivien Didelot 
57977df8fbddSVivien Didelot 	return err;
57987df8fbddSVivien Didelot }
57997df8fbddSVivien Didelot 
5800f0942e00SIwan R Timmer static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
5801f0942e00SIwan R Timmer 				     struct dsa_mall_mirror_tc_entry *mirror,
5802f0942e00SIwan R Timmer 				     bool ingress)
5803f0942e00SIwan R Timmer {
5804f0942e00SIwan R Timmer 	enum mv88e6xxx_egress_direction direction = ingress ?
5805f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS :
5806f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS;
5807f0942e00SIwan R Timmer 	struct mv88e6xxx_chip *chip = ds->priv;
5808f0942e00SIwan R Timmer 	bool other_mirrors = false;
5809f0942e00SIwan R Timmer 	int i;
5810f0942e00SIwan R Timmer 	int err;
5811f0942e00SIwan R Timmer 
5812f0942e00SIwan R Timmer 	mutex_lock(&chip->reg_lock);
5813f0942e00SIwan R Timmer 	if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
5814f0942e00SIwan R Timmer 	    mirror->to_local_port) {
5815f0942e00SIwan R Timmer 		for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
5816f0942e00SIwan R Timmer 			other_mirrors |= ingress ?
5817f0942e00SIwan R Timmer 					 chip->ports[i].mirror_ingress :
5818f0942e00SIwan R Timmer 					 chip->ports[i].mirror_egress;
5819f0942e00SIwan R Timmer 
5820f0942e00SIwan R Timmer 		/* Can't change egress port when other mirror is active */
5821f0942e00SIwan R Timmer 		if (other_mirrors) {
5822f0942e00SIwan R Timmer 			err = -EBUSY;
5823f0942e00SIwan R Timmer 			goto out;
5824f0942e00SIwan R Timmer 		}
5825f0942e00SIwan R Timmer 
58262fda45f0SMarek Behún 		err = mv88e6xxx_set_egress_port(chip, direction,
5827f0942e00SIwan R Timmer 						mirror->to_local_port);
5828f0942e00SIwan R Timmer 		if (err)
5829f0942e00SIwan R Timmer 			goto out;
5830f0942e00SIwan R Timmer 	}
5831f0942e00SIwan R Timmer 
5832f0942e00SIwan R Timmer 	err = mv88e6xxx_port_set_mirror(chip, port, direction, true);
5833f0942e00SIwan R Timmer out:
5834f0942e00SIwan R Timmer 	mutex_unlock(&chip->reg_lock);
5835f0942e00SIwan R Timmer 
5836f0942e00SIwan R Timmer 	return err;
5837f0942e00SIwan R Timmer }
5838f0942e00SIwan R Timmer 
5839f0942e00SIwan R Timmer static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
5840f0942e00SIwan R Timmer 				      struct dsa_mall_mirror_tc_entry *mirror)
5841f0942e00SIwan R Timmer {
5842f0942e00SIwan R Timmer 	enum mv88e6xxx_egress_direction direction = mirror->ingress ?
5843f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_INGRESS :
5844f0942e00SIwan R Timmer 						MV88E6XXX_EGRESS_DIR_EGRESS;
5845f0942e00SIwan R Timmer 	struct mv88e6xxx_chip *chip = ds->priv;
5846f0942e00SIwan R Timmer 	bool other_mirrors = false;
5847f0942e00SIwan R Timmer 	int i;
5848f0942e00SIwan R Timmer 
5849f0942e00SIwan R Timmer 	mutex_lock(&chip->reg_lock);
5850f0942e00SIwan R Timmer 	if (mv88e6xxx_port_set_mirror(chip, port, direction, false))
5851f0942e00SIwan R Timmer 		dev_err(ds->dev, "p%d: failed to disable mirroring\n", port);
5852f0942e00SIwan R Timmer 
5853f0942e00SIwan R Timmer 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
5854f0942e00SIwan R Timmer 		other_mirrors |= mirror->ingress ?
5855f0942e00SIwan R Timmer 				 chip->ports[i].mirror_ingress :
5856f0942e00SIwan R Timmer 				 chip->ports[i].mirror_egress;
5857f0942e00SIwan R Timmer 
5858f0942e00SIwan R Timmer 	/* Reset egress port when no other mirror is active */
5859f0942e00SIwan R Timmer 	if (!other_mirrors) {
58602fda45f0SMarek Behún 		if (mv88e6xxx_set_egress_port(chip, direction,
58612fda45f0SMarek Behún 					      dsa_upstream_port(ds, port)))
5862f0942e00SIwan R Timmer 			dev_err(ds->dev, "failed to set egress port\n");
5863f0942e00SIwan R Timmer 	}
5864f0942e00SIwan R Timmer 
5865f0942e00SIwan R Timmer 	mutex_unlock(&chip->reg_lock);
5866f0942e00SIwan R Timmer }
5867f0942e00SIwan R Timmer 
5868a8b659e7SVladimir Oltean static int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port,
5869a8b659e7SVladimir Oltean 					   struct switchdev_brport_flags flags,
5870a8b659e7SVladimir Oltean 					   struct netlink_ext_ack *extack)
5871a8b659e7SVladimir Oltean {
5872a8b659e7SVladimir Oltean 	struct mv88e6xxx_chip *chip = ds->priv;
5873a8b659e7SVladimir Oltean 	const struct mv88e6xxx_ops *ops;
5874a8b659e7SVladimir Oltean 
58758d1d8298STobias Waldekranz 	if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
58768d1d8298STobias Waldekranz 			   BR_BCAST_FLOOD))
5877a8b659e7SVladimir Oltean 		return -EINVAL;
5878a8b659e7SVladimir Oltean 
5879a8b659e7SVladimir Oltean 	ops = chip->info->ops;
5880a8b659e7SVladimir Oltean 
5881a8b659e7SVladimir Oltean 	if ((flags.mask & BR_FLOOD) && !ops->port_set_ucast_flood)
5882a8b659e7SVladimir Oltean 		return -EINVAL;
5883a8b659e7SVladimir Oltean 
5884a8b659e7SVladimir Oltean 	if ((flags.mask & BR_MCAST_FLOOD) && !ops->port_set_mcast_flood)
5885a8b659e7SVladimir Oltean 		return -EINVAL;
5886a8b659e7SVladimir Oltean 
5887a8b659e7SVladimir Oltean 	return 0;
5888a8b659e7SVladimir Oltean }
5889a8b659e7SVladimir Oltean 
5890a8b659e7SVladimir Oltean static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
5891a8b659e7SVladimir Oltean 				       struct switchdev_brport_flags flags,
5892a8b659e7SVladimir Oltean 				       struct netlink_ext_ack *extack)
58934f85901fSRussell King {
58944f85901fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
58954f85901fSRussell King 	int err = -EOPNOTSUPP;
58964f85901fSRussell King 
5897c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
5898a8b659e7SVladimir Oltean 
5899041bd545STobias Waldekranz 	if (flags.mask & BR_LEARNING) {
5900041bd545STobias Waldekranz 		bool learning = !!(flags.val & BR_LEARNING);
5901041bd545STobias Waldekranz 		u16 pav = learning ? (1 << port) : 0;
5902041bd545STobias Waldekranz 
5903041bd545STobias Waldekranz 		err = mv88e6xxx_port_set_assoc_vector(chip, port, pav);
5904041bd545STobias Waldekranz 		if (err)
5905041bd545STobias Waldekranz 			goto out;
5906041bd545STobias Waldekranz 	}
5907041bd545STobias Waldekranz 
5908a8b659e7SVladimir Oltean 	if (flags.mask & BR_FLOOD) {
5909a8b659e7SVladimir Oltean 		bool unicast = !!(flags.val & BR_FLOOD);
5910a8b659e7SVladimir Oltean 
5911a8b659e7SVladimir Oltean 		err = chip->info->ops->port_set_ucast_flood(chip, port,
5912a8b659e7SVladimir Oltean 							    unicast);
5913a8b659e7SVladimir Oltean 		if (err)
5914a8b659e7SVladimir Oltean 			goto out;
5915a8b659e7SVladimir Oltean 	}
5916a8b659e7SVladimir Oltean 
5917a8b659e7SVladimir Oltean 	if (flags.mask & BR_MCAST_FLOOD) {
5918a8b659e7SVladimir Oltean 		bool multicast = !!(flags.val & BR_MCAST_FLOOD);
5919a8b659e7SVladimir Oltean 
5920a8b659e7SVladimir Oltean 		err = chip->info->ops->port_set_mcast_flood(chip, port,
59214f85901fSRussell King 							    multicast);
5922a8b659e7SVladimir Oltean 		if (err)
5923a8b659e7SVladimir Oltean 			goto out;
5924a8b659e7SVladimir Oltean 	}
5925a8b659e7SVladimir Oltean 
59268d1d8298STobias Waldekranz 	if (flags.mask & BR_BCAST_FLOOD) {
59278d1d8298STobias Waldekranz 		bool broadcast = !!(flags.val & BR_BCAST_FLOOD);
59288d1d8298STobias Waldekranz 
59298d1d8298STobias Waldekranz 		err = mv88e6xxx_port_broadcast_sync(chip, port, broadcast);
59308d1d8298STobias Waldekranz 		if (err)
59318d1d8298STobias Waldekranz 			goto out;
59328d1d8298STobias Waldekranz 	}
59338d1d8298STobias Waldekranz 
5934a8b659e7SVladimir Oltean out:
5935a8b659e7SVladimir Oltean 	mv88e6xxx_reg_unlock(chip);
5936a8b659e7SVladimir Oltean 
5937a8b659e7SVladimir Oltean 	return err;
5938a8b659e7SVladimir Oltean }
5939a8b659e7SVladimir Oltean 
594057e661aaSTobias Waldekranz static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds,
594157e661aaSTobias Waldekranz 				      struct net_device *lag,
594257e661aaSTobias Waldekranz 				      struct netdev_lag_upper_info *info)
594357e661aaSTobias Waldekranz {
5944b80dc51bSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
594557e661aaSTobias Waldekranz 	struct dsa_port *dp;
594657e661aaSTobias Waldekranz 	int id, members = 0;
594757e661aaSTobias Waldekranz 
5948b80dc51bSTobias Waldekranz 	if (!mv88e6xxx_has_lag(chip))
5949b80dc51bSTobias Waldekranz 		return false;
5950b80dc51bSTobias Waldekranz 
595157e661aaSTobias Waldekranz 	id = dsa_lag_id(ds->dst, lag);
595257e661aaSTobias Waldekranz 	if (id < 0 || id >= ds->num_lag_ids)
595357e661aaSTobias Waldekranz 		return false;
595457e661aaSTobias Waldekranz 
595557e661aaSTobias Waldekranz 	dsa_lag_foreach_port(dp, ds->dst, lag)
595657e661aaSTobias Waldekranz 		/* Includes the port joining the LAG */
595757e661aaSTobias Waldekranz 		members++;
595857e661aaSTobias Waldekranz 
595957e661aaSTobias Waldekranz 	if (members > 8)
596057e661aaSTobias Waldekranz 		return false;
596157e661aaSTobias Waldekranz 
596257e661aaSTobias Waldekranz 	/* We could potentially relax this to include active
596357e661aaSTobias Waldekranz 	 * backup in the future.
596457e661aaSTobias Waldekranz 	 */
596557e661aaSTobias Waldekranz 	if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH)
596657e661aaSTobias Waldekranz 		return false;
596757e661aaSTobias Waldekranz 
596857e661aaSTobias Waldekranz 	/* Ideally we would also validate that the hash type matches
596957e661aaSTobias Waldekranz 	 * the hardware. Alas, this is always set to unknown on team
597057e661aaSTobias Waldekranz 	 * interfaces.
597157e661aaSTobias Waldekranz 	 */
597257e661aaSTobias Waldekranz 	return true;
597357e661aaSTobias Waldekranz }
597457e661aaSTobias Waldekranz 
597557e661aaSTobias Waldekranz static int mv88e6xxx_lag_sync_map(struct dsa_switch *ds, struct net_device *lag)
597657e661aaSTobias Waldekranz {
597757e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
597857e661aaSTobias Waldekranz 	struct dsa_port *dp;
597957e661aaSTobias Waldekranz 	u16 map = 0;
598057e661aaSTobias Waldekranz 	int id;
598157e661aaSTobias Waldekranz 
598257e661aaSTobias Waldekranz 	id = dsa_lag_id(ds->dst, lag);
598357e661aaSTobias Waldekranz 
598457e661aaSTobias Waldekranz 	/* Build the map of all ports to distribute flows destined for
598557e661aaSTobias Waldekranz 	 * this LAG. This can be either a local user port, or a DSA
598657e661aaSTobias Waldekranz 	 * port if the LAG port is on a remote chip.
598757e661aaSTobias Waldekranz 	 */
598857e661aaSTobias Waldekranz 	dsa_lag_foreach_port(dp, ds->dst, lag)
598957e661aaSTobias Waldekranz 		map |= BIT(dsa_towards_port(ds, dp->ds->index, dp->index));
599057e661aaSTobias Waldekranz 
599157e661aaSTobias Waldekranz 	return mv88e6xxx_g2_trunk_mapping_write(chip, id, map);
599257e661aaSTobias Waldekranz }
599357e661aaSTobias Waldekranz 
599457e661aaSTobias Waldekranz static const u8 mv88e6xxx_lag_mask_table[8][8] = {
599557e661aaSTobias Waldekranz 	/* Row number corresponds to the number of active members in a
599657e661aaSTobias Waldekranz 	 * LAG. Each column states which of the eight hash buckets are
599757e661aaSTobias Waldekranz 	 * mapped to the column:th port in the LAG.
599857e661aaSTobias Waldekranz 	 *
599957e661aaSTobias Waldekranz 	 * Example: In a LAG with three active ports, the second port
600057e661aaSTobias Waldekranz 	 * ([2][1]) would be selected for traffic mapped to buckets
600157e661aaSTobias Waldekranz 	 * 3,4,5 (0x38).
600257e661aaSTobias Waldekranz 	 */
600357e661aaSTobias Waldekranz 	{ 0xff,    0,    0,    0,    0,    0,    0,    0 },
600457e661aaSTobias Waldekranz 	{ 0x0f, 0xf0,    0,    0,    0,    0,    0,    0 },
600557e661aaSTobias Waldekranz 	{ 0x07, 0x38, 0xc0,    0,    0,    0,    0,    0 },
600657e661aaSTobias Waldekranz 	{ 0x03, 0x0c, 0x30, 0xc0,    0,    0,    0,    0 },
600757e661aaSTobias Waldekranz 	{ 0x03, 0x0c, 0x30, 0x40, 0x80,    0,    0,    0 },
600857e661aaSTobias Waldekranz 	{ 0x03, 0x0c, 0x10, 0x20, 0x40, 0x80,    0,    0 },
600957e661aaSTobias Waldekranz 	{ 0x03, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,    0 },
601057e661aaSTobias Waldekranz 	{ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 },
601157e661aaSTobias Waldekranz };
601257e661aaSTobias Waldekranz 
601357e661aaSTobias Waldekranz static void mv88e6xxx_lag_set_port_mask(u16 *mask, int port,
601457e661aaSTobias Waldekranz 					int num_tx, int nth)
601557e661aaSTobias Waldekranz {
601657e661aaSTobias Waldekranz 	u8 active = 0;
601757e661aaSTobias Waldekranz 	int i;
601857e661aaSTobias Waldekranz 
601957e661aaSTobias Waldekranz 	num_tx = num_tx <= 8 ? num_tx : 8;
602057e661aaSTobias Waldekranz 	if (nth < num_tx)
602157e661aaSTobias Waldekranz 		active = mv88e6xxx_lag_mask_table[num_tx - 1][nth];
602257e661aaSTobias Waldekranz 
602357e661aaSTobias Waldekranz 	for (i = 0; i < 8; i++) {
602457e661aaSTobias Waldekranz 		if (BIT(i) & active)
602557e661aaSTobias Waldekranz 			mask[i] |= BIT(port);
602657e661aaSTobias Waldekranz 	}
602757e661aaSTobias Waldekranz }
602857e661aaSTobias Waldekranz 
602957e661aaSTobias Waldekranz static int mv88e6xxx_lag_sync_masks(struct dsa_switch *ds)
603057e661aaSTobias Waldekranz {
603157e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
603257e661aaSTobias Waldekranz 	unsigned int id, num_tx;
603357e661aaSTobias Waldekranz 	struct net_device *lag;
603457e661aaSTobias Waldekranz 	struct dsa_port *dp;
603557e661aaSTobias Waldekranz 	int i, err, nth;
603657e661aaSTobias Waldekranz 	u16 mask[8];
603757e661aaSTobias Waldekranz 	u16 ivec;
603857e661aaSTobias Waldekranz 
603957e661aaSTobias Waldekranz 	/* Assume no port is a member of any LAG. */
604057e661aaSTobias Waldekranz 	ivec = BIT(mv88e6xxx_num_ports(chip)) - 1;
604157e661aaSTobias Waldekranz 
604257e661aaSTobias Waldekranz 	/* Disable all masks for ports that _are_ members of a LAG. */
604357e661aaSTobias Waldekranz 	list_for_each_entry(dp, &ds->dst->ports, list) {
604457e661aaSTobias Waldekranz 		if (!dp->lag_dev || dp->ds != ds)
604557e661aaSTobias Waldekranz 			continue;
604657e661aaSTobias Waldekranz 
604757e661aaSTobias Waldekranz 		ivec &= ~BIT(dp->index);
604857e661aaSTobias Waldekranz 	}
604957e661aaSTobias Waldekranz 
605057e661aaSTobias Waldekranz 	for (i = 0; i < 8; i++)
605157e661aaSTobias Waldekranz 		mask[i] = ivec;
605257e661aaSTobias Waldekranz 
605357e661aaSTobias Waldekranz 	/* Enable the correct subset of masks for all LAG ports that
605457e661aaSTobias Waldekranz 	 * are in the Tx set.
605557e661aaSTobias Waldekranz 	 */
605657e661aaSTobias Waldekranz 	dsa_lags_foreach_id(id, ds->dst) {
605757e661aaSTobias Waldekranz 		lag = dsa_lag_dev(ds->dst, id);
605857e661aaSTobias Waldekranz 		if (!lag)
605957e661aaSTobias Waldekranz 			continue;
606057e661aaSTobias Waldekranz 
606157e661aaSTobias Waldekranz 		num_tx = 0;
606257e661aaSTobias Waldekranz 		dsa_lag_foreach_port(dp, ds->dst, lag) {
606357e661aaSTobias Waldekranz 			if (dp->lag_tx_enabled)
606457e661aaSTobias Waldekranz 				num_tx++;
606557e661aaSTobias Waldekranz 		}
606657e661aaSTobias Waldekranz 
606757e661aaSTobias Waldekranz 		if (!num_tx)
606857e661aaSTobias Waldekranz 			continue;
606957e661aaSTobias Waldekranz 
607057e661aaSTobias Waldekranz 		nth = 0;
607157e661aaSTobias Waldekranz 		dsa_lag_foreach_port(dp, ds->dst, lag) {
607257e661aaSTobias Waldekranz 			if (!dp->lag_tx_enabled)
607357e661aaSTobias Waldekranz 				continue;
607457e661aaSTobias Waldekranz 
607557e661aaSTobias Waldekranz 			if (dp->ds == ds)
607657e661aaSTobias Waldekranz 				mv88e6xxx_lag_set_port_mask(mask, dp->index,
607757e661aaSTobias Waldekranz 							    num_tx, nth);
607857e661aaSTobias Waldekranz 
607957e661aaSTobias Waldekranz 			nth++;
608057e661aaSTobias Waldekranz 		}
608157e661aaSTobias Waldekranz 	}
608257e661aaSTobias Waldekranz 
608357e661aaSTobias Waldekranz 	for (i = 0; i < 8; i++) {
608457e661aaSTobias Waldekranz 		err = mv88e6xxx_g2_trunk_mask_write(chip, i, true, mask[i]);
608557e661aaSTobias Waldekranz 		if (err)
608657e661aaSTobias Waldekranz 			return err;
608757e661aaSTobias Waldekranz 	}
608857e661aaSTobias Waldekranz 
608957e661aaSTobias Waldekranz 	return 0;
609057e661aaSTobias Waldekranz }
609157e661aaSTobias Waldekranz 
609257e661aaSTobias Waldekranz static int mv88e6xxx_lag_sync_masks_map(struct dsa_switch *ds,
609357e661aaSTobias Waldekranz 					struct net_device *lag)
609457e661aaSTobias Waldekranz {
609557e661aaSTobias Waldekranz 	int err;
609657e661aaSTobias Waldekranz 
609757e661aaSTobias Waldekranz 	err = mv88e6xxx_lag_sync_masks(ds);
609857e661aaSTobias Waldekranz 
609957e661aaSTobias Waldekranz 	if (!err)
610057e661aaSTobias Waldekranz 		err = mv88e6xxx_lag_sync_map(ds, lag);
610157e661aaSTobias Waldekranz 
610257e661aaSTobias Waldekranz 	return err;
610357e661aaSTobias Waldekranz }
610457e661aaSTobias Waldekranz 
610557e661aaSTobias Waldekranz static int mv88e6xxx_port_lag_change(struct dsa_switch *ds, int port)
610657e661aaSTobias Waldekranz {
610757e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
610857e661aaSTobias Waldekranz 	int err;
610957e661aaSTobias Waldekranz 
611057e661aaSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
611157e661aaSTobias Waldekranz 	err = mv88e6xxx_lag_sync_masks(ds);
611257e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
611357e661aaSTobias Waldekranz 	return err;
611457e661aaSTobias Waldekranz }
611557e661aaSTobias Waldekranz 
611657e661aaSTobias Waldekranz static int mv88e6xxx_port_lag_join(struct dsa_switch *ds, int port,
611757e661aaSTobias Waldekranz 				   struct net_device *lag,
611857e661aaSTobias Waldekranz 				   struct netdev_lag_upper_info *info)
611957e661aaSTobias Waldekranz {
612057e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
612157e661aaSTobias Waldekranz 	int err, id;
612257e661aaSTobias Waldekranz 
612357e661aaSTobias Waldekranz 	if (!mv88e6xxx_lag_can_offload(ds, lag, info))
612457e661aaSTobias Waldekranz 		return -EOPNOTSUPP;
612557e661aaSTobias Waldekranz 
612657e661aaSTobias Waldekranz 	id = dsa_lag_id(ds->dst, lag);
612757e661aaSTobias Waldekranz 
612857e661aaSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
612957e661aaSTobias Waldekranz 
613057e661aaSTobias Waldekranz 	err = mv88e6xxx_port_set_trunk(chip, port, true, id);
613157e661aaSTobias Waldekranz 	if (err)
613257e661aaSTobias Waldekranz 		goto err_unlock;
613357e661aaSTobias Waldekranz 
613457e661aaSTobias Waldekranz 	err = mv88e6xxx_lag_sync_masks_map(ds, lag);
613557e661aaSTobias Waldekranz 	if (err)
613657e661aaSTobias Waldekranz 		goto err_clear_trunk;
613757e661aaSTobias Waldekranz 
613857e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
613957e661aaSTobias Waldekranz 	return 0;
614057e661aaSTobias Waldekranz 
614157e661aaSTobias Waldekranz err_clear_trunk:
614257e661aaSTobias Waldekranz 	mv88e6xxx_port_set_trunk(chip, port, false, 0);
614357e661aaSTobias Waldekranz err_unlock:
614457e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
614557e661aaSTobias Waldekranz 	return err;
614657e661aaSTobias Waldekranz }
614757e661aaSTobias Waldekranz 
614857e661aaSTobias Waldekranz static int mv88e6xxx_port_lag_leave(struct dsa_switch *ds, int port,
614957e661aaSTobias Waldekranz 				    struct net_device *lag)
615057e661aaSTobias Waldekranz {
615157e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
615257e661aaSTobias Waldekranz 	int err_sync, err_trunk;
615357e661aaSTobias Waldekranz 
615457e661aaSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
615557e661aaSTobias Waldekranz 	err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag);
615657e661aaSTobias Waldekranz 	err_trunk = mv88e6xxx_port_set_trunk(chip, port, false, 0);
615757e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
615857e661aaSTobias Waldekranz 	return err_sync ? : err_trunk;
615957e661aaSTobias Waldekranz }
616057e661aaSTobias Waldekranz 
616157e661aaSTobias Waldekranz static int mv88e6xxx_crosschip_lag_change(struct dsa_switch *ds, int sw_index,
616257e661aaSTobias Waldekranz 					  int port)
616357e661aaSTobias Waldekranz {
616457e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
616557e661aaSTobias Waldekranz 	int err;
616657e661aaSTobias Waldekranz 
616757e661aaSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
616857e661aaSTobias Waldekranz 	err = mv88e6xxx_lag_sync_masks(ds);
616957e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
617057e661aaSTobias Waldekranz 	return err;
617157e661aaSTobias Waldekranz }
617257e661aaSTobias Waldekranz 
617357e661aaSTobias Waldekranz static int mv88e6xxx_crosschip_lag_join(struct dsa_switch *ds, int sw_index,
617457e661aaSTobias Waldekranz 					int port, struct net_device *lag,
617557e661aaSTobias Waldekranz 					struct netdev_lag_upper_info *info)
617657e661aaSTobias Waldekranz {
617757e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
617857e661aaSTobias Waldekranz 	int err;
617957e661aaSTobias Waldekranz 
618057e661aaSTobias Waldekranz 	if (!mv88e6xxx_lag_can_offload(ds, lag, info))
618157e661aaSTobias Waldekranz 		return -EOPNOTSUPP;
618257e661aaSTobias Waldekranz 
618357e661aaSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
618457e661aaSTobias Waldekranz 
618557e661aaSTobias Waldekranz 	err = mv88e6xxx_lag_sync_masks_map(ds, lag);
618657e661aaSTobias Waldekranz 	if (err)
618757e661aaSTobias Waldekranz 		goto unlock;
618857e661aaSTobias Waldekranz 
618957e661aaSTobias Waldekranz 	err = mv88e6xxx_pvt_map(chip, sw_index, port);
619057e661aaSTobias Waldekranz 
619157e661aaSTobias Waldekranz unlock:
619257e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
619357e661aaSTobias Waldekranz 	return err;
619457e661aaSTobias Waldekranz }
619557e661aaSTobias Waldekranz 
619657e661aaSTobias Waldekranz static int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index,
619757e661aaSTobias Waldekranz 					 int port, struct net_device *lag)
619857e661aaSTobias Waldekranz {
619957e661aaSTobias Waldekranz 	struct mv88e6xxx_chip *chip = ds->priv;
620057e661aaSTobias Waldekranz 	int err_sync, err_pvt;
620157e661aaSTobias Waldekranz 
620257e661aaSTobias Waldekranz 	mv88e6xxx_reg_lock(chip);
620357e661aaSTobias Waldekranz 	err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag);
620457e661aaSTobias Waldekranz 	err_pvt = mv88e6xxx_pvt_map(chip, sw_index, port);
620557e661aaSTobias Waldekranz 	mv88e6xxx_reg_unlock(chip);
620657e661aaSTobias Waldekranz 	return err_sync ? : err_pvt;
620757e661aaSTobias Waldekranz }
620857e661aaSTobias Waldekranz 
6209a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
62107b314362SAndrew Lunn 	.get_tag_protocol	= mv88e6xxx_get_tag_protocol,
62119a99bef5STobias Waldekranz 	.change_tag_protocol	= mv88e6xxx_change_tag_protocol,
6212fad09c73SVivien Didelot 	.setup			= mv88e6xxx_setup,
621323e8b470SAndrew Lunn 	.teardown		= mv88e6xxx_teardown,
6214fd292c18SVladimir Oltean 	.port_setup		= mv88e6xxx_port_setup,
6215fd292c18SVladimir Oltean 	.port_teardown		= mv88e6xxx_port_teardown,
6216c9a2356fSRussell King 	.phylink_validate	= mv88e6xxx_validate,
6217a5a6858bSRussell King 	.phylink_mac_link_state	= mv88e6xxx_serdes_pcs_get_state,
6218c9a2356fSRussell King 	.phylink_mac_config	= mv88e6xxx_mac_config,
6219a5a6858bSRussell King 	.phylink_mac_an_restart	= mv88e6xxx_serdes_pcs_an_restart,
6220c9a2356fSRussell King 	.phylink_mac_link_down	= mv88e6xxx_mac_link_down,
6221c9a2356fSRussell King 	.phylink_mac_link_up	= mv88e6xxx_mac_link_up,
6222fad09c73SVivien Didelot 	.get_strings		= mv88e6xxx_get_strings,
6223fad09c73SVivien Didelot 	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
6224fad09c73SVivien Didelot 	.get_sset_count		= mv88e6xxx_get_sset_count,
622504aca993SAndrew Lunn 	.port_enable		= mv88e6xxx_port_enable,
622604aca993SAndrew Lunn 	.port_disable		= mv88e6xxx_port_disable,
62272a550aecSAndrew Lunn 	.port_max_mtu		= mv88e6xxx_get_max_mtu,
62282a550aecSAndrew Lunn 	.port_change_mtu	= mv88e6xxx_change_mtu,
622908f50061SVivien Didelot 	.get_mac_eee		= mv88e6xxx_get_mac_eee,
623008f50061SVivien Didelot 	.set_mac_eee		= mv88e6xxx_set_mac_eee,
6231fad09c73SVivien Didelot 	.get_eeprom_len		= mv88e6xxx_get_eeprom_len,
6232fad09c73SVivien Didelot 	.get_eeprom		= mv88e6xxx_get_eeprom,
6233fad09c73SVivien Didelot 	.set_eeprom		= mv88e6xxx_set_eeprom,
6234fad09c73SVivien Didelot 	.get_regs_len		= mv88e6xxx_get_regs_len,
6235fad09c73SVivien Didelot 	.get_regs		= mv88e6xxx_get_regs,
6236da7dc875SVivien Didelot 	.get_rxnfc		= mv88e6xxx_get_rxnfc,
6237da7dc875SVivien Didelot 	.set_rxnfc		= mv88e6xxx_set_rxnfc,
62382cfcd964SVivien Didelot 	.set_ageing_time	= mv88e6xxx_set_ageing_time,
6239fad09c73SVivien Didelot 	.port_bridge_join	= mv88e6xxx_port_bridge_join,
6240fad09c73SVivien Didelot 	.port_bridge_leave	= mv88e6xxx_port_bridge_leave,
6241a8b659e7SVladimir Oltean 	.port_pre_bridge_flags	= mv88e6xxx_port_pre_bridge_flags,
6242a8b659e7SVladimir Oltean 	.port_bridge_flags	= mv88e6xxx_port_bridge_flags,
6243fad09c73SVivien Didelot 	.port_stp_state_set	= mv88e6xxx_port_stp_state_set,
6244749efcb8SVivien Didelot 	.port_fast_age		= mv88e6xxx_port_fast_age,
6245fad09c73SVivien Didelot 	.port_vlan_filtering	= mv88e6xxx_port_vlan_filtering,
6246fad09c73SVivien Didelot 	.port_vlan_add		= mv88e6xxx_port_vlan_add,
6247fad09c73SVivien Didelot 	.port_vlan_del		= mv88e6xxx_port_vlan_del,
6248fad09c73SVivien Didelot 	.port_fdb_add           = mv88e6xxx_port_fdb_add,
6249fad09c73SVivien Didelot 	.port_fdb_del           = mv88e6xxx_port_fdb_del,
6250fad09c73SVivien Didelot 	.port_fdb_dump          = mv88e6xxx_port_fdb_dump,
62517df8fbddSVivien Didelot 	.port_mdb_add           = mv88e6xxx_port_mdb_add,
62527df8fbddSVivien Didelot 	.port_mdb_del           = mv88e6xxx_port_mdb_del,
6253f0942e00SIwan R Timmer 	.port_mirror_add	= mv88e6xxx_port_mirror_add,
6254f0942e00SIwan R Timmer 	.port_mirror_del	= mv88e6xxx_port_mirror_del,
6255aec5ac88SVivien Didelot 	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
6256aec5ac88SVivien Didelot 	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
6257c6fe0ad2SBrandon Streiff 	.port_hwtstamp_set	= mv88e6xxx_port_hwtstamp_set,
6258c6fe0ad2SBrandon Streiff 	.port_hwtstamp_get	= mv88e6xxx_port_hwtstamp_get,
6259c6fe0ad2SBrandon Streiff 	.port_txtstamp		= mv88e6xxx_port_txtstamp,
6260c6fe0ad2SBrandon Streiff 	.port_rxtstamp		= mv88e6xxx_port_rxtstamp,
6261c6fe0ad2SBrandon Streiff 	.get_ts_info		= mv88e6xxx_get_ts_info,
626223e8b470SAndrew Lunn 	.devlink_param_get	= mv88e6xxx_devlink_param_get,
626323e8b470SAndrew Lunn 	.devlink_param_set	= mv88e6xxx_devlink_param_set,
626493157307SAndrew Lunn 	.devlink_info_get	= mv88e6xxx_devlink_info_get,
626557e661aaSTobias Waldekranz 	.port_lag_change	= mv88e6xxx_port_lag_change,
626657e661aaSTobias Waldekranz 	.port_lag_join		= mv88e6xxx_port_lag_join,
626757e661aaSTobias Waldekranz 	.port_lag_leave		= mv88e6xxx_port_lag_leave,
626857e661aaSTobias Waldekranz 	.crosschip_lag_change	= mv88e6xxx_crosschip_lag_change,
626957e661aaSTobias Waldekranz 	.crosschip_lag_join	= mv88e6xxx_crosschip_lag_join,
627057e661aaSTobias Waldekranz 	.crosschip_lag_leave	= mv88e6xxx_crosschip_lag_leave,
6271ce5df689SVladimir Oltean 	.port_bridge_tx_fwd_offload = mv88e6xxx_bridge_tx_fwd_offload,
6272ce5df689SVladimir Oltean 	.port_bridge_tx_fwd_unoffload = mv88e6xxx_bridge_tx_fwd_unoffload,
6273fad09c73SVivien Didelot };
6274fad09c73SVivien Didelot 
627555ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
6276fad09c73SVivien Didelot {
6277fad09c73SVivien Didelot 	struct device *dev = chip->dev;
6278fad09c73SVivien Didelot 	struct dsa_switch *ds;
6279fad09c73SVivien Didelot 
62807e99e347SVivien Didelot 	ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
6281fad09c73SVivien Didelot 	if (!ds)
6282fad09c73SVivien Didelot 		return -ENOMEM;
6283fad09c73SVivien Didelot 
62847e99e347SVivien Didelot 	ds->dev = dev;
62857e99e347SVivien Didelot 	ds->num_ports = mv88e6xxx_num_ports(chip);
6286fad09c73SVivien Didelot 	ds->priv = chip;
6287877b7cb0SAndrew Lunn 	ds->dev = dev;
62889d490b4eSVivien Didelot 	ds->ops = &mv88e6xxx_switch_ops;
62899ff74f24SVivien Didelot 	ds->ageing_time_min = chip->info->age_time_coeff;
62909ff74f24SVivien Didelot 	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
6291fad09c73SVivien Didelot 
629257e661aaSTobias Waldekranz 	/* Some chips support up to 32, but that requires enabling the
629357e661aaSTobias Waldekranz 	 * 5-bit port mode, which we do not support. 640k^W16 ought to
629457e661aaSTobias Waldekranz 	 * be enough for anyone.
629557e661aaSTobias Waldekranz 	 */
6296b80dc51bSTobias Waldekranz 	ds->num_lag_ids = mv88e6xxx_has_lag(chip) ? 16 : 0;
629757e661aaSTobias Waldekranz 
6298fad09c73SVivien Didelot 	dev_set_drvdata(dev, ds);
6299fad09c73SVivien Didelot 
630023c9ee49SVivien Didelot 	return dsa_register_switch(ds);
6301fad09c73SVivien Didelot }
6302fad09c73SVivien Didelot 
6303fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
6304fad09c73SVivien Didelot {
6305fad09c73SVivien Didelot 	dsa_unregister_switch(chip->ds);
6306fad09c73SVivien Didelot }
6307fad09c73SVivien Didelot 
6308877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev)
6309877b7cb0SAndrew Lunn {
6310877b7cb0SAndrew Lunn 	const struct of_device_id *matches = dev->driver->of_match_table;
6311877b7cb0SAndrew Lunn 	const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data;
6312877b7cb0SAndrew Lunn 
6313877b7cb0SAndrew Lunn 	for (; matches->name[0] || matches->type[0] || matches->compatible[0];
6314877b7cb0SAndrew Lunn 	     matches++) {
6315877b7cb0SAndrew Lunn 		if (!strcmp(pdata->compatible, matches->compatible))
6316877b7cb0SAndrew Lunn 			return matches->data;
6317877b7cb0SAndrew Lunn 	}
6318877b7cb0SAndrew Lunn 	return NULL;
6319877b7cb0SAndrew Lunn }
6320877b7cb0SAndrew Lunn 
6321bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration
6322bcd3d9d9SMiquel Raynal  * would be lost after a power cycle so prevent it to be suspended.
6323bcd3d9d9SMiquel Raynal  */
6324bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev)
6325bcd3d9d9SMiquel Raynal {
6326bcd3d9d9SMiquel Raynal 	return -EOPNOTSUPP;
6327bcd3d9d9SMiquel Raynal }
6328bcd3d9d9SMiquel Raynal 
6329bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev)
6330bcd3d9d9SMiquel Raynal {
6331bcd3d9d9SMiquel Raynal 	return 0;
6332bcd3d9d9SMiquel Raynal }
6333bcd3d9d9SMiquel Raynal 
6334bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume);
6335bcd3d9d9SMiquel Raynal 
6336fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev)
6337fad09c73SVivien Didelot {
6338877b7cb0SAndrew Lunn 	struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data;
63397ddae24fSDavid S. Miller 	const struct mv88e6xxx_info *compat_info = NULL;
6340fad09c73SVivien Didelot 	struct device *dev = &mdiodev->dev;
6341fad09c73SVivien Didelot 	struct device_node *np = dev->of_node;
6342fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
6343877b7cb0SAndrew Lunn 	int port;
6344fad09c73SVivien Didelot 	int err;
6345fad09c73SVivien Didelot 
63467bb8c996SAndrew Lunn 	if (!np && !pdata)
63477bb8c996SAndrew Lunn 		return -EINVAL;
63487bb8c996SAndrew Lunn 
6349877b7cb0SAndrew Lunn 	if (np)
6350fad09c73SVivien Didelot 		compat_info = of_device_get_match_data(dev);
6351877b7cb0SAndrew Lunn 
6352877b7cb0SAndrew Lunn 	if (pdata) {
6353877b7cb0SAndrew Lunn 		compat_info = pdata_device_get_match_data(dev);
6354877b7cb0SAndrew Lunn 
6355877b7cb0SAndrew Lunn 		if (!pdata->netdev)
6356877b7cb0SAndrew Lunn 			return -EINVAL;
6357877b7cb0SAndrew Lunn 
6358877b7cb0SAndrew Lunn 		for (port = 0; port < DSA_MAX_PORTS; port++) {
6359877b7cb0SAndrew Lunn 			if (!(pdata->enabled_ports & (1 << port)))
6360877b7cb0SAndrew Lunn 				continue;
6361877b7cb0SAndrew Lunn 			if (strcmp(pdata->cd.port_names[port], "cpu"))
6362877b7cb0SAndrew Lunn 				continue;
6363877b7cb0SAndrew Lunn 			pdata->cd.netdev[port] = &pdata->netdev->dev;
6364877b7cb0SAndrew Lunn 			break;
6365877b7cb0SAndrew Lunn 		}
6366877b7cb0SAndrew Lunn 	}
6367877b7cb0SAndrew Lunn 
6368fad09c73SVivien Didelot 	if (!compat_info)
6369fad09c73SVivien Didelot 		return -EINVAL;
6370fad09c73SVivien Didelot 
6371fad09c73SVivien Didelot 	chip = mv88e6xxx_alloc_chip(dev);
6372877b7cb0SAndrew Lunn 	if (!chip) {
6373877b7cb0SAndrew Lunn 		err = -ENOMEM;
6374877b7cb0SAndrew Lunn 		goto out;
6375877b7cb0SAndrew Lunn 	}
6376fad09c73SVivien Didelot 
6377fad09c73SVivien Didelot 	chip->info = compat_info;
6378fad09c73SVivien Didelot 
6379fad09c73SVivien Didelot 	err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
6380fad09c73SVivien Didelot 	if (err)
6381877b7cb0SAndrew Lunn 		goto out;
6382fad09c73SVivien Didelot 
6383b4308f04SAndrew Lunn 	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
6384877b7cb0SAndrew Lunn 	if (IS_ERR(chip->reset)) {
6385877b7cb0SAndrew Lunn 		err = PTR_ERR(chip->reset);
6386877b7cb0SAndrew Lunn 		goto out;
6387877b7cb0SAndrew Lunn 	}
63887b75e49dSBaruch Siach 	if (chip->reset)
63897b75e49dSBaruch Siach 		usleep_range(1000, 2000);
6390b4308f04SAndrew Lunn 
6391fad09c73SVivien Didelot 	err = mv88e6xxx_detect(chip);
6392fad09c73SVivien Didelot 	if (err)
6393877b7cb0SAndrew Lunn 		goto out;
6394fad09c73SVivien Didelot 
6395670bb80fSTobias Waldekranz 	if (chip->info->edsa_support == MV88E6XXX_EDSA_SUPPORTED)
6396670bb80fSTobias Waldekranz 		chip->tag_protocol = DSA_TAG_PROTO_EDSA;
6397670bb80fSTobias Waldekranz 	else
6398670bb80fSTobias Waldekranz 		chip->tag_protocol = DSA_TAG_PROTO_DSA;
6399670bb80fSTobias Waldekranz 
6400e57e5e77SVivien Didelot 	mv88e6xxx_phy_init(chip);
6401e57e5e77SVivien Didelot 
640200baabe5SAndrew Lunn 	if (chip->info->ops->get_eeprom) {
640300baabe5SAndrew Lunn 		if (np)
640400baabe5SAndrew Lunn 			of_property_read_u32(np, "eeprom-length",
640500baabe5SAndrew Lunn 					     &chip->eeprom_len);
640600baabe5SAndrew Lunn 		else
640700baabe5SAndrew Lunn 			chip->eeprom_len = pdata->eeprom_len;
640800baabe5SAndrew Lunn 	}
6409fad09c73SVivien Didelot 
6410c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
6411dc30c35bSAndrew Lunn 	err = mv88e6xxx_switch_reset(chip);
6412c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
6413fad09c73SVivien Didelot 	if (err)
6414dc30c35bSAndrew Lunn 		goto out;
6415fad09c73SVivien Didelot 
6416a27415deSAndrew Lunn 	if (np) {
6417dc30c35bSAndrew Lunn 		chip->irq = of_irq_get(np, 0);
6418dc30c35bSAndrew Lunn 		if (chip->irq == -EPROBE_DEFER) {
6419dc30c35bSAndrew Lunn 			err = chip->irq;
6420dc30c35bSAndrew Lunn 			goto out;
6421fad09c73SVivien Didelot 		}
6422a27415deSAndrew Lunn 	}
6423a27415deSAndrew Lunn 
6424a27415deSAndrew Lunn 	if (pdata)
6425a27415deSAndrew Lunn 		chip->irq = pdata->irq;
6426fad09c73SVivien Didelot 
6427294d711eSAndrew Lunn 	/* Has to be performed before the MDIO bus is created, because
6428a708767eSUwe Kleine-König 	 * the PHYs will link their interrupts to these interrupt
6429294d711eSAndrew Lunn 	 * controllers
6430dc30c35bSAndrew Lunn 	 */
6431c9acece0SRasmus Villemoes 	mv88e6xxx_reg_lock(chip);
6432294d711eSAndrew Lunn 	if (chip->irq > 0)
6433dc30c35bSAndrew Lunn 		err = mv88e6xxx_g1_irq_setup(chip);
6434294d711eSAndrew Lunn 	else
6435294d711eSAndrew Lunn 		err = mv88e6xxx_irq_poll_setup(chip);
6436c9acece0SRasmus Villemoes 	mv88e6xxx_reg_unlock(chip);
6437dc30c35bSAndrew Lunn 
6438dc30c35bSAndrew Lunn 	if (err)
6439dc30c35bSAndrew Lunn 		goto out;
6440dc30c35bSAndrew Lunn 
6441d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0) {
6442dc30c35bSAndrew Lunn 		err = mv88e6xxx_g2_irq_setup(chip);
6443dc30c35bSAndrew Lunn 		if (err)
6444dc30c35bSAndrew Lunn 			goto out_g1_irq;
6445dc30c35bSAndrew Lunn 	}
64460977644cSAndrew Lunn 
64470977644cSAndrew Lunn 	err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
64480977644cSAndrew Lunn 	if (err)
64490977644cSAndrew Lunn 		goto out_g2_irq;
645062eb1162SAndrew Lunn 
645162eb1162SAndrew Lunn 	err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
645262eb1162SAndrew Lunn 	if (err)
645362eb1162SAndrew Lunn 		goto out_g1_atu_prob_irq;
6454dc30c35bSAndrew Lunn 
6455a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdios_register(chip, np);
6456dc30c35bSAndrew Lunn 	if (err)
645762eb1162SAndrew Lunn 		goto out_g1_vtu_prob_irq;
6458dc30c35bSAndrew Lunn 
645955ed0ce0SFlorian Fainelli 	err = mv88e6xxx_register_switch(chip);
6460dc30c35bSAndrew Lunn 	if (err)
6461dc30c35bSAndrew Lunn 		goto out_mdio;
6462dc30c35bSAndrew Lunn 
6463fad09c73SVivien Didelot 	return 0;
6464dc30c35bSAndrew Lunn 
6465dc30c35bSAndrew Lunn out_mdio:
6466a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
646762eb1162SAndrew Lunn out_g1_vtu_prob_irq:
646862eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
64690977644cSAndrew Lunn out_g1_atu_prob_irq:
64700977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
6471dc30c35bSAndrew Lunn out_g2_irq:
6472294d711eSAndrew Lunn 	if (chip->info->g2_irqs > 0)
6473dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
6474dc30c35bSAndrew Lunn out_g1_irq:
6475294d711eSAndrew Lunn 	if (chip->irq > 0)
6476dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
6477294d711eSAndrew Lunn 	else
6478294d711eSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
6479dc30c35bSAndrew Lunn out:
6480877b7cb0SAndrew Lunn 	if (pdata)
6481877b7cb0SAndrew Lunn 		dev_put(pdata->netdev);
6482877b7cb0SAndrew Lunn 
6483dc30c35bSAndrew Lunn 	return err;
6484fad09c73SVivien Didelot }
6485fad09c73SVivien Didelot 
6486fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev)
6487fad09c73SVivien Didelot {
6488fad09c73SVivien Didelot 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
64890650bf52SVladimir Oltean 	struct mv88e6xxx_chip *chip;
64900650bf52SVladimir Oltean 
64910650bf52SVladimir Oltean 	if (!ds)
64920650bf52SVladimir Oltean 		return;
64930650bf52SVladimir Oltean 
64940650bf52SVladimir Oltean 	chip = ds->priv;
6495fad09c73SVivien Didelot 
6496c6fe0ad2SBrandon Streiff 	if (chip->info->ptp_support) {
6497c6fe0ad2SBrandon Streiff 		mv88e6xxx_hwtstamp_free(chip);
64982fa8d3afSBrandon Streiff 		mv88e6xxx_ptp_free(chip);
6499c6fe0ad2SBrandon Streiff 	}
65002fa8d3afSBrandon Streiff 
6501930188ceSAndrew Lunn 	mv88e6xxx_phy_destroy(chip);
6502fad09c73SVivien Didelot 	mv88e6xxx_unregister_switch(chip);
6503a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
6504dc30c35bSAndrew Lunn 
650562eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
65060977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
650776f38f1fSAndrew Lunn 
6508d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0)
6509dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
651076f38f1fSAndrew Lunn 
651176f38f1fSAndrew Lunn 	if (chip->irq > 0)
6512dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
651376f38f1fSAndrew Lunn 	else
651476f38f1fSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
65150650bf52SVladimir Oltean 
65160650bf52SVladimir Oltean 	dev_set_drvdata(&mdiodev->dev, NULL);
65170650bf52SVladimir Oltean }
65180650bf52SVladimir Oltean 
65190650bf52SVladimir Oltean static void mv88e6xxx_shutdown(struct mdio_device *mdiodev)
65200650bf52SVladimir Oltean {
65210650bf52SVladimir Oltean 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
65220650bf52SVladimir Oltean 
65230650bf52SVladimir Oltean 	if (!ds)
65240650bf52SVladimir Oltean 		return;
65250650bf52SVladimir Oltean 
65260650bf52SVladimir Oltean 	dsa_switch_shutdown(ds);
65270650bf52SVladimir Oltean 
65280650bf52SVladimir Oltean 	dev_set_drvdata(&mdiodev->dev, NULL);
6529fad09c73SVivien Didelot }
6530fad09c73SVivien Didelot 
6531fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = {
6532fad09c73SVivien Didelot 	{
6533fad09c73SVivien Didelot 		.compatible = "marvell,mv88e6085",
6534fad09c73SVivien Didelot 		.data = &mv88e6xxx_table[MV88E6085],
6535fad09c73SVivien Didelot 	},
65361a3b39ecSAndrew Lunn 	{
65371a3b39ecSAndrew Lunn 		.compatible = "marvell,mv88e6190",
65381a3b39ecSAndrew Lunn 		.data = &mv88e6xxx_table[MV88E6190],
65391a3b39ecSAndrew Lunn 	},
65401f71836fSRasmus Villemoes 	{
65411f71836fSRasmus Villemoes 		.compatible = "marvell,mv88e6250",
65421f71836fSRasmus Villemoes 		.data = &mv88e6xxx_table[MV88E6250],
65431f71836fSRasmus Villemoes 	},
6544fad09c73SVivien Didelot 	{ /* sentinel */ },
6545fad09c73SVivien Didelot };
6546fad09c73SVivien Didelot 
6547fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);
6548fad09c73SVivien Didelot 
6549fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = {
6550fad09c73SVivien Didelot 	.probe	= mv88e6xxx_probe,
6551fad09c73SVivien Didelot 	.remove = mv88e6xxx_remove,
65520650bf52SVladimir Oltean 	.shutdown = mv88e6xxx_shutdown,
6553fad09c73SVivien Didelot 	.mdiodrv.driver = {
6554fad09c73SVivien Didelot 		.name = "mv88e6085",
6555fad09c73SVivien Didelot 		.of_match_table = mv88e6xxx_of_match,
6556bcd3d9d9SMiquel Raynal 		.pm = &mv88e6xxx_pm_ops,
6557fad09c73SVivien Didelot 	},
6558fad09c73SVivien Didelot };
6559fad09c73SVivien Didelot 
65607324d50eSAndrew Lunn mdio_module_driver(mv88e6xxx_driver);
6561fad09c73SVivien Didelot 
6562fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
6563fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
6564fad09c73SVivien Didelot MODULE_LICENSE("GPL");
6565