xref: /openbmc/linux/drivers/net/dsa/mv88e6xxx/chip.c (revision fcf15367)
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 
13fad09c73SVivien Didelot #include <linux/delay.h>
14fad09c73SVivien Didelot #include <linux/etherdevice.h>
15fad09c73SVivien Didelot #include <linux/ethtool.h>
16fad09c73SVivien Didelot #include <linux/if_bridge.h>
17dc30c35bSAndrew Lunn #include <linux/interrupt.h>
18dc30c35bSAndrew Lunn #include <linux/irq.h>
19dc30c35bSAndrew Lunn #include <linux/irqdomain.h>
20fad09c73SVivien Didelot #include <linux/jiffies.h>
21fad09c73SVivien Didelot #include <linux/list.h>
22fad09c73SVivien Didelot #include <linux/mdio.h>
23fad09c73SVivien Didelot #include <linux/module.h>
24fad09c73SVivien Didelot #include <linux/of_device.h>
25dc30c35bSAndrew Lunn #include <linux/of_irq.h>
26fad09c73SVivien Didelot #include <linux/of_mdio.h>
27877b7cb0SAndrew Lunn #include <linux/platform_data/mv88e6xxx.h>
28fad09c73SVivien Didelot #include <linux/netdevice.h>
29fad09c73SVivien Didelot #include <linux/gpio/consumer.h>
30fad09c73SVivien Didelot #include <linux/phy.h>
31c9a2356fSRussell King #include <linux/phylink.h>
32fad09c73SVivien Didelot #include <net/dsa.h>
33ec561276SVivien Didelot 
344d5f2ba7SVivien Didelot #include "chip.h"
35a935c052SVivien Didelot #include "global1.h"
36ec561276SVivien Didelot #include "global2.h"
37c6fe0ad2SBrandon Streiff #include "hwtstamp.h"
3810fa5bfcSAndrew Lunn #include "phy.h"
3918abed21SVivien Didelot #include "port.h"
402fa8d3afSBrandon Streiff #include "ptp.h"
416d91782fSAndrew Lunn #include "serdes.h"
42e7ba0fadSVivien Didelot #include "smi.h"
43fad09c73SVivien Didelot 
44fad09c73SVivien Didelot static void assert_reg_lock(struct mv88e6xxx_chip *chip)
45fad09c73SVivien Didelot {
46fad09c73SVivien Didelot 	if (unlikely(!mutex_is_locked(&chip->reg_lock))) {
47fad09c73SVivien Didelot 		dev_err(chip->dev, "Switch registers lock not held!\n");
48fad09c73SVivien Didelot 		dump_stack();
49fad09c73SVivien Didelot 	}
50fad09c73SVivien Didelot }
51fad09c73SVivien Didelot 
52ec561276SVivien Didelot int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
53fad09c73SVivien Didelot {
54fad09c73SVivien Didelot 	int err;
55fad09c73SVivien Didelot 
56fad09c73SVivien Didelot 	assert_reg_lock(chip);
57fad09c73SVivien Didelot 
58fad09c73SVivien Didelot 	err = mv88e6xxx_smi_read(chip, addr, reg, val);
59fad09c73SVivien Didelot 	if (err)
60fad09c73SVivien Didelot 		return err;
61fad09c73SVivien Didelot 
62fad09c73SVivien Didelot 	dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
63fad09c73SVivien Didelot 		addr, reg, *val);
64fad09c73SVivien Didelot 
65fad09c73SVivien Didelot 	return 0;
66fad09c73SVivien Didelot }
67fad09c73SVivien Didelot 
68ec561276SVivien Didelot int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
69fad09c73SVivien Didelot {
70fad09c73SVivien Didelot 	int err;
71fad09c73SVivien Didelot 
72fad09c73SVivien Didelot 	assert_reg_lock(chip);
73fad09c73SVivien Didelot 
74fad09c73SVivien Didelot 	err = mv88e6xxx_smi_write(chip, addr, reg, val);
75fad09c73SVivien Didelot 	if (err)
76fad09c73SVivien Didelot 		return err;
77fad09c73SVivien Didelot 
78fad09c73SVivien Didelot 	dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
79fad09c73SVivien Didelot 		addr, reg, val);
80fad09c73SVivien Didelot 
81fad09c73SVivien Didelot 	return 0;
82fad09c73SVivien Didelot }
83fad09c73SVivien Didelot 
8410fa5bfcSAndrew Lunn struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
85a3c53be5SAndrew Lunn {
86a3c53be5SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
87a3c53be5SAndrew Lunn 
88a3c53be5SAndrew Lunn 	mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus,
89a3c53be5SAndrew Lunn 				    list);
90a3c53be5SAndrew Lunn 	if (!mdio_bus)
91a3c53be5SAndrew Lunn 		return NULL;
92a3c53be5SAndrew Lunn 
93a3c53be5SAndrew Lunn 	return mdio_bus->bus;
94a3c53be5SAndrew Lunn }
95a3c53be5SAndrew Lunn 
96dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_mask(struct irq_data *d)
97dc30c35bSAndrew Lunn {
98dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
99dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
100dc30c35bSAndrew Lunn 
101dc30c35bSAndrew Lunn 	chip->g1_irq.masked |= (1 << n);
102dc30c35bSAndrew Lunn }
103dc30c35bSAndrew Lunn 
104dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_unmask(struct irq_data *d)
105dc30c35bSAndrew Lunn {
106dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
107dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
108dc30c35bSAndrew Lunn 
109dc30c35bSAndrew Lunn 	chip->g1_irq.masked &= ~(1 << n);
110dc30c35bSAndrew Lunn }
111dc30c35bSAndrew Lunn 
112294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip)
113dc30c35bSAndrew Lunn {
114dc30c35bSAndrew Lunn 	unsigned int nhandled = 0;
115dc30c35bSAndrew Lunn 	unsigned int sub_irq;
116dc30c35bSAndrew Lunn 	unsigned int n;
117dc30c35bSAndrew Lunn 	u16 reg;
1187c0db24cSJohn David Anglin 	u16 ctl1;
119dc30c35bSAndrew Lunn 	int err;
120dc30c35bSAndrew Lunn 
121dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
12282466921SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
123dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
124dc30c35bSAndrew Lunn 
125dc30c35bSAndrew Lunn 	if (err)
126dc30c35bSAndrew Lunn 		goto out;
127dc30c35bSAndrew Lunn 
1287c0db24cSJohn David Anglin 	do {
129dc30c35bSAndrew Lunn 		for (n = 0; n < chip->g1_irq.nirqs; ++n) {
130dc30c35bSAndrew Lunn 			if (reg & (1 << n)) {
1317c0db24cSJohn David Anglin 				sub_irq = irq_find_mapping(chip->g1_irq.domain,
1327c0db24cSJohn David Anglin 							   n);
133dc30c35bSAndrew Lunn 				handle_nested_irq(sub_irq);
134dc30c35bSAndrew Lunn 				++nhandled;
135dc30c35bSAndrew Lunn 			}
136dc30c35bSAndrew Lunn 		}
1377c0db24cSJohn David Anglin 
1387c0db24cSJohn David Anglin 		mutex_lock(&chip->reg_lock);
1397c0db24cSJohn David Anglin 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1);
1407c0db24cSJohn David Anglin 		if (err)
1417c0db24cSJohn David Anglin 			goto unlock;
1427c0db24cSJohn David Anglin 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
1437c0db24cSJohn David Anglin unlock:
1447c0db24cSJohn David Anglin 		mutex_unlock(&chip->reg_lock);
1457c0db24cSJohn David Anglin 		if (err)
1467c0db24cSJohn David Anglin 			goto out;
1477c0db24cSJohn David Anglin 		ctl1 &= GENMASK(chip->g1_irq.nirqs, 0);
1487c0db24cSJohn David Anglin 	} while (reg & ctl1);
1497c0db24cSJohn David Anglin 
150dc30c35bSAndrew Lunn out:
151dc30c35bSAndrew Lunn 	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
152dc30c35bSAndrew Lunn }
153dc30c35bSAndrew Lunn 
154294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
155294d711eSAndrew Lunn {
156294d711eSAndrew Lunn 	struct mv88e6xxx_chip *chip = dev_id;
157294d711eSAndrew Lunn 
158294d711eSAndrew Lunn 	return mv88e6xxx_g1_irq_thread_work(chip);
159294d711eSAndrew Lunn }
160294d711eSAndrew Lunn 
161dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
162dc30c35bSAndrew Lunn {
163dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
164dc30c35bSAndrew Lunn 
165dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
166dc30c35bSAndrew Lunn }
167dc30c35bSAndrew Lunn 
168dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
169dc30c35bSAndrew Lunn {
170dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
171dc30c35bSAndrew Lunn 	u16 mask = GENMASK(chip->g1_irq.nirqs, 0);
172dc30c35bSAndrew Lunn 	u16 reg;
173dc30c35bSAndrew Lunn 	int err;
174dc30c35bSAndrew Lunn 
175d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &reg);
176dc30c35bSAndrew Lunn 	if (err)
177dc30c35bSAndrew Lunn 		goto out;
178dc30c35bSAndrew Lunn 
179dc30c35bSAndrew Lunn 	reg &= ~mask;
180dc30c35bSAndrew Lunn 	reg |= (~chip->g1_irq.masked & mask);
181dc30c35bSAndrew Lunn 
182d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg);
183dc30c35bSAndrew Lunn 	if (err)
184dc30c35bSAndrew Lunn 		goto out;
185dc30c35bSAndrew Lunn 
186dc30c35bSAndrew Lunn out:
187dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
188dc30c35bSAndrew Lunn }
189dc30c35bSAndrew Lunn 
1906eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g1_irq_chip = {
191dc30c35bSAndrew Lunn 	.name			= "mv88e6xxx-g1",
192dc30c35bSAndrew Lunn 	.irq_mask		= mv88e6xxx_g1_irq_mask,
193dc30c35bSAndrew Lunn 	.irq_unmask		= mv88e6xxx_g1_irq_unmask,
194dc30c35bSAndrew Lunn 	.irq_bus_lock		= mv88e6xxx_g1_irq_bus_lock,
195dc30c35bSAndrew Lunn 	.irq_bus_sync_unlock	= mv88e6xxx_g1_irq_bus_sync_unlock,
196dc30c35bSAndrew Lunn };
197dc30c35bSAndrew Lunn 
198dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d,
199dc30c35bSAndrew Lunn 				       unsigned int irq,
200dc30c35bSAndrew Lunn 				       irq_hw_number_t hwirq)
201dc30c35bSAndrew Lunn {
202dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = d->host_data;
203dc30c35bSAndrew Lunn 
204dc30c35bSAndrew Lunn 	irq_set_chip_data(irq, d->host_data);
205dc30c35bSAndrew Lunn 	irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq);
206dc30c35bSAndrew Lunn 	irq_set_noprobe(irq);
207dc30c35bSAndrew Lunn 
208dc30c35bSAndrew Lunn 	return 0;
209dc30c35bSAndrew Lunn }
210dc30c35bSAndrew Lunn 
211dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = {
212dc30c35bSAndrew Lunn 	.map	= mv88e6xxx_g1_irq_domain_map,
213dc30c35bSAndrew Lunn 	.xlate	= irq_domain_xlate_twocell,
214dc30c35bSAndrew Lunn };
215dc30c35bSAndrew Lunn 
2163d82475aSUwe Kleine-König /* To be called with reg_lock held */
217294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip)
218dc30c35bSAndrew Lunn {
219dc30c35bSAndrew Lunn 	int irq, virq;
2203460a577SAndrew Lunn 	u16 mask;
2213460a577SAndrew Lunn 
222d77f4321SVivien Didelot 	mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
2233d5fdba1SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
224d77f4321SVivien Didelot 	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
2253460a577SAndrew Lunn 
2265edef2f2SAndreas Färber 	for (irq = 0; irq < chip->g1_irq.nirqs; irq++) {
227a3db3d3aSAndrew Lunn 		virq = irq_find_mapping(chip->g1_irq.domain, irq);
228dc30c35bSAndrew Lunn 		irq_dispose_mapping(virq);
229dc30c35bSAndrew Lunn 	}
230dc30c35bSAndrew Lunn 
231a3db3d3aSAndrew Lunn 	irq_domain_remove(chip->g1_irq.domain);
232dc30c35bSAndrew Lunn }
233dc30c35bSAndrew Lunn 
234294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
235294d711eSAndrew Lunn {
2363d82475aSUwe Kleine-König 	/*
2373d82475aSUwe Kleine-König 	 * free_irq must be called without reg_lock taken because the irq
2383d82475aSUwe Kleine-König 	 * handler takes this lock, too.
2393d82475aSUwe Kleine-König 	 */
240294d711eSAndrew Lunn 	free_irq(chip->irq, chip);
2413d82475aSUwe Kleine-König 
2423d82475aSUwe Kleine-König 	mutex_lock(&chip->reg_lock);
2433d82475aSUwe Kleine-König 	mv88e6xxx_g1_irq_free_common(chip);
2443d82475aSUwe Kleine-König 	mutex_unlock(&chip->reg_lock);
245294d711eSAndrew Lunn }
246294d711eSAndrew Lunn 
247294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip)
248dc30c35bSAndrew Lunn {
2493dd0ef05SAndrew Lunn 	int err, irq, virq;
2503dd0ef05SAndrew Lunn 	u16 reg, mask;
251dc30c35bSAndrew Lunn 
252dc30c35bSAndrew Lunn 	chip->g1_irq.nirqs = chip->info->g1_irqs;
253dc30c35bSAndrew Lunn 	chip->g1_irq.domain = irq_domain_add_simple(
254dc30c35bSAndrew Lunn 		NULL, chip->g1_irq.nirqs, 0,
255dc30c35bSAndrew Lunn 		&mv88e6xxx_g1_irq_domain_ops, chip);
256dc30c35bSAndrew Lunn 	if (!chip->g1_irq.domain)
257dc30c35bSAndrew Lunn 		return -ENOMEM;
258dc30c35bSAndrew Lunn 
259dc30c35bSAndrew Lunn 	for (irq = 0; irq < chip->g1_irq.nirqs; irq++)
260dc30c35bSAndrew Lunn 		irq_create_mapping(chip->g1_irq.domain, irq);
261dc30c35bSAndrew Lunn 
262dc30c35bSAndrew Lunn 	chip->g1_irq.chip = mv88e6xxx_g1_irq_chip;
263dc30c35bSAndrew Lunn 	chip->g1_irq.masked = ~0;
264dc30c35bSAndrew Lunn 
265d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
266dc30c35bSAndrew Lunn 	if (err)
2673dd0ef05SAndrew Lunn 		goto out_mapping;
268dc30c35bSAndrew Lunn 
2693dd0ef05SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
270dc30c35bSAndrew Lunn 
271d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
272dc30c35bSAndrew Lunn 	if (err)
2733dd0ef05SAndrew Lunn 		goto out_disable;
274dc30c35bSAndrew Lunn 
275dc30c35bSAndrew Lunn 	/* Reading the interrupt status clears (most of) them */
27682466921SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
277dc30c35bSAndrew Lunn 	if (err)
2783dd0ef05SAndrew Lunn 		goto out_disable;
279dc30c35bSAndrew Lunn 
280dc30c35bSAndrew Lunn 	return 0;
281dc30c35bSAndrew Lunn 
2823dd0ef05SAndrew Lunn out_disable:
2833d5fdba1SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
284d77f4321SVivien Didelot 	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
2853dd0ef05SAndrew Lunn 
2863dd0ef05SAndrew Lunn out_mapping:
2873dd0ef05SAndrew Lunn 	for (irq = 0; irq < 16; irq++) {
2883dd0ef05SAndrew Lunn 		virq = irq_find_mapping(chip->g1_irq.domain, irq);
2893dd0ef05SAndrew Lunn 		irq_dispose_mapping(virq);
2903dd0ef05SAndrew Lunn 	}
2913dd0ef05SAndrew Lunn 
2923dd0ef05SAndrew Lunn 	irq_domain_remove(chip->g1_irq.domain);
293dc30c35bSAndrew Lunn 
294dc30c35bSAndrew Lunn 	return err;
295dc30c35bSAndrew Lunn }
296dc30c35bSAndrew Lunn 
297294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
298294d711eSAndrew Lunn {
299f6d9758bSAndrew Lunn 	static struct lock_class_key lock_key;
300f6d9758bSAndrew Lunn 	static struct lock_class_key request_key;
301294d711eSAndrew Lunn 	int err;
302294d711eSAndrew Lunn 
303294d711eSAndrew Lunn 	err = mv88e6xxx_g1_irq_setup_common(chip);
304294d711eSAndrew Lunn 	if (err)
305294d711eSAndrew Lunn 		return err;
306294d711eSAndrew Lunn 
307f6d9758bSAndrew Lunn 	/* These lock classes tells lockdep that global 1 irqs are in
308f6d9758bSAndrew Lunn 	 * a different category than their parent GPIO, so it won't
309f6d9758bSAndrew Lunn 	 * report false recursion.
310f6d9758bSAndrew Lunn 	 */
311f6d9758bSAndrew Lunn 	irq_set_lockdep_class(chip->irq, &lock_key, &request_key);
312f6d9758bSAndrew Lunn 
313342a0ee7SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
314294d711eSAndrew Lunn 	err = request_threaded_irq(chip->irq, NULL,
315294d711eSAndrew Lunn 				   mv88e6xxx_g1_irq_thread_fn,
3160340376eSMarek Behún 				   IRQF_ONESHOT | IRQF_SHARED,
317294d711eSAndrew Lunn 				   dev_name(chip->dev), chip);
318342a0ee7SAndrew Lunn 	mutex_lock(&chip->reg_lock);
319294d711eSAndrew Lunn 	if (err)
320294d711eSAndrew Lunn 		mv88e6xxx_g1_irq_free_common(chip);
321294d711eSAndrew Lunn 
322294d711eSAndrew Lunn 	return err;
323294d711eSAndrew Lunn }
324294d711eSAndrew Lunn 
325294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work)
326294d711eSAndrew Lunn {
327294d711eSAndrew Lunn 	struct mv88e6xxx_chip *chip = container_of(work,
328294d711eSAndrew Lunn 						   struct mv88e6xxx_chip,
329294d711eSAndrew Lunn 						   irq_poll_work.work);
330294d711eSAndrew Lunn 	mv88e6xxx_g1_irq_thread_work(chip);
331294d711eSAndrew Lunn 
332294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
333294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
334294d711eSAndrew Lunn }
335294d711eSAndrew Lunn 
336294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip)
337294d711eSAndrew Lunn {
338294d711eSAndrew Lunn 	int err;
339294d711eSAndrew Lunn 
340294d711eSAndrew Lunn 	err = mv88e6xxx_g1_irq_setup_common(chip);
341294d711eSAndrew Lunn 	if (err)
342294d711eSAndrew Lunn 		return err;
343294d711eSAndrew Lunn 
344294d711eSAndrew Lunn 	kthread_init_delayed_work(&chip->irq_poll_work,
345294d711eSAndrew Lunn 				  mv88e6xxx_irq_poll);
346294d711eSAndrew Lunn 
3473f8b8696SFlorian Fainelli 	chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev));
348294d711eSAndrew Lunn 	if (IS_ERR(chip->kworker))
349294d711eSAndrew Lunn 		return PTR_ERR(chip->kworker);
350294d711eSAndrew Lunn 
351294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
352294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
353294d711eSAndrew Lunn 
354294d711eSAndrew Lunn 	return 0;
355294d711eSAndrew Lunn }
356294d711eSAndrew Lunn 
357294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip)
358294d711eSAndrew Lunn {
359294d711eSAndrew Lunn 	kthread_cancel_delayed_work_sync(&chip->irq_poll_work);
360294d711eSAndrew Lunn 	kthread_destroy_worker(chip->kworker);
3613d82475aSUwe Kleine-König 
3623d82475aSUwe Kleine-König 	mutex_lock(&chip->reg_lock);
3633d82475aSUwe Kleine-König 	mv88e6xxx_g1_irq_free_common(chip);
3643d82475aSUwe Kleine-König 	mutex_unlock(&chip->reg_lock);
365294d711eSAndrew Lunn }
366294d711eSAndrew Lunn 
367ec561276SVivien Didelot int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask)
3682d79af6eSVivien Didelot {
3696441e669SAndrew Lunn 	int i;
3702d79af6eSVivien Didelot 
3716441e669SAndrew Lunn 	for (i = 0; i < 16; i++) {
3722d79af6eSVivien Didelot 		u16 val;
3732d79af6eSVivien Didelot 		int err;
3742d79af6eSVivien Didelot 
3752d79af6eSVivien Didelot 		err = mv88e6xxx_read(chip, addr, reg, &val);
3762d79af6eSVivien Didelot 		if (err)
3772d79af6eSVivien Didelot 			return err;
3782d79af6eSVivien Didelot 
3792d79af6eSVivien Didelot 		if (!(val & mask))
3802d79af6eSVivien Didelot 			return 0;
3812d79af6eSVivien Didelot 
3822d79af6eSVivien Didelot 		usleep_range(1000, 2000);
3832d79af6eSVivien Didelot 	}
3842d79af6eSVivien Didelot 
38530853553SAndrew Lunn 	dev_err(chip->dev, "Timeout while waiting for switch\n");
3862d79af6eSVivien Didelot 	return -ETIMEDOUT;
3872d79af6eSVivien Didelot }
3882d79af6eSVivien Didelot 
389f22ab641SVivien Didelot /* Indirect write to single pointer-data register with an Update bit */
390ec561276SVivien Didelot int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update)
391f22ab641SVivien Didelot {
392f22ab641SVivien Didelot 	u16 val;
3930f02b4f7SAndrew Lunn 	int err;
394f22ab641SVivien Didelot 
395f22ab641SVivien Didelot 	/* Wait until the previous operation is completed */
3960f02b4f7SAndrew Lunn 	err = mv88e6xxx_wait(chip, addr, reg, BIT(15));
397f22ab641SVivien Didelot 	if (err)
398f22ab641SVivien Didelot 		return err;
399f22ab641SVivien Didelot 
400f22ab641SVivien Didelot 	/* Set the Update bit to trigger a write operation */
401f22ab641SVivien Didelot 	val = BIT(15) | update;
402f22ab641SVivien Didelot 
403f22ab641SVivien Didelot 	return mv88e6xxx_write(chip, addr, reg, val);
404f22ab641SVivien Didelot }
405f22ab641SVivien Didelot 
40672d8b4fdSHeiner Kallweit int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
40772d8b4fdSHeiner Kallweit 			     int speed, int duplex, int pause,
408d78343d2SVivien Didelot 			     phy_interface_t mode)
409d78343d2SVivien Didelot {
410a26deec6SAndrew Lunn 	struct phylink_link_state state;
411d78343d2SVivien Didelot 	int err;
412d78343d2SVivien Didelot 
413d78343d2SVivien Didelot 	if (!chip->info->ops->port_set_link)
414d78343d2SVivien Didelot 		return 0;
415d78343d2SVivien Didelot 
416a26deec6SAndrew Lunn 	if (!chip->info->ops->port_link_state)
417a26deec6SAndrew Lunn 		return 0;
418a26deec6SAndrew Lunn 
419a26deec6SAndrew Lunn 	err = chip->info->ops->port_link_state(chip, port, &state);
420a26deec6SAndrew Lunn 	if (err)
421a26deec6SAndrew Lunn 		return err;
422a26deec6SAndrew Lunn 
423a26deec6SAndrew Lunn 	/* Has anything actually changed? We don't expect the
424a26deec6SAndrew Lunn 	 * interface mode to change without one of the other
425a26deec6SAndrew Lunn 	 * parameters also changing
426a26deec6SAndrew Lunn 	 */
427a26deec6SAndrew Lunn 	if (state.link == link &&
428a26deec6SAndrew Lunn 	    state.speed == speed &&
429a26deec6SAndrew Lunn 	    state.duplex == duplex)
430a26deec6SAndrew Lunn 		return 0;
431a26deec6SAndrew Lunn 
432d78343d2SVivien Didelot 	/* Port's MAC control must not be changed unless the link is down */
433d78343d2SVivien Didelot 	err = chip->info->ops->port_set_link(chip, port, 0);
434d78343d2SVivien Didelot 	if (err)
435d78343d2SVivien Didelot 		return err;
436d78343d2SVivien Didelot 
437d78343d2SVivien Didelot 	if (chip->info->ops->port_set_speed) {
438d78343d2SVivien Didelot 		err = chip->info->ops->port_set_speed(chip, port, speed);
439d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
440d78343d2SVivien Didelot 			goto restore_link;
441d78343d2SVivien Didelot 	}
442d78343d2SVivien Didelot 
4437cbbee05SAndrew Lunn 	if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode)
4447cbbee05SAndrew Lunn 		mode = chip->info->ops->port_max_speed_mode(port);
4457cbbee05SAndrew Lunn 
44654186b91SAndrew Lunn 	if (chip->info->ops->port_set_pause) {
44754186b91SAndrew Lunn 		err = chip->info->ops->port_set_pause(chip, port, pause);
44854186b91SAndrew Lunn 		if (err)
44954186b91SAndrew Lunn 			goto restore_link;
45054186b91SAndrew Lunn 	}
45154186b91SAndrew Lunn 
452d78343d2SVivien Didelot 	if (chip->info->ops->port_set_duplex) {
453d78343d2SVivien Didelot 		err = chip->info->ops->port_set_duplex(chip, port, duplex);
454d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
455d78343d2SVivien Didelot 			goto restore_link;
456d78343d2SVivien Didelot 	}
457d78343d2SVivien Didelot 
458d78343d2SVivien Didelot 	if (chip->info->ops->port_set_rgmii_delay) {
459d78343d2SVivien Didelot 		err = chip->info->ops->port_set_rgmii_delay(chip, port, mode);
460d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
461d78343d2SVivien Didelot 			goto restore_link;
462d78343d2SVivien Didelot 	}
463d78343d2SVivien Didelot 
464f39908d3SAndrew Lunn 	if (chip->info->ops->port_set_cmode) {
465f39908d3SAndrew Lunn 		err = chip->info->ops->port_set_cmode(chip, port, mode);
466f39908d3SAndrew Lunn 		if (err && err != -EOPNOTSUPP)
467f39908d3SAndrew Lunn 			goto restore_link;
468f39908d3SAndrew Lunn 	}
469f39908d3SAndrew Lunn 
470d78343d2SVivien Didelot 	err = 0;
471d78343d2SVivien Didelot restore_link:
472d78343d2SVivien Didelot 	if (chip->info->ops->port_set_link(chip, port, link))
473774439e5SVivien Didelot 		dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
474d78343d2SVivien Didelot 
475d78343d2SVivien Didelot 	return err;
476d78343d2SVivien Didelot }
477d78343d2SVivien Didelot 
478d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
479d700ec41SMarek Vasut {
480d700ec41SMarek Vasut 	struct mv88e6xxx_chip *chip = ds->priv;
481d700ec41SMarek Vasut 
482d700ec41SMarek Vasut 	return port < chip->info->num_internal_phys;
483d700ec41SMarek Vasut }
484d700ec41SMarek Vasut 
485fad09c73SVivien Didelot /* We expect the switch to perform auto negotiation if there is a real
486fad09c73SVivien Didelot  * phy. However, in the case of a fixed link phy, we force the port
487fad09c73SVivien Didelot  * settings from the fixed link settings.
488fad09c73SVivien Didelot  */
489fad09c73SVivien Didelot static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
490fad09c73SVivien Didelot 				  struct phy_device *phydev)
491fad09c73SVivien Didelot {
49204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
4930e7b9925SAndrew Lunn 	int err;
494fad09c73SVivien Didelot 
495d700ec41SMarek Vasut 	if (!phy_is_pseudo_fixed_link(phydev) &&
496d700ec41SMarek Vasut 	    mv88e6xxx_phy_is_internal(ds, port))
497fad09c73SVivien Didelot 		return;
498fad09c73SVivien Didelot 
499fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
500d78343d2SVivien Didelot 	err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
50154186b91SAndrew Lunn 				       phydev->duplex, phydev->pause,
50254186b91SAndrew Lunn 				       phydev->interface);
503fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
504d78343d2SVivien Didelot 
505d78343d2SVivien Didelot 	if (err && err != -EOPNOTSUPP)
506774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
507fad09c73SVivien Didelot }
508fad09c73SVivien Didelot 
5096c422e34SRussell King static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5106c422e34SRussell King 				       unsigned long *mask,
5116c422e34SRussell King 				       struct phylink_link_state *state)
5126c422e34SRussell King {
5136c422e34SRussell King 	if (!phy_interface_mode_is_8023z(state->interface)) {
5146c422e34SRussell King 		/* 10M and 100M are only supported in non-802.3z mode */
5156c422e34SRussell King 		phylink_set(mask, 10baseT_Half);
5166c422e34SRussell King 		phylink_set(mask, 10baseT_Full);
5176c422e34SRussell King 		phylink_set(mask, 100baseT_Half);
5186c422e34SRussell King 		phylink_set(mask, 100baseT_Full);
5196c422e34SRussell King 	}
5206c422e34SRussell King }
5216c422e34SRussell King 
5226c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5236c422e34SRussell King 				       unsigned long *mask,
5246c422e34SRussell King 				       struct phylink_link_state *state)
5256c422e34SRussell King {
5266c422e34SRussell King 	/* FIXME: if the port is in 1000Base-X mode, then it only supports
5276c422e34SRussell King 	 * 1000M FD speeds.  In this case, CMODE will indicate 5.
5286c422e34SRussell King 	 */
5296c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
5306c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
5316c422e34SRussell King 
5326c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
5336c422e34SRussell King }
5346c422e34SRussell King 
535e3af71a3SMarek Behún static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port,
536e3af71a3SMarek Behún 				       unsigned long *mask,
537e3af71a3SMarek Behún 				       struct phylink_link_state *state)
538e3af71a3SMarek Behún {
539e3af71a3SMarek Behún 	if (port >= 5)
540e3af71a3SMarek Behún 		phylink_set(mask, 2500baseX_Full);
541e3af71a3SMarek Behún 
542e3af71a3SMarek Behún 	/* No ethtool bits for 200Mbps */
543e3af71a3SMarek Behún 	phylink_set(mask, 1000baseT_Full);
544e3af71a3SMarek Behún 	phylink_set(mask, 1000baseX_Full);
545e3af71a3SMarek Behún 
546e3af71a3SMarek Behún 	mv88e6065_phylink_validate(chip, port, mask, state);
547e3af71a3SMarek Behún }
548e3af71a3SMarek Behún 
5496c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5506c422e34SRussell King 				       unsigned long *mask,
5516c422e34SRussell King 				       struct phylink_link_state *state)
5526c422e34SRussell King {
5536c422e34SRussell King 	/* No ethtool bits for 200Mbps */
5546c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
5556c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
5566c422e34SRussell King 
5576c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
5586c422e34SRussell King }
5596c422e34SRussell King 
5606c422e34SRussell King static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5616c422e34SRussell King 				       unsigned long *mask,
5626c422e34SRussell King 				       struct phylink_link_state *state)
5636c422e34SRussell King {
564ec26016bSAndrew Lunn 	if (port >= 9) {
5656c422e34SRussell King 		phylink_set(mask, 2500baseX_Full);
566ec26016bSAndrew Lunn 		phylink_set(mask, 2500baseT_Full);
567ec26016bSAndrew Lunn 	}
5686c422e34SRussell King 
5696c422e34SRussell King 	/* No ethtool bits for 200Mbps */
5706c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
5716c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
5726c422e34SRussell King 
5736c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
5746c422e34SRussell King }
5756c422e34SRussell King 
5766c422e34SRussell King static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
5776c422e34SRussell King 					unsigned long *mask,
5786c422e34SRussell King 					struct phylink_link_state *state)
5796c422e34SRussell King {
5806c422e34SRussell King 	if (port >= 9) {
5816c422e34SRussell King 		phylink_set(mask, 10000baseT_Full);
5826c422e34SRussell King 		phylink_set(mask, 10000baseKR_Full);
5836c422e34SRussell King 	}
5846c422e34SRussell King 
5856c422e34SRussell King 	mv88e6390_phylink_validate(chip, port, mask, state);
5866c422e34SRussell King }
5876c422e34SRussell King 
588c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
589c9a2356fSRussell King 			       unsigned long *supported,
590c9a2356fSRussell King 			       struct phylink_link_state *state)
591c9a2356fSRussell King {
5926c422e34SRussell King 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
5936c422e34SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
5946c422e34SRussell King 
5956c422e34SRussell King 	/* Allow all the expected bits */
5966c422e34SRussell King 	phylink_set(mask, Autoneg);
5976c422e34SRussell King 	phylink_set(mask, Pause);
5986c422e34SRussell King 	phylink_set_port_modes(mask);
5996c422e34SRussell King 
6006c422e34SRussell King 	if (chip->info->ops->phylink_validate)
6016c422e34SRussell King 		chip->info->ops->phylink_validate(chip, port, mask, state);
6026c422e34SRussell King 
6036c422e34SRussell King 	bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
6046c422e34SRussell King 	bitmap_and(state->advertising, state->advertising, mask,
6056c422e34SRussell King 		   __ETHTOOL_LINK_MODE_MASK_NBITS);
6066c422e34SRussell King 
6076c422e34SRussell King 	/* We can only operate at 2500BaseX or 1000BaseX.  If requested
6086c422e34SRussell King 	 * to advertise both, only report advertising at 2500BaseX.
6096c422e34SRussell King 	 */
6106c422e34SRussell King 	phylink_helper_basex_speed(state);
611c9a2356fSRussell King }
612c9a2356fSRussell King 
613c9a2356fSRussell King static int mv88e6xxx_link_state(struct dsa_switch *ds, int port,
614c9a2356fSRussell King 				struct phylink_link_state *state)
615c9a2356fSRussell King {
616c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
617c9a2356fSRussell King 	int err;
618c9a2356fSRussell King 
619c9a2356fSRussell King 	mutex_lock(&chip->reg_lock);
6206c422e34SRussell King 	if (chip->info->ops->port_link_state)
6216c422e34SRussell King 		err = chip->info->ops->port_link_state(chip, port, state);
6226c422e34SRussell King 	else
6236c422e34SRussell King 		err = -EOPNOTSUPP;
624c9a2356fSRussell King 	mutex_unlock(&chip->reg_lock);
625c9a2356fSRussell King 
626c9a2356fSRussell King 	return err;
627c9a2356fSRussell King }
628c9a2356fSRussell King 
629c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
630c9a2356fSRussell King 				 unsigned int mode,
631c9a2356fSRussell King 				 const struct phylink_link_state *state)
632c9a2356fSRussell King {
633c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
63454186b91SAndrew Lunn 	int speed, duplex, link, pause, err;
635c9a2356fSRussell King 
636d700ec41SMarek Vasut 	if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port))
637c9a2356fSRussell King 		return;
638c9a2356fSRussell King 
639c9a2356fSRussell King 	if (mode == MLO_AN_FIXED) {
640c9a2356fSRussell King 		link = LINK_FORCED_UP;
641c9a2356fSRussell King 		speed = state->speed;
642c9a2356fSRussell King 		duplex = state->duplex;
643d700ec41SMarek Vasut 	} else if (!mv88e6xxx_phy_is_internal(ds, port)) {
644d700ec41SMarek Vasut 		link = state->link;
645d700ec41SMarek Vasut 		speed = state->speed;
646d700ec41SMarek Vasut 		duplex = state->duplex;
647c9a2356fSRussell King 	} else {
648c9a2356fSRussell King 		speed = SPEED_UNFORCED;
649c9a2356fSRussell King 		duplex = DUPLEX_UNFORCED;
650c9a2356fSRussell King 		link = LINK_UNFORCED;
651c9a2356fSRussell King 	}
65254186b91SAndrew Lunn 	pause = !!phylink_test(state->advertising, Pause);
653c9a2356fSRussell King 
654c9a2356fSRussell King 	mutex_lock(&chip->reg_lock);
65554186b91SAndrew Lunn 	err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, pause,
656c9a2356fSRussell King 				       state->interface);
657c9a2356fSRussell King 	mutex_unlock(&chip->reg_lock);
658c9a2356fSRussell King 
659c9a2356fSRussell King 	if (err && err != -EOPNOTSUPP)
660c9a2356fSRussell King 		dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
661c9a2356fSRussell King }
662c9a2356fSRussell King 
663c9a2356fSRussell King static void mv88e6xxx_mac_link_force(struct dsa_switch *ds, int port, int link)
664c9a2356fSRussell King {
665c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
666c9a2356fSRussell King 	int err;
667c9a2356fSRussell King 
668c9a2356fSRussell King 	mutex_lock(&chip->reg_lock);
669c9a2356fSRussell King 	err = chip->info->ops->port_set_link(chip, port, link);
670c9a2356fSRussell King 	mutex_unlock(&chip->reg_lock);
671c9a2356fSRussell King 
672c9a2356fSRussell King 	if (err)
673c9a2356fSRussell King 		dev_err(chip->dev, "p%d: failed to force MAC link\n", port);
674c9a2356fSRussell King }
675c9a2356fSRussell King 
676c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
677c9a2356fSRussell King 				    unsigned int mode,
678c9a2356fSRussell King 				    phy_interface_t interface)
679c9a2356fSRussell King {
680c9a2356fSRussell King 	if (mode == MLO_AN_FIXED)
681c9a2356fSRussell King 		mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_DOWN);
682c9a2356fSRussell King }
683c9a2356fSRussell King 
684c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
685c9a2356fSRussell King 				  unsigned int mode, phy_interface_t interface,
686c9a2356fSRussell King 				  struct phy_device *phydev)
687c9a2356fSRussell King {
688c9a2356fSRussell King 	if (mode == MLO_AN_FIXED)
689c9a2356fSRussell King 		mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_UP);
690c9a2356fSRussell King }
691c9a2356fSRussell King 
692a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
693fad09c73SVivien Didelot {
694a605a0feSAndrew Lunn 	if (!chip->info->ops->stats_snapshot)
695a605a0feSAndrew Lunn 		return -EOPNOTSUPP;
696fad09c73SVivien Didelot 
697a605a0feSAndrew Lunn 	return chip->info->ops->stats_snapshot(chip, port);
698fad09c73SVivien Didelot }
699fad09c73SVivien Didelot 
700fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
701dfafe449SAndrew Lunn 	{ "in_good_octets",		8, 0x00, STATS_TYPE_BANK0, },
702dfafe449SAndrew Lunn 	{ "in_bad_octets",		4, 0x02, STATS_TYPE_BANK0, },
703dfafe449SAndrew Lunn 	{ "in_unicast",			4, 0x04, STATS_TYPE_BANK0, },
704dfafe449SAndrew Lunn 	{ "in_broadcasts",		4, 0x06, STATS_TYPE_BANK0, },
705dfafe449SAndrew Lunn 	{ "in_multicasts",		4, 0x07, STATS_TYPE_BANK0, },
706dfafe449SAndrew Lunn 	{ "in_pause",			4, 0x16, STATS_TYPE_BANK0, },
707dfafe449SAndrew Lunn 	{ "in_undersize",		4, 0x18, STATS_TYPE_BANK0, },
708dfafe449SAndrew Lunn 	{ "in_fragments",		4, 0x19, STATS_TYPE_BANK0, },
709dfafe449SAndrew Lunn 	{ "in_oversize",		4, 0x1a, STATS_TYPE_BANK0, },
710dfafe449SAndrew Lunn 	{ "in_jabber",			4, 0x1b, STATS_TYPE_BANK0, },
711dfafe449SAndrew Lunn 	{ "in_rx_error",		4, 0x1c, STATS_TYPE_BANK0, },
712dfafe449SAndrew Lunn 	{ "in_fcs_error",		4, 0x1d, STATS_TYPE_BANK0, },
713dfafe449SAndrew Lunn 	{ "out_octets",			8, 0x0e, STATS_TYPE_BANK0, },
714dfafe449SAndrew Lunn 	{ "out_unicast",		4, 0x10, STATS_TYPE_BANK0, },
715dfafe449SAndrew Lunn 	{ "out_broadcasts",		4, 0x13, STATS_TYPE_BANK0, },
716dfafe449SAndrew Lunn 	{ "out_multicasts",		4, 0x12, STATS_TYPE_BANK0, },
717dfafe449SAndrew Lunn 	{ "out_pause",			4, 0x15, STATS_TYPE_BANK0, },
718dfafe449SAndrew Lunn 	{ "excessive",			4, 0x11, STATS_TYPE_BANK0, },
719dfafe449SAndrew Lunn 	{ "collisions",			4, 0x1e, STATS_TYPE_BANK0, },
720dfafe449SAndrew Lunn 	{ "deferred",			4, 0x05, STATS_TYPE_BANK0, },
721dfafe449SAndrew Lunn 	{ "single",			4, 0x14, STATS_TYPE_BANK0, },
722dfafe449SAndrew Lunn 	{ "multiple",			4, 0x17, STATS_TYPE_BANK0, },
723dfafe449SAndrew Lunn 	{ "out_fcs_error",		4, 0x03, STATS_TYPE_BANK0, },
724dfafe449SAndrew Lunn 	{ "late",			4, 0x1f, STATS_TYPE_BANK0, },
725dfafe449SAndrew Lunn 	{ "hist_64bytes",		4, 0x08, STATS_TYPE_BANK0, },
726dfafe449SAndrew Lunn 	{ "hist_65_127bytes",		4, 0x09, STATS_TYPE_BANK0, },
727dfafe449SAndrew Lunn 	{ "hist_128_255bytes",		4, 0x0a, STATS_TYPE_BANK0, },
728dfafe449SAndrew Lunn 	{ "hist_256_511bytes",		4, 0x0b, STATS_TYPE_BANK0, },
729dfafe449SAndrew Lunn 	{ "hist_512_1023bytes",		4, 0x0c, STATS_TYPE_BANK0, },
730dfafe449SAndrew Lunn 	{ "hist_1024_max_bytes",	4, 0x0d, STATS_TYPE_BANK0, },
731dfafe449SAndrew Lunn 	{ "sw_in_discards",		4, 0x10, STATS_TYPE_PORT, },
732dfafe449SAndrew Lunn 	{ "sw_in_filtered",		2, 0x12, STATS_TYPE_PORT, },
733dfafe449SAndrew Lunn 	{ "sw_out_filtered",		2, 0x13, STATS_TYPE_PORT, },
734dfafe449SAndrew Lunn 	{ "in_discards",		4, 0x00, STATS_TYPE_BANK1, },
735dfafe449SAndrew Lunn 	{ "in_filtered",		4, 0x01, STATS_TYPE_BANK1, },
736dfafe449SAndrew Lunn 	{ "in_accepted",		4, 0x02, STATS_TYPE_BANK1, },
737dfafe449SAndrew Lunn 	{ "in_bad_accepted",		4, 0x03, STATS_TYPE_BANK1, },
738dfafe449SAndrew Lunn 	{ "in_good_avb_class_a",	4, 0x04, STATS_TYPE_BANK1, },
739dfafe449SAndrew Lunn 	{ "in_good_avb_class_b",	4, 0x05, STATS_TYPE_BANK1, },
740dfafe449SAndrew Lunn 	{ "in_bad_avb_class_a",		4, 0x06, STATS_TYPE_BANK1, },
741dfafe449SAndrew Lunn 	{ "in_bad_avb_class_b",		4, 0x07, STATS_TYPE_BANK1, },
742dfafe449SAndrew Lunn 	{ "tcam_counter_0",		4, 0x08, STATS_TYPE_BANK1, },
743dfafe449SAndrew Lunn 	{ "tcam_counter_1",		4, 0x09, STATS_TYPE_BANK1, },
744dfafe449SAndrew Lunn 	{ "tcam_counter_2",		4, 0x0a, STATS_TYPE_BANK1, },
745dfafe449SAndrew Lunn 	{ "tcam_counter_3",		4, 0x0b, STATS_TYPE_BANK1, },
746dfafe449SAndrew Lunn 	{ "in_da_unknown",		4, 0x0e, STATS_TYPE_BANK1, },
747dfafe449SAndrew Lunn 	{ "in_management",		4, 0x0f, STATS_TYPE_BANK1, },
748dfafe449SAndrew Lunn 	{ "out_queue_0",		4, 0x10, STATS_TYPE_BANK1, },
749dfafe449SAndrew Lunn 	{ "out_queue_1",		4, 0x11, STATS_TYPE_BANK1, },
750dfafe449SAndrew Lunn 	{ "out_queue_2",		4, 0x12, STATS_TYPE_BANK1, },
751dfafe449SAndrew Lunn 	{ "out_queue_3",		4, 0x13, STATS_TYPE_BANK1, },
752dfafe449SAndrew Lunn 	{ "out_queue_4",		4, 0x14, STATS_TYPE_BANK1, },
753dfafe449SAndrew Lunn 	{ "out_queue_5",		4, 0x15, STATS_TYPE_BANK1, },
754dfafe449SAndrew Lunn 	{ "out_queue_6",		4, 0x16, STATS_TYPE_BANK1, },
755dfafe449SAndrew Lunn 	{ "out_queue_7",		4, 0x17, STATS_TYPE_BANK1, },
756dfafe449SAndrew Lunn 	{ "out_cut_through",		4, 0x18, STATS_TYPE_BANK1, },
757dfafe449SAndrew Lunn 	{ "out_octets_a",		4, 0x1a, STATS_TYPE_BANK1, },
758dfafe449SAndrew Lunn 	{ "out_octets_b",		4, 0x1b, STATS_TYPE_BANK1, },
759dfafe449SAndrew Lunn 	{ "out_management",		4, 0x1f, STATS_TYPE_BANK1, },
760fad09c73SVivien Didelot };
761fad09c73SVivien Didelot 
762fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
763fad09c73SVivien Didelot 					    struct mv88e6xxx_hw_stat *s,
764e0d8b615SAndrew Lunn 					    int port, u16 bank1_select,
765e0d8b615SAndrew Lunn 					    u16 histogram)
766fad09c73SVivien Didelot {
767fad09c73SVivien Didelot 	u32 low;
768fad09c73SVivien Didelot 	u32 high = 0;
769dfafe449SAndrew Lunn 	u16 reg = 0;
7700e7b9925SAndrew Lunn 	int err;
771fad09c73SVivien Didelot 	u64 value;
772fad09c73SVivien Didelot 
773fad09c73SVivien Didelot 	switch (s->type) {
774dfafe449SAndrew Lunn 	case STATS_TYPE_PORT:
7750e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
7760e7b9925SAndrew Lunn 		if (err)
7776c3442f5SJisheng Zhang 			return U64_MAX;
778fad09c73SVivien Didelot 
7790e7b9925SAndrew Lunn 		low = reg;
780cda9f4aaSAndrew Lunn 		if (s->size == 4) {
7810e7b9925SAndrew Lunn 			err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
7820e7b9925SAndrew Lunn 			if (err)
7836c3442f5SJisheng Zhang 				return U64_MAX;
78484b3fd1fSRasmus Villemoes 			low |= ((u32)reg) << 16;
785fad09c73SVivien Didelot 		}
786fad09c73SVivien Didelot 		break;
787dfafe449SAndrew Lunn 	case STATS_TYPE_BANK1:
788e0d8b615SAndrew Lunn 		reg = bank1_select;
789dfafe449SAndrew Lunn 		/* fall through */
790dfafe449SAndrew Lunn 	case STATS_TYPE_BANK0:
791e0d8b615SAndrew Lunn 		reg |= s->reg | histogram;
7927f9ef3afSAndrew Lunn 		mv88e6xxx_g1_stats_read(chip, reg, &low);
793cda9f4aaSAndrew Lunn 		if (s->size == 8)
7947f9ef3afSAndrew Lunn 			mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
7959fc3e4dcSGustavo A. R. Silva 		break;
7969fc3e4dcSGustavo A. R. Silva 	default:
7976c3442f5SJisheng Zhang 		return U64_MAX;
798fad09c73SVivien Didelot 	}
7996e46e2d8SAndrew Lunn 	value = (((u64)high) << 32) | low;
800fad09c73SVivien Didelot 	return value;
801fad09c73SVivien Didelot }
802fad09c73SVivien Didelot 
803436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
804dfafe449SAndrew Lunn 				       uint8_t *data, int types)
805fad09c73SVivien Didelot {
806fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
807fad09c73SVivien Didelot 	int i, j;
808fad09c73SVivien Didelot 
809fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
810fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
811dfafe449SAndrew Lunn 		if (stat->type & types) {
812fad09c73SVivien Didelot 			memcpy(data + j * ETH_GSTRING_LEN, stat->string,
813fad09c73SVivien Didelot 			       ETH_GSTRING_LEN);
814fad09c73SVivien Didelot 			j++;
815fad09c73SVivien Didelot 		}
816fad09c73SVivien Didelot 	}
817436fe17dSAndrew Lunn 
818436fe17dSAndrew Lunn 	return j;
819fad09c73SVivien Didelot }
820fad09c73SVivien Didelot 
821436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
822dfafe449SAndrew Lunn 				       uint8_t *data)
823dfafe449SAndrew Lunn {
824436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
825dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_PORT);
826dfafe449SAndrew Lunn }
827dfafe449SAndrew Lunn 
8281f71836fSRasmus Villemoes static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip,
8291f71836fSRasmus Villemoes 				       uint8_t *data)
8301f71836fSRasmus Villemoes {
8311f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0);
8321f71836fSRasmus Villemoes }
8331f71836fSRasmus Villemoes 
834436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
835dfafe449SAndrew Lunn 				       uint8_t *data)
836dfafe449SAndrew Lunn {
837436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
838dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
839dfafe449SAndrew Lunn }
840dfafe449SAndrew Lunn 
84165f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = {
84265f60e45SAndrew Lunn 	"atu_member_violation",
84365f60e45SAndrew Lunn 	"atu_miss_violation",
84465f60e45SAndrew Lunn 	"atu_full_violation",
84565f60e45SAndrew Lunn 	"vtu_member_violation",
84665f60e45SAndrew Lunn 	"vtu_miss_violation",
84765f60e45SAndrew Lunn };
84865f60e45SAndrew Lunn 
84965f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data)
85065f60e45SAndrew Lunn {
85165f60e45SAndrew Lunn 	unsigned int i;
85265f60e45SAndrew Lunn 
85365f60e45SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++)
85465f60e45SAndrew Lunn 		strlcpy(data + i * ETH_GSTRING_LEN,
85565f60e45SAndrew Lunn 			mv88e6xxx_atu_vtu_stats_strings[i],
85665f60e45SAndrew Lunn 			ETH_GSTRING_LEN);
85765f60e45SAndrew Lunn }
85865f60e45SAndrew Lunn 
859dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
86089f09048SFlorian Fainelli 				  u32 stringset, uint8_t *data)
861fad09c73SVivien Didelot {
86204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
863436fe17dSAndrew Lunn 	int count = 0;
864dfafe449SAndrew Lunn 
86589f09048SFlorian Fainelli 	if (stringset != ETH_SS_STATS)
86689f09048SFlorian Fainelli 		return;
86789f09048SFlorian Fainelli 
868c6c8cd5eSAndrew Lunn 	mutex_lock(&chip->reg_lock);
869c6c8cd5eSAndrew Lunn 
870dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_strings)
871436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_strings(chip, data);
872436fe17dSAndrew Lunn 
873436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_strings) {
874436fe17dSAndrew Lunn 		data += count * ETH_GSTRING_LEN;
87565f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_strings(chip, port, data);
876436fe17dSAndrew Lunn 	}
877c6c8cd5eSAndrew Lunn 
87865f60e45SAndrew Lunn 	data += count * ETH_GSTRING_LEN;
87965f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_strings(data);
88065f60e45SAndrew Lunn 
881c6c8cd5eSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
882dfafe449SAndrew Lunn }
883dfafe449SAndrew Lunn 
884dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
885dfafe449SAndrew Lunn 					  int types)
886dfafe449SAndrew Lunn {
887fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
888fad09c73SVivien Didelot 	int i, j;
889fad09c73SVivien Didelot 
890fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
891fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
892dfafe449SAndrew Lunn 		if (stat->type & types)
893fad09c73SVivien Didelot 			j++;
894fad09c73SVivien Didelot 	}
895fad09c73SVivien Didelot 	return j;
896fad09c73SVivien Didelot }
897fad09c73SVivien Didelot 
898dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
899dfafe449SAndrew Lunn {
900dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
901dfafe449SAndrew Lunn 					      STATS_TYPE_PORT);
902dfafe449SAndrew Lunn }
903dfafe449SAndrew Lunn 
9041f71836fSRasmus Villemoes static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip)
9051f71836fSRasmus Villemoes {
9061f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0);
9071f71836fSRasmus Villemoes }
9081f71836fSRasmus Villemoes 
909dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
910dfafe449SAndrew Lunn {
911dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
912dfafe449SAndrew Lunn 					      STATS_TYPE_BANK1);
913dfafe449SAndrew Lunn }
914dfafe449SAndrew Lunn 
91589f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
916dfafe449SAndrew Lunn {
917dfafe449SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
918436fe17dSAndrew Lunn 	int serdes_count = 0;
919436fe17dSAndrew Lunn 	int count = 0;
920dfafe449SAndrew Lunn 
92189f09048SFlorian Fainelli 	if (sset != ETH_SS_STATS)
92289f09048SFlorian Fainelli 		return 0;
92389f09048SFlorian Fainelli 
924c6c8cd5eSAndrew Lunn 	mutex_lock(&chip->reg_lock);
925dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_sset_count)
926436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_sset_count(chip);
927436fe17dSAndrew Lunn 	if (count < 0)
928436fe17dSAndrew Lunn 		goto out;
929436fe17dSAndrew Lunn 
930436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_sset_count)
931436fe17dSAndrew Lunn 		serdes_count = chip->info->ops->serdes_get_sset_count(chip,
932436fe17dSAndrew Lunn 								      port);
93365f60e45SAndrew Lunn 	if (serdes_count < 0) {
934436fe17dSAndrew Lunn 		count = serdes_count;
93565f60e45SAndrew Lunn 		goto out;
93665f60e45SAndrew Lunn 	}
937436fe17dSAndrew Lunn 	count += serdes_count;
93865f60e45SAndrew Lunn 	count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings);
93965f60e45SAndrew Lunn 
940436fe17dSAndrew Lunn out:
941c6c8cd5eSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
942dfafe449SAndrew Lunn 
943436fe17dSAndrew Lunn 	return count;
944dfafe449SAndrew Lunn }
945dfafe449SAndrew Lunn 
946436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
947e0d8b615SAndrew Lunn 				     uint64_t *data, int types,
948e0d8b615SAndrew Lunn 				     u16 bank1_select, u16 histogram)
949052f947fSAndrew Lunn {
950052f947fSAndrew Lunn 	struct mv88e6xxx_hw_stat *stat;
951052f947fSAndrew Lunn 	int i, j;
952052f947fSAndrew Lunn 
953052f947fSAndrew Lunn 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
954052f947fSAndrew Lunn 		stat = &mv88e6xxx_hw_stats[i];
955052f947fSAndrew Lunn 		if (stat->type & types) {
956377cda13SAndrew Lunn 			mutex_lock(&chip->reg_lock);
957e0d8b615SAndrew Lunn 			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
958e0d8b615SAndrew Lunn 							      bank1_select,
959e0d8b615SAndrew Lunn 							      histogram);
960377cda13SAndrew Lunn 			mutex_unlock(&chip->reg_lock);
961377cda13SAndrew Lunn 
962052f947fSAndrew Lunn 			j++;
963052f947fSAndrew Lunn 		}
964052f947fSAndrew Lunn 	}
965436fe17dSAndrew Lunn 	return j;
966052f947fSAndrew Lunn }
967052f947fSAndrew Lunn 
968436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
969052f947fSAndrew Lunn 				     uint64_t *data)
970052f947fSAndrew Lunn {
971052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
972e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
97357d1ef38SVivien Didelot 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
974052f947fSAndrew Lunn }
975052f947fSAndrew Lunn 
9761f71836fSRasmus Villemoes static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
9771f71836fSRasmus Villemoes 				     uint64_t *data)
9781f71836fSRasmus Villemoes {
9791f71836fSRasmus Villemoes 	return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0,
9801f71836fSRasmus Villemoes 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
9811f71836fSRasmus Villemoes }
9821f71836fSRasmus Villemoes 
983436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
984052f947fSAndrew Lunn 				     uint64_t *data)
985052f947fSAndrew Lunn {
986052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
987e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
98857d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
98957d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
990e0d8b615SAndrew Lunn }
991e0d8b615SAndrew Lunn 
992436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
993e0d8b615SAndrew Lunn 				     uint64_t *data)
994e0d8b615SAndrew Lunn {
995e0d8b615SAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
996e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
99757d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
99857d1ef38SVivien Didelot 					 0);
999052f947fSAndrew Lunn }
1000052f947fSAndrew Lunn 
100165f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
100265f60e45SAndrew Lunn 					uint64_t *data)
100365f60e45SAndrew Lunn {
100465f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_member_violation;
100565f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_miss_violation;
100665f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_full_violation;
100765f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_member_violation;
100865f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_miss_violation;
100965f60e45SAndrew Lunn }
101065f60e45SAndrew Lunn 
1011052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
1012052f947fSAndrew Lunn 				uint64_t *data)
1013052f947fSAndrew Lunn {
1014436fe17dSAndrew Lunn 	int count = 0;
1015436fe17dSAndrew Lunn 
1016052f947fSAndrew Lunn 	if (chip->info->ops->stats_get_stats)
1017436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_stats(chip, port, data);
1018436fe17dSAndrew Lunn 
101965f60e45SAndrew Lunn 	mutex_lock(&chip->reg_lock);
1020436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_stats) {
1021436fe17dSAndrew Lunn 		data += count;
102265f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_stats(chip, port, data);
1023436fe17dSAndrew Lunn 	}
102465f60e45SAndrew Lunn 	data += count;
102565f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_stats(chip, port, data);
102665f60e45SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
1027052f947fSAndrew Lunn }
1028052f947fSAndrew Lunn 
1029fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
1030fad09c73SVivien Didelot 					uint64_t *data)
1031fad09c73SVivien Didelot {
103204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1033fad09c73SVivien Didelot 	int ret;
1034fad09c73SVivien Didelot 
1035fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1036fad09c73SVivien Didelot 
1037a605a0feSAndrew Lunn 	ret = mv88e6xxx_stats_snapshot(chip, port);
1038fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1039377cda13SAndrew Lunn 
1040377cda13SAndrew Lunn 	if (ret < 0)
1041fad09c73SVivien Didelot 		return;
1042052f947fSAndrew Lunn 
1043052f947fSAndrew Lunn 	mv88e6xxx_get_stats(chip, port, data);
1044fad09c73SVivien Didelot 
1045fad09c73SVivien Didelot }
1046fad09c73SVivien Didelot 
1047fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
1048fad09c73SVivien Didelot {
1049fad09c73SVivien Didelot 	return 32 * sizeof(u16);
1050fad09c73SVivien Didelot }
1051fad09c73SVivien Didelot 
1052fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
1053fad09c73SVivien Didelot 			       struct ethtool_regs *regs, void *_p)
1054fad09c73SVivien Didelot {
105504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
10560e7b9925SAndrew Lunn 	int err;
10570e7b9925SAndrew Lunn 	u16 reg;
1058fad09c73SVivien Didelot 	u16 *p = _p;
1059fad09c73SVivien Didelot 	int i;
1060fad09c73SVivien Didelot 
1061a5f39326SVivien Didelot 	regs->version = chip->info->prod_num;
1062fad09c73SVivien Didelot 
1063fad09c73SVivien Didelot 	memset(p, 0xff, 32 * sizeof(u16));
1064fad09c73SVivien Didelot 
1065fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1066fad09c73SVivien Didelot 
1067fad09c73SVivien Didelot 	for (i = 0; i < 32; i++) {
1068fad09c73SVivien Didelot 
10690e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, i, &reg);
10700e7b9925SAndrew Lunn 		if (!err)
10710e7b9925SAndrew Lunn 			p[i] = reg;
1072fad09c73SVivien Didelot 	}
1073fad09c73SVivien Didelot 
1074fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1075fad09c73SVivien Didelot }
1076fad09c73SVivien Didelot 
107708f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
1078fad09c73SVivien Didelot 				 struct ethtool_eee *e)
1079fad09c73SVivien Didelot {
10805480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
10815480db69SVivien Didelot 	return 0;
1082fad09c73SVivien Didelot }
1083fad09c73SVivien Didelot 
108408f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port,
108546587e4aSVivien Didelot 				 struct ethtool_eee *e)
1086fad09c73SVivien Didelot {
10875480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
10885480db69SVivien Didelot 	return 0;
1089fad09c73SVivien Didelot }
1090fad09c73SVivien Didelot 
1091e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
1092fad09c73SVivien Didelot {
1093e5887a2aSVivien Didelot 	struct dsa_switch *ds = NULL;
1094e5887a2aSVivien Didelot 	struct net_device *br;
1095e5887a2aSVivien Didelot 	u16 pvlan;
1096fad09c73SVivien Didelot 	int i;
1097fad09c73SVivien Didelot 
1098e5887a2aSVivien Didelot 	if (dev < DSA_MAX_SWITCHES)
1099e5887a2aSVivien Didelot 		ds = chip->ds->dst->ds[dev];
1100fad09c73SVivien Didelot 
1101e5887a2aSVivien Didelot 	/* Prevent frames from unknown switch or port */
1102e5887a2aSVivien Didelot 	if (!ds || port >= ds->num_ports)
1103e5887a2aSVivien Didelot 		return 0;
1104e5887a2aSVivien Didelot 
1105e5887a2aSVivien Didelot 	/* Frames from DSA links and CPU ports can egress any local port */
1106e5887a2aSVivien Didelot 	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
1107e5887a2aSVivien Didelot 		return mv88e6xxx_port_mask(chip);
1108e5887a2aSVivien Didelot 
1109e5887a2aSVivien Didelot 	br = ds->ports[port].bridge_dev;
1110e5887a2aSVivien Didelot 	pvlan = 0;
1111e5887a2aSVivien Didelot 
1112e5887a2aSVivien Didelot 	/* Frames from user ports can egress any local DSA links and CPU ports,
1113e5887a2aSVivien Didelot 	 * as well as any local member of their bridge group.
1114e5887a2aSVivien Didelot 	 */
1115e5887a2aSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
1116e5887a2aSVivien Didelot 		if (dsa_is_cpu_port(chip->ds, i) ||
1117e5887a2aSVivien Didelot 		    dsa_is_dsa_port(chip->ds, i) ||
1118c8652c83SVivien Didelot 		    (br && dsa_to_port(chip->ds, i)->bridge_dev == br))
1119e5887a2aSVivien Didelot 			pvlan |= BIT(i);
1120e5887a2aSVivien Didelot 
1121e5887a2aSVivien Didelot 	return pvlan;
1122fad09c73SVivien Didelot }
1123e5887a2aSVivien Didelot 
1124240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port)
1125e5887a2aSVivien Didelot {
1126e5887a2aSVivien Didelot 	u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port);
1127fad09c73SVivien Didelot 
1128fad09c73SVivien Didelot 	/* prevent frames from going back out of the port they came in on */
1129fad09c73SVivien Didelot 	output_ports &= ~BIT(port);
1130fad09c73SVivien Didelot 
11315a7921f4SVivien Didelot 	return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
1132fad09c73SVivien Didelot }
1133fad09c73SVivien Didelot 
1134fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
1135fad09c73SVivien Didelot 					 u8 state)
1136fad09c73SVivien Didelot {
113704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1138fad09c73SVivien Didelot 	int err;
1139fad09c73SVivien Didelot 
1140fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1141f894c29cSVivien Didelot 	err = mv88e6xxx_port_set_state(chip, port, state);
1142fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1143fad09c73SVivien Didelot 
1144fad09c73SVivien Didelot 	if (err)
1145774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to update state\n", port);
1146fad09c73SVivien Didelot }
1147fad09c73SVivien Didelot 
114893e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip)
114993e18d61SVivien Didelot {
115093e18d61SVivien Didelot 	int err;
115193e18d61SVivien Didelot 
115293e18d61SVivien Didelot 	if (chip->info->ops->ieee_pri_map) {
115393e18d61SVivien Didelot 		err = chip->info->ops->ieee_pri_map(chip);
115493e18d61SVivien Didelot 		if (err)
115593e18d61SVivien Didelot 			return err;
115693e18d61SVivien Didelot 	}
115793e18d61SVivien Didelot 
115893e18d61SVivien Didelot 	if (chip->info->ops->ip_pri_map) {
115993e18d61SVivien Didelot 		err = chip->info->ops->ip_pri_map(chip);
116093e18d61SVivien Didelot 		if (err)
116193e18d61SVivien Didelot 			return err;
116293e18d61SVivien Didelot 	}
116393e18d61SVivien Didelot 
116493e18d61SVivien Didelot 	return 0;
116593e18d61SVivien Didelot }
116693e18d61SVivien Didelot 
1167c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
1168c7f047b6SVivien Didelot {
1169c7f047b6SVivien Didelot 	int target, port;
1170c7f047b6SVivien Didelot 	int err;
1171c7f047b6SVivien Didelot 
1172c7f047b6SVivien Didelot 	if (!chip->info->global2_addr)
1173c7f047b6SVivien Didelot 		return 0;
1174c7f047b6SVivien Didelot 
1175c7f047b6SVivien Didelot 	/* Initialize the routing port to the 32 possible target devices */
1176c7f047b6SVivien Didelot 	for (target = 0; target < 32; target++) {
1177c7f047b6SVivien Didelot 		port = 0x1f;
1178c7f047b6SVivien Didelot 		if (target < DSA_MAX_SWITCHES)
1179c7f047b6SVivien Didelot 			if (chip->ds->rtable[target] != DSA_RTABLE_NONE)
1180c7f047b6SVivien Didelot 				port = chip->ds->rtable[target];
1181c7f047b6SVivien Didelot 
1182c7f047b6SVivien Didelot 		err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
1183c7f047b6SVivien Didelot 		if (err)
1184c7f047b6SVivien Didelot 			return err;
1185c7f047b6SVivien Didelot 	}
1186c7f047b6SVivien Didelot 
118702317e68SVivien Didelot 	if (chip->info->ops->set_cascade_port) {
118802317e68SVivien Didelot 		port = MV88E6XXX_CASCADE_PORT_MULTIPLE;
118902317e68SVivien Didelot 		err = chip->info->ops->set_cascade_port(chip, port);
119002317e68SVivien Didelot 		if (err)
119102317e68SVivien Didelot 			return err;
119202317e68SVivien Didelot 	}
119302317e68SVivien Didelot 
119423c98919SVivien Didelot 	err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index);
119523c98919SVivien Didelot 	if (err)
119623c98919SVivien Didelot 		return err;
119723c98919SVivien Didelot 
1198c7f047b6SVivien Didelot 	return 0;
1199c7f047b6SVivien Didelot }
1200c7f047b6SVivien Didelot 
1201b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip)
1202b28f872dSVivien Didelot {
1203b28f872dSVivien Didelot 	/* Clear all trunk masks and mapping */
1204b28f872dSVivien Didelot 	if (chip->info->global2_addr)
1205b28f872dSVivien Didelot 		return mv88e6xxx_g2_trunk_clear(chip);
1206b28f872dSVivien Didelot 
1207b28f872dSVivien Didelot 	return 0;
1208b28f872dSVivien Didelot }
1209b28f872dSVivien Didelot 
12109e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
12119e5baf9bSVivien Didelot {
12129e5baf9bSVivien Didelot 	if (chip->info->ops->rmu_disable)
12139e5baf9bSVivien Didelot 		return chip->info->ops->rmu_disable(chip);
12149e5baf9bSVivien Didelot 
12159e5baf9bSVivien Didelot 	return 0;
12169e5baf9bSVivien Didelot }
12179e5baf9bSVivien Didelot 
12189e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
12199e907d73SVivien Didelot {
12209e907d73SVivien Didelot 	if (chip->info->ops->pot_clear)
12219e907d73SVivien Didelot 		return chip->info->ops->pot_clear(chip);
12229e907d73SVivien Didelot 
12239e907d73SVivien Didelot 	return 0;
12249e907d73SVivien Didelot }
12259e907d73SVivien Didelot 
122651c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip)
122751c901a7SVivien Didelot {
122851c901a7SVivien Didelot 	if (chip->info->ops->mgmt_rsvd2cpu)
122951c901a7SVivien Didelot 		return chip->info->ops->mgmt_rsvd2cpu(chip);
123051c901a7SVivien Didelot 
123151c901a7SVivien Didelot 	return 0;
123251c901a7SVivien Didelot }
123351c901a7SVivien Didelot 
1234a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
1235a2ac29d2SVivien Didelot {
1236c3a7d4adSVivien Didelot 	int err;
1237c3a7d4adSVivien Didelot 
1238daefc943SVivien Didelot 	err = mv88e6xxx_g1_atu_flush(chip, 0, true);
1239daefc943SVivien Didelot 	if (err)
1240daefc943SVivien Didelot 		return err;
1241daefc943SVivien Didelot 
1242c3a7d4adSVivien Didelot 	err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
1243c3a7d4adSVivien Didelot 	if (err)
1244c3a7d4adSVivien Didelot 		return err;
1245c3a7d4adSVivien Didelot 
1246a2ac29d2SVivien Didelot 	return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
1247a2ac29d2SVivien Didelot }
1248a2ac29d2SVivien Didelot 
1249cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip)
1250cd8da8bbSVivien Didelot {
1251cd8da8bbSVivien Didelot 	int port;
1252cd8da8bbSVivien Didelot 	int err;
1253cd8da8bbSVivien Didelot 
1254cd8da8bbSVivien Didelot 	if (!chip->info->ops->irl_init_all)
1255cd8da8bbSVivien Didelot 		return 0;
1256cd8da8bbSVivien Didelot 
1257cd8da8bbSVivien Didelot 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
1258cd8da8bbSVivien Didelot 		/* Disable ingress rate limiting by resetting all per port
1259cd8da8bbSVivien Didelot 		 * ingress rate limit resources to their initial state.
1260cd8da8bbSVivien Didelot 		 */
1261cd8da8bbSVivien Didelot 		err = chip->info->ops->irl_init_all(chip, port);
1262cd8da8bbSVivien Didelot 		if (err)
1263cd8da8bbSVivien Didelot 			return err;
1264cd8da8bbSVivien Didelot 	}
1265cd8da8bbSVivien Didelot 
1266cd8da8bbSVivien Didelot 	return 0;
1267cd8da8bbSVivien Didelot }
1268cd8da8bbSVivien Didelot 
126904a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip)
127004a69a17SVivien Didelot {
127104a69a17SVivien Didelot 	if (chip->info->ops->set_switch_mac) {
127204a69a17SVivien Didelot 		u8 addr[ETH_ALEN];
127304a69a17SVivien Didelot 
127404a69a17SVivien Didelot 		eth_random_addr(addr);
127504a69a17SVivien Didelot 
127604a69a17SVivien Didelot 		return chip->info->ops->set_switch_mac(chip, addr);
127704a69a17SVivien Didelot 	}
127804a69a17SVivien Didelot 
127904a69a17SVivien Didelot 	return 0;
128004a69a17SVivien Didelot }
128104a69a17SVivien Didelot 
128217a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
128317a1594eSVivien Didelot {
128417a1594eSVivien Didelot 	u16 pvlan = 0;
128517a1594eSVivien Didelot 
128617a1594eSVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
128717a1594eSVivien Didelot 		return -EOPNOTSUPP;
128817a1594eSVivien Didelot 
128917a1594eSVivien Didelot 	/* Skip the local source device, which uses in-chip port VLAN */
129017a1594eSVivien Didelot 	if (dev != chip->ds->index)
1291aec5ac88SVivien Didelot 		pvlan = mv88e6xxx_port_vlan(chip, dev, port);
129217a1594eSVivien Didelot 
129317a1594eSVivien Didelot 	return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
129417a1594eSVivien Didelot }
129517a1594eSVivien Didelot 
129681228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
129781228996SVivien Didelot {
129817a1594eSVivien Didelot 	int dev, port;
129917a1594eSVivien Didelot 	int err;
130017a1594eSVivien Didelot 
130181228996SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
130281228996SVivien Didelot 		return 0;
130381228996SVivien Didelot 
130481228996SVivien Didelot 	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
130581228996SVivien Didelot 	 * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
130681228996SVivien Didelot 	 */
130717a1594eSVivien Didelot 	err = mv88e6xxx_g2_misc_4_bit_port(chip);
130817a1594eSVivien Didelot 	if (err)
130917a1594eSVivien Didelot 		return err;
131017a1594eSVivien Didelot 
131117a1594eSVivien Didelot 	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) {
131217a1594eSVivien Didelot 		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) {
131317a1594eSVivien Didelot 			err = mv88e6xxx_pvt_map(chip, dev, port);
131417a1594eSVivien Didelot 			if (err)
131517a1594eSVivien Didelot 				return err;
131617a1594eSVivien Didelot 		}
131717a1594eSVivien Didelot 	}
131817a1594eSVivien Didelot 
131917a1594eSVivien Didelot 	return 0;
132081228996SVivien Didelot }
132181228996SVivien Didelot 
1322749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
1323749efcb8SVivien Didelot {
1324749efcb8SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1325749efcb8SVivien Didelot 	int err;
1326749efcb8SVivien Didelot 
1327749efcb8SVivien Didelot 	mutex_lock(&chip->reg_lock);
1328e606ca36SVivien Didelot 	err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
1329749efcb8SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1330749efcb8SVivien Didelot 
1331749efcb8SVivien Didelot 	if (err)
1332774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to flush ATU\n", port);
1333749efcb8SVivien Didelot }
1334749efcb8SVivien Didelot 
1335b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)
1336b486d7c9SVivien Didelot {
1337b486d7c9SVivien Didelot 	if (!chip->info->max_vid)
1338b486d7c9SVivien Didelot 		return 0;
1339b486d7c9SVivien Didelot 
1340b486d7c9SVivien Didelot 	return mv88e6xxx_g1_vtu_flush(chip);
1341b486d7c9SVivien Didelot }
1342b486d7c9SVivien Didelot 
1343f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,
1344f1394b78SVivien Didelot 				 struct mv88e6xxx_vtu_entry *entry)
1345f1394b78SVivien Didelot {
1346f1394b78SVivien Didelot 	if (!chip->info->ops->vtu_getnext)
1347f1394b78SVivien Didelot 		return -EOPNOTSUPP;
1348f1394b78SVivien Didelot 
1349f1394b78SVivien Didelot 	return chip->info->ops->vtu_getnext(chip, entry);
1350f1394b78SVivien Didelot }
1351f1394b78SVivien Didelot 
13520ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
13530ad5daf6SVivien Didelot 				   struct mv88e6xxx_vtu_entry *entry)
13540ad5daf6SVivien Didelot {
13550ad5daf6SVivien Didelot 	if (!chip->info->ops->vtu_loadpurge)
13560ad5daf6SVivien Didelot 		return -EOPNOTSUPP;
13570ad5daf6SVivien Didelot 
13580ad5daf6SVivien Didelot 	return chip->info->ops->vtu_loadpurge(chip, entry);
13590ad5daf6SVivien Didelot }
13600ad5daf6SVivien Didelot 
1361d7f435f9SVivien Didelot static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
1362fad09c73SVivien Didelot {
1363fad09c73SVivien Didelot 	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
13643afb4bdeSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan = {
13653afb4bdeSVivien Didelot 		.vid = chip->info->max_vid,
13663afb4bdeSVivien Didelot 	};
1367fad09c73SVivien Didelot 	int i, err;
1368fad09c73SVivien Didelot 
1369fad09c73SVivien Didelot 	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
1370fad09c73SVivien Didelot 
1371fad09c73SVivien Didelot 	/* Set every FID bit used by the (un)bridged ports */
1372370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1373b4e48c50SVivien Didelot 		err = mv88e6xxx_port_get_fid(chip, i, fid);
1374fad09c73SVivien Didelot 		if (err)
1375fad09c73SVivien Didelot 			return err;
1376fad09c73SVivien Didelot 
1377fad09c73SVivien Didelot 		set_bit(*fid, fid_bitmap);
1378fad09c73SVivien Didelot 	}
1379fad09c73SVivien Didelot 
1380fad09c73SVivien Didelot 	/* Set every FID bit used by the VLAN entries */
1381fad09c73SVivien Didelot 	do {
1382f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1383fad09c73SVivien Didelot 		if (err)
1384fad09c73SVivien Didelot 			return err;
1385fad09c73SVivien Didelot 
1386fad09c73SVivien Didelot 		if (!vlan.valid)
1387fad09c73SVivien Didelot 			break;
1388fad09c73SVivien Didelot 
1389fad09c73SVivien Didelot 		set_bit(vlan.fid, fid_bitmap);
13903cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
1391fad09c73SVivien Didelot 
1392fad09c73SVivien Didelot 	/* The reset value 0x000 is used to indicate that multiple address
1393fad09c73SVivien Didelot 	 * databases are not needed. Return the next positive available.
1394fad09c73SVivien Didelot 	 */
1395fad09c73SVivien Didelot 	*fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1);
1396fad09c73SVivien Didelot 	if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
1397fad09c73SVivien Didelot 		return -ENOSPC;
1398fad09c73SVivien Didelot 
1399fad09c73SVivien Didelot 	/* Clear the database */
1400daefc943SVivien Didelot 	return mv88e6xxx_g1_atu_flush(chip, *fid, true);
1401fad09c73SVivien Didelot }
1402fad09c73SVivien Didelot 
1403567aa59aSVivien Didelot static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
1404567aa59aSVivien Didelot 			     struct mv88e6xxx_vtu_entry *entry, bool new)
1405fad09c73SVivien Didelot {
1406fad09c73SVivien Didelot 	int err;
1407fad09c73SVivien Didelot 
1408fad09c73SVivien Didelot 	if (!vid)
140962394708SNikita Yushchenko 		return -EOPNOTSUPP;
1410fad09c73SVivien Didelot 
14113afb4bdeSVivien Didelot 	entry->vid = vid - 1;
14123afb4bdeSVivien Didelot 	entry->valid = false;
1413fad09c73SVivien Didelot 
1414f1394b78SVivien Didelot 	err = mv88e6xxx_vtu_getnext(chip, entry);
1415fad09c73SVivien Didelot 	if (err)
1416fad09c73SVivien Didelot 		return err;
1417fad09c73SVivien Didelot 
1418567aa59aSVivien Didelot 	if (entry->vid == vid && entry->valid)
1419567aa59aSVivien Didelot 		return 0;
1420fad09c73SVivien Didelot 
1421567aa59aSVivien Didelot 	if (new) {
1422567aa59aSVivien Didelot 		int i;
1423567aa59aSVivien Didelot 
1424567aa59aSVivien Didelot 		/* Initialize a fresh VLAN entry */
1425567aa59aSVivien Didelot 		memset(entry, 0, sizeof(*entry));
1426567aa59aSVivien Didelot 		entry->valid = true;
1427567aa59aSVivien Didelot 		entry->vid = vid;
1428567aa59aSVivien Didelot 
1429553a768dSVivien Didelot 		/* Exclude all ports */
1430567aa59aSVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
1431553a768dSVivien Didelot 			entry->member[i] =
14327ec60d6eSVivien Didelot 				MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1433567aa59aSVivien Didelot 
1434567aa59aSVivien Didelot 		return mv88e6xxx_atu_new(chip, &entry->fid);
1435fad09c73SVivien Didelot 	}
1436fad09c73SVivien Didelot 
1437567aa59aSVivien Didelot 	/* switchdev expects -EOPNOTSUPP to honor software VLANs */
1438567aa59aSVivien Didelot 	return -EOPNOTSUPP;
1439fad09c73SVivien Didelot }
1440fad09c73SVivien Didelot 
1441fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
1442fad09c73SVivien Didelot 					u16 vid_begin, u16 vid_end)
1443fad09c73SVivien Didelot {
144404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
14453afb4bdeSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan = {
14463afb4bdeSVivien Didelot 		.vid = vid_begin - 1,
14473afb4bdeSVivien Didelot 	};
1448fad09c73SVivien Didelot 	int i, err;
1449fad09c73SVivien Didelot 
1450db06ae41SAndrew Lunn 	/* DSA and CPU ports have to be members of multiple vlans */
1451db06ae41SAndrew Lunn 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
1452db06ae41SAndrew Lunn 		return 0;
1453db06ae41SAndrew Lunn 
1454fad09c73SVivien Didelot 	if (!vid_begin)
1455fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1456fad09c73SVivien Didelot 
1457fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1458fad09c73SVivien Didelot 
1459fad09c73SVivien Didelot 	do {
1460f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1461fad09c73SVivien Didelot 		if (err)
1462fad09c73SVivien Didelot 			goto unlock;
1463fad09c73SVivien Didelot 
1464fad09c73SVivien Didelot 		if (!vlan.valid)
1465fad09c73SVivien Didelot 			break;
1466fad09c73SVivien Didelot 
1467fad09c73SVivien Didelot 		if (vlan.vid > vid_end)
1468fad09c73SVivien Didelot 			break;
1469fad09c73SVivien Didelot 
1470370b4ffbSVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1471fad09c73SVivien Didelot 			if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
1472fad09c73SVivien Didelot 				continue;
1473fad09c73SVivien Didelot 
1474cd886469SAndrew Lunn 			if (!ds->ports[i].slave)
147566e2809dSAndrew Lunn 				continue;
147666e2809dSAndrew Lunn 
1477bd00e053SVivien Didelot 			if (vlan.member[i] ==
14787ec60d6eSVivien Didelot 			    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1479fad09c73SVivien Didelot 				continue;
1480fad09c73SVivien Didelot 
1481c8652c83SVivien Didelot 			if (dsa_to_port(ds, i)->bridge_dev ==
1482fae8a25eSVivien Didelot 			    ds->ports[port].bridge_dev)
1483fad09c73SVivien Didelot 				break; /* same bridge, check next VLAN */
1484fad09c73SVivien Didelot 
1485c8652c83SVivien Didelot 			if (!dsa_to_port(ds, i)->bridge_dev)
148666e2809dSAndrew Lunn 				continue;
148766e2809dSAndrew Lunn 
1488743fcc28SAndrew Lunn 			dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
1489743fcc28SAndrew Lunn 				port, vlan.vid, i,
1490c8652c83SVivien Didelot 				netdev_name(dsa_to_port(ds, i)->bridge_dev));
1491fad09c73SVivien Didelot 			err = -EOPNOTSUPP;
1492fad09c73SVivien Didelot 			goto unlock;
1493fad09c73SVivien Didelot 		}
1494fad09c73SVivien Didelot 	} while (vlan.vid < vid_end);
1495fad09c73SVivien Didelot 
1496fad09c73SVivien Didelot unlock:
1497fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1498fad09c73SVivien Didelot 
1499fad09c73SVivien Didelot 	return err;
1500fad09c73SVivien Didelot }
1501fad09c73SVivien Didelot 
1502fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
1503fad09c73SVivien Didelot 					 bool vlan_filtering)
1504fad09c73SVivien Didelot {
150504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
150681c6edb2SVivien Didelot 	u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
150781c6edb2SVivien Didelot 		MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
15080e7b9925SAndrew Lunn 	int err;
1509fad09c73SVivien Didelot 
15103cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1511fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1512fad09c73SVivien Didelot 
1513fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1514385a0995SVivien Didelot 	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
1515fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1516fad09c73SVivien Didelot 
15170e7b9925SAndrew Lunn 	return err;
1518fad09c73SVivien Didelot }
1519fad09c73SVivien Didelot 
1520fad09c73SVivien Didelot static int
1521fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
152280e02360SVivien Didelot 			    const struct switchdev_obj_port_vlan *vlan)
1523fad09c73SVivien Didelot {
152404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1525fad09c73SVivien Didelot 	int err;
1526fad09c73SVivien Didelot 
15273cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1528fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1529fad09c73SVivien Didelot 
1530fad09c73SVivien Didelot 	/* If the requested port doesn't belong to the same bridge as the VLAN
1531fad09c73SVivien Didelot 	 * members, do not support it (yet) and fallback to software VLAN.
1532fad09c73SVivien Didelot 	 */
1533fad09c73SVivien Didelot 	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
1534fad09c73SVivien Didelot 					   vlan->vid_end);
1535fad09c73SVivien Didelot 	if (err)
1536fad09c73SVivien Didelot 		return err;
1537fad09c73SVivien Didelot 
1538fad09c73SVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
1539fad09c73SVivien Didelot 	 * so skip the prepare phase.
1540fad09c73SVivien Didelot 	 */
1541fad09c73SVivien Didelot 	return 0;
1542fad09c73SVivien Didelot }
1543fad09c73SVivien Didelot 
1544a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
1545a4c93ae1SAndrew Lunn 					const unsigned char *addr, u16 vid,
1546a4c93ae1SAndrew Lunn 					u8 state)
1547a4c93ae1SAndrew Lunn {
1548a4c93ae1SAndrew Lunn 	struct mv88e6xxx_vtu_entry vlan;
1549a4c93ae1SAndrew Lunn 	struct mv88e6xxx_atu_entry entry;
1550a4c93ae1SAndrew Lunn 	int err;
1551a4c93ae1SAndrew Lunn 
1552a4c93ae1SAndrew Lunn 	/* Null VLAN ID corresponds to the port private database */
1553a4c93ae1SAndrew Lunn 	if (vid == 0)
1554a4c93ae1SAndrew Lunn 		err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
1555a4c93ae1SAndrew Lunn 	else
1556a4c93ae1SAndrew Lunn 		err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
1557a4c93ae1SAndrew Lunn 	if (err)
1558a4c93ae1SAndrew Lunn 		return err;
1559a4c93ae1SAndrew Lunn 
1560a4c93ae1SAndrew Lunn 	entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1561a4c93ae1SAndrew Lunn 	ether_addr_copy(entry.mac, addr);
1562a4c93ae1SAndrew Lunn 	eth_addr_dec(entry.mac);
1563a4c93ae1SAndrew Lunn 
1564a4c93ae1SAndrew Lunn 	err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry);
1565a4c93ae1SAndrew Lunn 	if (err)
1566a4c93ae1SAndrew Lunn 		return err;
1567a4c93ae1SAndrew Lunn 
1568a4c93ae1SAndrew Lunn 	/* Initialize a fresh ATU entry if it isn't found */
1569a4c93ae1SAndrew Lunn 	if (entry.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED ||
1570a4c93ae1SAndrew Lunn 	    !ether_addr_equal(entry.mac, addr)) {
1571a4c93ae1SAndrew Lunn 		memset(&entry, 0, sizeof(entry));
1572a4c93ae1SAndrew Lunn 		ether_addr_copy(entry.mac, addr);
1573a4c93ae1SAndrew Lunn 	}
1574a4c93ae1SAndrew Lunn 
1575a4c93ae1SAndrew Lunn 	/* Purge the ATU entry only if no port is using it anymore */
1576a4c93ae1SAndrew Lunn 	if (state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
1577a4c93ae1SAndrew Lunn 		entry.portvec &= ~BIT(port);
1578a4c93ae1SAndrew Lunn 		if (!entry.portvec)
1579a4c93ae1SAndrew Lunn 			entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1580a4c93ae1SAndrew Lunn 	} else {
1581a4c93ae1SAndrew Lunn 		entry.portvec |= BIT(port);
1582a4c93ae1SAndrew Lunn 		entry.state = state;
1583a4c93ae1SAndrew Lunn 	}
1584a4c93ae1SAndrew Lunn 
1585a4c93ae1SAndrew Lunn 	return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry);
1586a4c93ae1SAndrew Lunn }
1587a4c93ae1SAndrew Lunn 
158887fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
158987fa886eSAndrew Lunn 					u16 vid)
159087fa886eSAndrew Lunn {
159187fa886eSAndrew Lunn 	const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
159287fa886eSAndrew Lunn 	u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
159387fa886eSAndrew Lunn 
159487fa886eSAndrew Lunn 	return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
159587fa886eSAndrew Lunn }
159687fa886eSAndrew Lunn 
159787fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
159887fa886eSAndrew Lunn {
159987fa886eSAndrew Lunn 	int port;
160087fa886eSAndrew Lunn 	int err;
160187fa886eSAndrew Lunn 
160287fa886eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
160387fa886eSAndrew Lunn 		err = mv88e6xxx_port_add_broadcast(chip, port, vid);
160487fa886eSAndrew Lunn 		if (err)
160587fa886eSAndrew Lunn 			return err;
160687fa886eSAndrew Lunn 	}
160787fa886eSAndrew Lunn 
160887fa886eSAndrew Lunn 	return 0;
160987fa886eSAndrew Lunn }
161087fa886eSAndrew Lunn 
1611fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
1612c91498e1SVivien Didelot 				    u16 vid, u8 member)
1613fad09c73SVivien Didelot {
1614b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1615fad09c73SVivien Didelot 	int err;
1616fad09c73SVivien Didelot 
1617567aa59aSVivien Didelot 	err = mv88e6xxx_vtu_get(chip, vid, &vlan, true);
1618fad09c73SVivien Didelot 	if (err)
1619fad09c73SVivien Didelot 		return err;
1620fad09c73SVivien Didelot 
1621c91498e1SVivien Didelot 	vlan.member[port] = member;
1622fad09c73SVivien Didelot 
162387fa886eSAndrew Lunn 	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
162487fa886eSAndrew Lunn 	if (err)
162587fa886eSAndrew Lunn 		return err;
162687fa886eSAndrew Lunn 
162787fa886eSAndrew Lunn 	return mv88e6xxx_broadcast_setup(chip, vid);
1628fad09c73SVivien Didelot }
1629fad09c73SVivien Didelot 
1630fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
163180e02360SVivien Didelot 				    const struct switchdev_obj_port_vlan *vlan)
1632fad09c73SVivien Didelot {
163304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1634fad09c73SVivien Didelot 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1635fad09c73SVivien Didelot 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1636c91498e1SVivien Didelot 	u8 member;
1637fad09c73SVivien Didelot 	u16 vid;
1638fad09c73SVivien Didelot 
16393cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1640fad09c73SVivien Didelot 		return;
1641fad09c73SVivien Didelot 
1642c91498e1SVivien Didelot 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
16437ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED;
1644c91498e1SVivien Didelot 	else if (untagged)
16457ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED;
1646c91498e1SVivien Didelot 	else
16477ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
1648c91498e1SVivien Didelot 
1649fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1650fad09c73SVivien Didelot 
1651fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
1652c91498e1SVivien Didelot 		if (_mv88e6xxx_port_vlan_add(chip, port, vid, member))
1653774439e5SVivien Didelot 			dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
1654fad09c73SVivien Didelot 				vid, untagged ? 'u' : 't');
1655fad09c73SVivien Didelot 
165677064f37SVivien Didelot 	if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end))
1657774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to set PVID %d\n", port,
1658fad09c73SVivien Didelot 			vlan->vid_end);
1659fad09c73SVivien Didelot 
1660fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1661fad09c73SVivien Didelot }
1662fad09c73SVivien Didelot 
1663fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
1664fad09c73SVivien Didelot 				    int port, u16 vid)
1665fad09c73SVivien Didelot {
1666b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1667fad09c73SVivien Didelot 	int i, err;
1668fad09c73SVivien Didelot 
1669567aa59aSVivien Didelot 	err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
1670fad09c73SVivien Didelot 	if (err)
1671fad09c73SVivien Didelot 		return err;
1672fad09c73SVivien Didelot 
1673fad09c73SVivien Didelot 	/* Tell switchdev if this VLAN is handled in software */
16747ec60d6eSVivien Didelot 	if (vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1675fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1676fad09c73SVivien Didelot 
16777ec60d6eSVivien Didelot 	vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1678fad09c73SVivien Didelot 
1679fad09c73SVivien Didelot 	/* keep the VLAN unless all ports are excluded */
1680fad09c73SVivien Didelot 	vlan.valid = false;
1681370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
16827ec60d6eSVivien Didelot 		if (vlan.member[i] !=
16837ec60d6eSVivien Didelot 		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
1684fad09c73SVivien Didelot 			vlan.valid = true;
1685fad09c73SVivien Didelot 			break;
1686fad09c73SVivien Didelot 		}
1687fad09c73SVivien Didelot 	}
1688fad09c73SVivien Didelot 
16890ad5daf6SVivien Didelot 	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
1690fad09c73SVivien Didelot 	if (err)
1691fad09c73SVivien Didelot 		return err;
1692fad09c73SVivien Didelot 
1693e606ca36SVivien Didelot 	return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
1694fad09c73SVivien Didelot }
1695fad09c73SVivien Didelot 
1696fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
1697fad09c73SVivien Didelot 				   const struct switchdev_obj_port_vlan *vlan)
1698fad09c73SVivien Didelot {
169904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1700fad09c73SVivien Didelot 	u16 pvid, vid;
1701fad09c73SVivien Didelot 	int err = 0;
1702fad09c73SVivien Didelot 
17033cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1704fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1705fad09c73SVivien Didelot 
1706fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1707fad09c73SVivien Didelot 
170877064f37SVivien Didelot 	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
1709fad09c73SVivien Didelot 	if (err)
1710fad09c73SVivien Didelot 		goto unlock;
1711fad09c73SVivien Didelot 
1712fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1713fad09c73SVivien Didelot 		err = _mv88e6xxx_port_vlan_del(chip, port, vid);
1714fad09c73SVivien Didelot 		if (err)
1715fad09c73SVivien Didelot 			goto unlock;
1716fad09c73SVivien Didelot 
1717fad09c73SVivien Didelot 		if (vid == pvid) {
171877064f37SVivien Didelot 			err = mv88e6xxx_port_set_pvid(chip, port, 0);
1719fad09c73SVivien Didelot 			if (err)
1720fad09c73SVivien Didelot 				goto unlock;
1721fad09c73SVivien Didelot 		}
1722fad09c73SVivien Didelot 	}
1723fad09c73SVivien Didelot 
1724fad09c73SVivien Didelot unlock:
1725fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1726fad09c73SVivien Didelot 
1727fad09c73SVivien Didelot 	return err;
1728fad09c73SVivien Didelot }
1729fad09c73SVivien Didelot 
17301b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
17316c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
1732fad09c73SVivien Didelot {
173304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
17341b6dd556SArkadi Sharshevsky 	int err;
1735fad09c73SVivien Didelot 
1736fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
17371b6dd556SArkadi Sharshevsky 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
17381b6dd556SArkadi Sharshevsky 					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
1739fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
17401b6dd556SArkadi Sharshevsky 
17411b6dd556SArkadi Sharshevsky 	return err;
1742fad09c73SVivien Didelot }
1743fad09c73SVivien Didelot 
1744fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
17456c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
1746fad09c73SVivien Didelot {
174704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
174883dabd1fSVivien Didelot 	int err;
1749fad09c73SVivien Didelot 
1750fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
17516c2c1dcbSArkadi Sharshevsky 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
175227c0e600SVivien Didelot 					   MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
1753fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1754fad09c73SVivien Didelot 
175583dabd1fSVivien Didelot 	return err;
1756fad09c73SVivien Didelot }
1757fad09c73SVivien Didelot 
175883dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
1759fad09c73SVivien Didelot 				      u16 fid, u16 vid, int port,
17602bedde1aSArkadi Sharshevsky 				      dsa_fdb_dump_cb_t *cb, void *data)
1761fad09c73SVivien Didelot {
1762dabc1a96SVivien Didelot 	struct mv88e6xxx_atu_entry addr;
17632bedde1aSArkadi Sharshevsky 	bool is_static;
1764fad09c73SVivien Didelot 	int err;
1765fad09c73SVivien Didelot 
176627c0e600SVivien Didelot 	addr.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1767dabc1a96SVivien Didelot 	eth_broadcast_addr(addr.mac);
1768fad09c73SVivien Didelot 
1769fad09c73SVivien Didelot 	do {
1770dabc1a96SVivien Didelot 		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
1771fad09c73SVivien Didelot 		if (err)
177283dabd1fSVivien Didelot 			return err;
1773fad09c73SVivien Didelot 
177427c0e600SVivien Didelot 		if (addr.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED)
1775fad09c73SVivien Didelot 			break;
1776fad09c73SVivien Didelot 
177701bd96c8SVivien Didelot 		if (addr.trunk || (addr.portvec & BIT(port)) == 0)
177883dabd1fSVivien Didelot 			continue;
1779fad09c73SVivien Didelot 
178083dabd1fSVivien Didelot 		if (!is_unicast_ether_addr(addr.mac))
178183dabd1fSVivien Didelot 			continue;
178283dabd1fSVivien Didelot 
17832bedde1aSArkadi Sharshevsky 		is_static = (addr.state ==
17842bedde1aSArkadi Sharshevsky 			     MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
17852bedde1aSArkadi Sharshevsky 		err = cb(addr.mac, vid, is_static, data);
178683dabd1fSVivien Didelot 		if (err)
178783dabd1fSVivien Didelot 			return err;
1788fad09c73SVivien Didelot 	} while (!is_broadcast_ether_addr(addr.mac));
1789fad09c73SVivien Didelot 
1790fad09c73SVivien Didelot 	return err;
1791fad09c73SVivien Didelot }
1792fad09c73SVivien Didelot 
179383dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
17942bedde1aSArkadi Sharshevsky 				  dsa_fdb_dump_cb_t *cb, void *data)
179583dabd1fSVivien Didelot {
1796b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan = {
17973cf3c846SVivien Didelot 		.vid = chip->info->max_vid,
179883dabd1fSVivien Didelot 	};
179983dabd1fSVivien Didelot 	u16 fid;
180083dabd1fSVivien Didelot 	int err;
180183dabd1fSVivien Didelot 
180283dabd1fSVivien Didelot 	/* Dump port's default Filtering Information Database (VLAN ID 0) */
1803b4e48c50SVivien Didelot 	err = mv88e6xxx_port_get_fid(chip, port, &fid);
180483dabd1fSVivien Didelot 	if (err)
180583dabd1fSVivien Didelot 		return err;
180683dabd1fSVivien Didelot 
18072bedde1aSArkadi Sharshevsky 	err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data);
180883dabd1fSVivien Didelot 	if (err)
180983dabd1fSVivien Didelot 		return err;
181083dabd1fSVivien Didelot 
181183dabd1fSVivien Didelot 	/* Dump VLANs' Filtering Information Databases */
181283dabd1fSVivien Didelot 	do {
1813f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
181483dabd1fSVivien Didelot 		if (err)
181583dabd1fSVivien Didelot 			return err;
181683dabd1fSVivien Didelot 
181783dabd1fSVivien Didelot 		if (!vlan.valid)
181883dabd1fSVivien Didelot 			break;
181983dabd1fSVivien Didelot 
182083dabd1fSVivien Didelot 		err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port,
18212bedde1aSArkadi Sharshevsky 						 cb, data);
182283dabd1fSVivien Didelot 		if (err)
182383dabd1fSVivien Didelot 			return err;
18243cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
182583dabd1fSVivien Didelot 
182683dabd1fSVivien Didelot 	return err;
182783dabd1fSVivien Didelot }
182883dabd1fSVivien Didelot 
1829fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
18302bedde1aSArkadi Sharshevsky 				   dsa_fdb_dump_cb_t *cb, void *data)
1831fad09c73SVivien Didelot {
183204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1833fcf15367SVivien Didelot 	int err;
1834fad09c73SVivien Didelot 
1835fcf15367SVivien Didelot 	mutex_lock(&chip->reg_lock);
1836fcf15367SVivien Didelot 	err = mv88e6xxx_port_db_dump(chip, port, cb, data);
1837fcf15367SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1838fcf15367SVivien Didelot 
1839fcf15367SVivien Didelot 	return err;
1840fad09c73SVivien Didelot }
1841fad09c73SVivien Didelot 
1842240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
1843240ea3efSVivien Didelot 				struct net_device *br)
1844240ea3efSVivien Didelot {
1845e96a6e02SVivien Didelot 	struct dsa_switch *ds;
1846240ea3efSVivien Didelot 	int port;
1847e96a6e02SVivien Didelot 	int dev;
1848240ea3efSVivien Didelot 	int err;
1849240ea3efSVivien Didelot 
1850240ea3efSVivien Didelot 	/* Remap the Port VLAN of each local bridge group member */
1851240ea3efSVivien Didelot 	for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) {
1852240ea3efSVivien Didelot 		if (chip->ds->ports[port].bridge_dev == br) {
1853240ea3efSVivien Didelot 			err = mv88e6xxx_port_vlan_map(chip, port);
1854240ea3efSVivien Didelot 			if (err)
1855240ea3efSVivien Didelot 				return err;
1856240ea3efSVivien Didelot 		}
1857240ea3efSVivien Didelot 	}
1858240ea3efSVivien Didelot 
1859e96a6e02SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
1860e96a6e02SVivien Didelot 		return 0;
1861e96a6e02SVivien Didelot 
1862e96a6e02SVivien Didelot 	/* Remap the Port VLAN of each cross-chip bridge group member */
1863e96a6e02SVivien Didelot 	for (dev = 0; dev < DSA_MAX_SWITCHES; ++dev) {
1864e96a6e02SVivien Didelot 		ds = chip->ds->dst->ds[dev];
1865e96a6e02SVivien Didelot 		if (!ds)
1866e96a6e02SVivien Didelot 			break;
1867e96a6e02SVivien Didelot 
1868e96a6e02SVivien Didelot 		for (port = 0; port < ds->num_ports; ++port) {
1869e96a6e02SVivien Didelot 			if (ds->ports[port].bridge_dev == br) {
1870e96a6e02SVivien Didelot 				err = mv88e6xxx_pvt_map(chip, dev, port);
1871e96a6e02SVivien Didelot 				if (err)
1872e96a6e02SVivien Didelot 					return err;
1873e96a6e02SVivien Didelot 			}
1874e96a6e02SVivien Didelot 		}
1875e96a6e02SVivien Didelot 	}
1876e96a6e02SVivien Didelot 
1877240ea3efSVivien Didelot 	return 0;
1878240ea3efSVivien Didelot }
1879240ea3efSVivien Didelot 
1880fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
1881fae8a25eSVivien Didelot 				      struct net_device *br)
1882fad09c73SVivien Didelot {
188304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1884240ea3efSVivien Didelot 	int err;
1885fad09c73SVivien Didelot 
1886fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1887240ea3efSVivien Didelot 	err = mv88e6xxx_bridge_map(chip, br);
1888fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1889fad09c73SVivien Didelot 
1890fad09c73SVivien Didelot 	return err;
1891fad09c73SVivien Didelot }
1892fad09c73SVivien Didelot 
1893f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
1894f123f2fbSVivien Didelot 					struct net_device *br)
1895fad09c73SVivien Didelot {
189604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1897fad09c73SVivien Didelot 
1898fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1899240ea3efSVivien Didelot 	if (mv88e6xxx_bridge_map(chip, br) ||
1900240ea3efSVivien Didelot 	    mv88e6xxx_port_vlan_map(chip, port))
1901240ea3efSVivien Didelot 		dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
1902fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1903fad09c73SVivien Didelot }
1904fad09c73SVivien Didelot 
1905aec5ac88SVivien Didelot static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev,
1906aec5ac88SVivien Didelot 					   int port, struct net_device *br)
1907aec5ac88SVivien Didelot {
1908aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1909aec5ac88SVivien Didelot 	int err;
1910aec5ac88SVivien Didelot 
1911aec5ac88SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
1912aec5ac88SVivien Didelot 		return 0;
1913aec5ac88SVivien Didelot 
1914aec5ac88SVivien Didelot 	mutex_lock(&chip->reg_lock);
1915aec5ac88SVivien Didelot 	err = mv88e6xxx_pvt_map(chip, dev, port);
1916aec5ac88SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1917aec5ac88SVivien Didelot 
1918aec5ac88SVivien Didelot 	return err;
1919aec5ac88SVivien Didelot }
1920aec5ac88SVivien Didelot 
1921aec5ac88SVivien Didelot static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev,
1922aec5ac88SVivien Didelot 					     int port, struct net_device *br)
1923aec5ac88SVivien Didelot {
1924aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1925aec5ac88SVivien Didelot 
1926aec5ac88SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
1927aec5ac88SVivien Didelot 		return;
1928aec5ac88SVivien Didelot 
1929aec5ac88SVivien Didelot 	mutex_lock(&chip->reg_lock);
1930aec5ac88SVivien Didelot 	if (mv88e6xxx_pvt_map(chip, dev, port))
1931aec5ac88SVivien Didelot 		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
1932aec5ac88SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1933aec5ac88SVivien Didelot }
1934aec5ac88SVivien Didelot 
193517e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
193617e708baSVivien Didelot {
193717e708baSVivien Didelot 	if (chip->info->ops->reset)
193817e708baSVivien Didelot 		return chip->info->ops->reset(chip);
193917e708baSVivien Didelot 
194017e708baSVivien Didelot 	return 0;
194117e708baSVivien Didelot }
194217e708baSVivien Didelot 
1943309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
1944309eca6dSVivien Didelot {
1945309eca6dSVivien Didelot 	struct gpio_desc *gpiod = chip->reset;
1946309eca6dSVivien Didelot 
1947309eca6dSVivien Didelot 	/* If there is a GPIO connected to the reset pin, toggle it */
1948309eca6dSVivien Didelot 	if (gpiod) {
1949309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 1);
1950309eca6dSVivien Didelot 		usleep_range(10000, 20000);
1951309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 0);
1952309eca6dSVivien Didelot 		usleep_range(10000, 20000);
1953309eca6dSVivien Didelot 	}
1954309eca6dSVivien Didelot }
1955309eca6dSVivien Didelot 
19564ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
19574ac4b5a6SVivien Didelot {
19584ac4b5a6SVivien Didelot 	int i, err;
19594ac4b5a6SVivien Didelot 
19604ac4b5a6SVivien Didelot 	/* Set all ports to the Disabled state */
19614ac4b5a6SVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
1962f894c29cSVivien Didelot 		err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED);
19634ac4b5a6SVivien Didelot 		if (err)
19644ac4b5a6SVivien Didelot 			return err;
19654ac4b5a6SVivien Didelot 	}
19664ac4b5a6SVivien Didelot 
19674ac4b5a6SVivien Didelot 	/* Wait for transmit queues to drain,
19684ac4b5a6SVivien Didelot 	 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
19694ac4b5a6SVivien Didelot 	 */
19704ac4b5a6SVivien Didelot 	usleep_range(2000, 4000);
19714ac4b5a6SVivien Didelot 
19724ac4b5a6SVivien Didelot 	return 0;
19734ac4b5a6SVivien Didelot }
19744ac4b5a6SVivien Didelot 
1975fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
1976fad09c73SVivien Didelot {
1977a935c052SVivien Didelot 	int err;
1978fad09c73SVivien Didelot 
19794ac4b5a6SVivien Didelot 	err = mv88e6xxx_disable_ports(chip);
19800e7b9925SAndrew Lunn 	if (err)
19810e7b9925SAndrew Lunn 		return err;
1982fad09c73SVivien Didelot 
1983309eca6dSVivien Didelot 	mv88e6xxx_hardware_reset(chip);
1984fad09c73SVivien Didelot 
198517e708baSVivien Didelot 	return mv88e6xxx_software_reset(chip);
1986fad09c73SVivien Didelot }
1987fad09c73SVivien Didelot 
19884314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
198931bef4e9SVivien Didelot 				   enum mv88e6xxx_frame_mode frame,
199031bef4e9SVivien Didelot 				   enum mv88e6xxx_egress_mode egress, u16 etype)
199156995cbcSAndrew Lunn {
199256995cbcSAndrew Lunn 	int err;
199356995cbcSAndrew Lunn 
19944314557cSVivien Didelot 	if (!chip->info->ops->port_set_frame_mode)
19954314557cSVivien Didelot 		return -EOPNOTSUPP;
19964314557cSVivien Didelot 
19974314557cSVivien Didelot 	err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
199856995cbcSAndrew Lunn 	if (err)
199956995cbcSAndrew Lunn 		return err;
200056995cbcSAndrew Lunn 
20014314557cSVivien Didelot 	err = chip->info->ops->port_set_frame_mode(chip, port, frame);
20024314557cSVivien Didelot 	if (err)
20034314557cSVivien Didelot 		return err;
20044314557cSVivien Didelot 
20054314557cSVivien Didelot 	if (chip->info->ops->port_set_ether_type)
20064314557cSVivien Didelot 		return chip->info->ops->port_set_ether_type(chip, port, etype);
20074314557cSVivien Didelot 
20084314557cSVivien Didelot 	return 0;
20094314557cSVivien Didelot }
20104314557cSVivien Didelot 
20114314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
20124314557cSVivien Didelot {
20134314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
201431bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2015b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
20164314557cSVivien Didelot }
20174314557cSVivien Didelot 
20184314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
20194314557cSVivien Didelot {
20204314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
202131bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2022b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
20234314557cSVivien Didelot }
20244314557cSVivien Didelot 
20254314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
20264314557cSVivien Didelot {
20274314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port,
20284314557cSVivien Didelot 				       MV88E6XXX_FRAME_MODE_ETHERTYPE,
202931bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_ETHERTYPE,
203031bef4e9SVivien Didelot 				       ETH_P_EDSA);
20314314557cSVivien Didelot }
20324314557cSVivien Didelot 
20334314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port)
20344314557cSVivien Didelot {
20354314557cSVivien Didelot 	if (dsa_is_dsa_port(chip->ds, port))
20364314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
20374314557cSVivien Didelot 
20382b3e9891SVivien Didelot 	if (dsa_is_user_port(chip->ds, port))
20394314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_normal(chip, port);
20404314557cSVivien Didelot 
20414314557cSVivien Didelot 	/* Setup CPU port mode depending on its supported tag format */
20424314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA)
20434314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
20444314557cSVivien Didelot 
20454314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA)
20464314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_edsa(chip, port);
20474314557cSVivien Didelot 
20484314557cSVivien Didelot 	return -EINVAL;
20494314557cSVivien Didelot }
20504314557cSVivien Didelot 
2051ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
2052ea698f4fSVivien Didelot {
2053ea698f4fSVivien Didelot 	bool message = dsa_is_dsa_port(chip->ds, port);
2054ea698f4fSVivien Didelot 
2055ea698f4fSVivien Didelot 	return mv88e6xxx_port_set_message_port(chip, port, message);
2056ea698f4fSVivien Didelot }
2057ea698f4fSVivien Didelot 
2058601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
2059601aeed3SVivien Didelot {
20603ee50cbfSVivien Didelot 	struct dsa_switch *ds = chip->ds;
20613ee50cbfSVivien Didelot 	bool flood;
2062601aeed3SVivien Didelot 
2063601aeed3SVivien Didelot 	/* Upstream ports flood frames with unknown unicast or multicast DA */
20643ee50cbfSVivien Didelot 	flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port);
2065601aeed3SVivien Didelot 	if (chip->info->ops->port_set_egress_floods)
2066601aeed3SVivien Didelot 		return chip->info->ops->port_set_egress_floods(chip, port,
2067601aeed3SVivien Didelot 							       flood, flood);
2068601aeed3SVivien Didelot 
2069601aeed3SVivien Didelot 	return 0;
2070601aeed3SVivien Didelot }
2071601aeed3SVivien Didelot 
20726d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
20736d91782fSAndrew Lunn 				  bool on)
20746d91782fSAndrew Lunn {
2075523a8904SVivien Didelot 	if (chip->info->ops->serdes_power)
2076523a8904SVivien Didelot 		return chip->info->ops->serdes_power(chip, port, on);
20776d91782fSAndrew Lunn 
2078523a8904SVivien Didelot 	return 0;
20796d91782fSAndrew Lunn }
20806d91782fSAndrew Lunn 
2081fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
2082fa371c80SVivien Didelot {
2083fa371c80SVivien Didelot 	struct dsa_switch *ds = chip->ds;
2084fa371c80SVivien Didelot 	int upstream_port;
2085fa371c80SVivien Didelot 	int err;
2086fa371c80SVivien Didelot 
208707073c79SVivien Didelot 	upstream_port = dsa_upstream_port(ds, port);
2088fa371c80SVivien Didelot 	if (chip->info->ops->port_set_upstream_port) {
2089fa371c80SVivien Didelot 		err = chip->info->ops->port_set_upstream_port(chip, port,
2090fa371c80SVivien Didelot 							      upstream_port);
2091fa371c80SVivien Didelot 		if (err)
2092fa371c80SVivien Didelot 			return err;
2093fa371c80SVivien Didelot 	}
2094fa371c80SVivien Didelot 
20950ea54ddaSVivien Didelot 	if (port == upstream_port) {
20960ea54ddaSVivien Didelot 		if (chip->info->ops->set_cpu_port) {
20970ea54ddaSVivien Didelot 			err = chip->info->ops->set_cpu_port(chip,
20980ea54ddaSVivien Didelot 							    upstream_port);
20990ea54ddaSVivien Didelot 			if (err)
21000ea54ddaSVivien Didelot 				return err;
21010ea54ddaSVivien Didelot 		}
21020ea54ddaSVivien Didelot 
21030ea54ddaSVivien Didelot 		if (chip->info->ops->set_egress_port) {
21040ea54ddaSVivien Didelot 			err = chip->info->ops->set_egress_port(chip,
21050ea54ddaSVivien Didelot 							       upstream_port);
21060ea54ddaSVivien Didelot 			if (err)
21070ea54ddaSVivien Didelot 				return err;
21080ea54ddaSVivien Didelot 		}
21090ea54ddaSVivien Didelot 	}
21100ea54ddaSVivien Didelot 
2111fa371c80SVivien Didelot 	return 0;
2112fa371c80SVivien Didelot }
2113fa371c80SVivien Didelot 
2114fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
2115fad09c73SVivien Didelot {
2116fad09c73SVivien Didelot 	struct dsa_switch *ds = chip->ds;
21170e7b9925SAndrew Lunn 	int err;
2118fad09c73SVivien Didelot 	u16 reg;
2119fad09c73SVivien Didelot 
21207b898469SAndrew Lunn 	chip->ports[port].chip = chip;
21217b898469SAndrew Lunn 	chip->ports[port].port = port;
21227b898469SAndrew Lunn 
2123d78343d2SVivien Didelot 	/* MAC Forcing register: don't force link, speed, duplex or flow control
2124d78343d2SVivien Didelot 	 * state to any particular values on physical ports, but force the CPU
2125d78343d2SVivien Didelot 	 * port and all DSA ports to their maximum bandwidth and full duplex.
2126fad09c73SVivien Didelot 	 */
2127d78343d2SVivien Didelot 	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
2128d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
2129d78343d2SVivien Didelot 					       SPEED_MAX, DUPLEX_FULL,
213054186b91SAndrew Lunn 					       PAUSE_OFF,
2131d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
2132fad09c73SVivien Didelot 	else
2133d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
2134d78343d2SVivien Didelot 					       SPEED_UNFORCED, DUPLEX_UNFORCED,
213554186b91SAndrew Lunn 					       PAUSE_ON,
2136d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
21370e7b9925SAndrew Lunn 	if (err)
21380e7b9925SAndrew Lunn 		return err;
2139fad09c73SVivien Didelot 
2140fad09c73SVivien Didelot 	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
2141fad09c73SVivien Didelot 	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
2142fad09c73SVivien Didelot 	 * tunneling, determine priority by looking at 802.1p and IP
2143fad09c73SVivien Didelot 	 * priority fields (IP prio has precedence), and set STP state
2144fad09c73SVivien Didelot 	 * to Forwarding.
2145fad09c73SVivien Didelot 	 *
2146fad09c73SVivien Didelot 	 * If this is the CPU link, use DSA or EDSA tagging depending
2147fad09c73SVivien Didelot 	 * on which tagging mode was configured.
2148fad09c73SVivien Didelot 	 *
2149fad09c73SVivien Didelot 	 * If this is a link to another switch, use DSA tagging mode.
2150fad09c73SVivien Didelot 	 *
2151fad09c73SVivien Didelot 	 * If this is the upstream port for this switch, enable
2152fad09c73SVivien Didelot 	 * forwarding of unknown unicasts and multicasts.
2153fad09c73SVivien Didelot 	 */
2154a89b433bSVivien Didelot 	reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP |
2155a89b433bSVivien Didelot 		MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
2156a89b433bSVivien Didelot 		MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
2157a89b433bSVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
21580e7b9925SAndrew Lunn 	if (err)
21590e7b9925SAndrew Lunn 		return err;
216056995cbcSAndrew Lunn 
2161601aeed3SVivien Didelot 	err = mv88e6xxx_setup_port_mode(chip, port);
216256995cbcSAndrew Lunn 	if (err)
216356995cbcSAndrew Lunn 		return err;
2164fad09c73SVivien Didelot 
2165601aeed3SVivien Didelot 	err = mv88e6xxx_setup_egress_floods(chip, port);
21664314557cSVivien Didelot 	if (err)
21674314557cSVivien Didelot 		return err;
21684314557cSVivien Didelot 
216904aca993SAndrew Lunn 	/* Enable the SERDES interface for DSA and CPU ports. Normal
217004aca993SAndrew Lunn 	 * ports SERDES are enabled when the port is enabled, thus
217104aca993SAndrew Lunn 	 * saving a bit of power.
2172fad09c73SVivien Didelot 	 */
217304aca993SAndrew Lunn 	if ((dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) {
21746d91782fSAndrew Lunn 		err = mv88e6xxx_serdes_power(chip, port, true);
21750e7b9925SAndrew Lunn 		if (err)
21760e7b9925SAndrew Lunn 			return err;
217704aca993SAndrew Lunn 	}
2178fad09c73SVivien Didelot 
2179fad09c73SVivien Didelot 	/* Port Control 2: don't force a good FCS, set the maximum frame size to
2180fad09c73SVivien Didelot 	 * 10240 bytes, disable 802.1q tags checking, don't discard tagged or
2181fad09c73SVivien Didelot 	 * untagged frames on this port, do a destination address lookup on all
2182fad09c73SVivien Didelot 	 * received packets as usual, disable ARP mirroring and don't send a
2183fad09c73SVivien Didelot 	 * copy of all transmitted/received frames on this port to the CPU.
2184fad09c73SVivien Didelot 	 */
2185a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_map_da(chip, port);
2186a23b2961SAndrew Lunn 	if (err)
2187a23b2961SAndrew Lunn 		return err;
2188a23b2961SAndrew Lunn 
2189fa371c80SVivien Didelot 	err = mv88e6xxx_setup_upstream_port(chip, port);
21900e7b9925SAndrew Lunn 	if (err)
21910e7b9925SAndrew Lunn 		return err;
2192fad09c73SVivien Didelot 
2193a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_8021q_mode(chip, port,
219481c6edb2SVivien Didelot 				MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED);
2195a23b2961SAndrew Lunn 	if (err)
2196a23b2961SAndrew Lunn 		return err;
2197a23b2961SAndrew Lunn 
2198cd782656SVivien Didelot 	if (chip->info->ops->port_set_jumbo_size) {
2199cd782656SVivien Didelot 		err = chip->info->ops->port_set_jumbo_size(chip, port, 10240);
22005f436666SAndrew Lunn 		if (err)
22015f436666SAndrew Lunn 			return err;
22025f436666SAndrew Lunn 	}
22035f436666SAndrew Lunn 
2204fad09c73SVivien Didelot 	/* Port Association Vector: when learning source addresses
2205fad09c73SVivien Didelot 	 * of packets, add the address to the address database using
2206fad09c73SVivien Didelot 	 * a port bitmap that has only the bit for this port set and
2207fad09c73SVivien Didelot 	 * the other bits clear.
2208fad09c73SVivien Didelot 	 */
2209fad09c73SVivien Didelot 	reg = 1 << port;
2210fad09c73SVivien Didelot 	/* Disable learning for CPU port */
2211fad09c73SVivien Didelot 	if (dsa_is_cpu_port(ds, port))
2212fad09c73SVivien Didelot 		reg = 0;
2213fad09c73SVivien Didelot 
22142a4614e4SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
22152a4614e4SVivien Didelot 				   reg);
22160e7b9925SAndrew Lunn 	if (err)
22170e7b9925SAndrew Lunn 		return err;
2218fad09c73SVivien Didelot 
2219fad09c73SVivien Didelot 	/* Egress rate control 2: disable egress rate control. */
22202cb8cb14SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2,
22212cb8cb14SVivien Didelot 				   0x0000);
22220e7b9925SAndrew Lunn 	if (err)
22230e7b9925SAndrew Lunn 		return err;
2224fad09c73SVivien Didelot 
22250898432cSVivien Didelot 	if (chip->info->ops->port_pause_limit) {
22260898432cSVivien Didelot 		err = chip->info->ops->port_pause_limit(chip, port, 0, 0);
2227b35d322aSAndrew Lunn 		if (err)
2228b35d322aSAndrew Lunn 			return err;
2229b35d322aSAndrew Lunn 	}
2230b35d322aSAndrew Lunn 
2231c8c94891SVivien Didelot 	if (chip->info->ops->port_disable_learn_limit) {
2232c8c94891SVivien Didelot 		err = chip->info->ops->port_disable_learn_limit(chip, port);
2233c8c94891SVivien Didelot 		if (err)
2234c8c94891SVivien Didelot 			return err;
2235c8c94891SVivien Didelot 	}
2236c8c94891SVivien Didelot 
22379dbfb4e1SVivien Didelot 	if (chip->info->ops->port_disable_pri_override) {
22389dbfb4e1SVivien Didelot 		err = chip->info->ops->port_disable_pri_override(chip, port);
22390e7b9925SAndrew Lunn 		if (err)
22400e7b9925SAndrew Lunn 			return err;
2241ef0a7318SAndrew Lunn 	}
22422bbb33beSAndrew Lunn 
2243ef0a7318SAndrew Lunn 	if (chip->info->ops->port_tag_remap) {
2244ef0a7318SAndrew Lunn 		err = chip->info->ops->port_tag_remap(chip, port);
22450e7b9925SAndrew Lunn 		if (err)
22460e7b9925SAndrew Lunn 			return err;
2247fad09c73SVivien Didelot 	}
2248fad09c73SVivien Didelot 
2249ef70b111SAndrew Lunn 	if (chip->info->ops->port_egress_rate_limiting) {
2250ef70b111SAndrew Lunn 		err = chip->info->ops->port_egress_rate_limiting(chip, port);
22510e7b9925SAndrew Lunn 		if (err)
22520e7b9925SAndrew Lunn 			return err;
2253fad09c73SVivien Didelot 	}
2254fad09c73SVivien Didelot 
2255ea698f4fSVivien Didelot 	err = mv88e6xxx_setup_message_port(chip, port);
22560e7b9925SAndrew Lunn 	if (err)
22570e7b9925SAndrew Lunn 		return err;
2258fad09c73SVivien Didelot 
2259fad09c73SVivien Didelot 	/* Port based VLAN map: give each port the same default address
2260fad09c73SVivien Didelot 	 * database, and allow bidirectional communication between the
2261fad09c73SVivien Didelot 	 * CPU and DSA port(s), and the other ports.
2262fad09c73SVivien Didelot 	 */
2263b4e48c50SVivien Didelot 	err = mv88e6xxx_port_set_fid(chip, port, 0);
22640e7b9925SAndrew Lunn 	if (err)
22650e7b9925SAndrew Lunn 		return err;
2266fad09c73SVivien Didelot 
2267240ea3efSVivien Didelot 	err = mv88e6xxx_port_vlan_map(chip, port);
22680e7b9925SAndrew Lunn 	if (err)
22690e7b9925SAndrew Lunn 		return err;
2270fad09c73SVivien Didelot 
2271fad09c73SVivien Didelot 	/* Default VLAN ID and priority: don't set a default VLAN
2272fad09c73SVivien Didelot 	 * ID, and set the default packet priority to zero.
2273fad09c73SVivien Didelot 	 */
2274b7929fb3SVivien Didelot 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0);
2275fad09c73SVivien Didelot }
2276fad09c73SVivien Didelot 
227704aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
227804aca993SAndrew Lunn 				 struct phy_device *phydev)
227904aca993SAndrew Lunn {
228004aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
2281523a8904SVivien Didelot 	int err;
228204aca993SAndrew Lunn 
228304aca993SAndrew Lunn 	mutex_lock(&chip->reg_lock);
2284efd1ba6aSAndrew Lunn 
2285523a8904SVivien Didelot 	err = mv88e6xxx_serdes_power(chip, port, true);
2286efd1ba6aSAndrew Lunn 
2287efd1ba6aSAndrew Lunn 	if (!err && chip->info->ops->serdes_irq_setup)
2288efd1ba6aSAndrew Lunn 		err = chip->info->ops->serdes_irq_setup(chip, port);
2289efd1ba6aSAndrew Lunn 
229004aca993SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
229104aca993SAndrew Lunn 
229204aca993SAndrew Lunn 	return err;
229304aca993SAndrew Lunn }
229404aca993SAndrew Lunn 
229575104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
229604aca993SAndrew Lunn {
229704aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
229804aca993SAndrew Lunn 
229904aca993SAndrew Lunn 	mutex_lock(&chip->reg_lock);
2300efd1ba6aSAndrew Lunn 
23014a0eb731SAndrew Lunn 	if (mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED))
23024a0eb731SAndrew Lunn 		dev_err(chip->dev, "failed to disable port\n");
23034a0eb731SAndrew Lunn 
2304efd1ba6aSAndrew Lunn 	if (chip->info->ops->serdes_irq_free)
2305efd1ba6aSAndrew Lunn 		chip->info->ops->serdes_irq_free(chip, port);
2306efd1ba6aSAndrew Lunn 
2307523a8904SVivien Didelot 	if (mv88e6xxx_serdes_power(chip, port, false))
2308523a8904SVivien Didelot 		dev_err(chip->dev, "failed to power off SERDES\n");
2309efd1ba6aSAndrew Lunn 
231004aca993SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
231104aca993SAndrew Lunn }
231204aca993SAndrew Lunn 
23132cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
23142cfcd964SVivien Didelot 				     unsigned int ageing_time)
23152cfcd964SVivien Didelot {
231604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
23172cfcd964SVivien Didelot 	int err;
23182cfcd964SVivien Didelot 
23192cfcd964SVivien Didelot 	mutex_lock(&chip->reg_lock);
2320720c6343SVivien Didelot 	err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
23212cfcd964SVivien Didelot 	mutex_unlock(&chip->reg_lock);
23222cfcd964SVivien Didelot 
23232cfcd964SVivien Didelot 	return err;
23242cfcd964SVivien Didelot }
23252cfcd964SVivien Didelot 
2326447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
2327fad09c73SVivien Didelot {
2328fad09c73SVivien Didelot 	int err;
2329fad09c73SVivien Didelot 
2330de227387SAndrew Lunn 	/* Initialize the statistics unit */
2331447b1bb8SVivien Didelot 	if (chip->info->ops->stats_set_histogram) {
2332447b1bb8SVivien Didelot 		err = chip->info->ops->stats_set_histogram(chip);
2333de227387SAndrew Lunn 		if (err)
2334de227387SAndrew Lunn 			return err;
2335447b1bb8SVivien Didelot 	}
2336de227387SAndrew Lunn 
233740cff8fcSAndrew Lunn 	return mv88e6xxx_g1_stats_clear(chip);
23389729934cSVivien Didelot }
23399729934cSVivien Didelot 
2340ea89098eSAndrew Lunn /* The mv88e6390 has some hidden registers used for debug and
2341ea89098eSAndrew Lunn  * development. The errata also makes use of them.
2342ea89098eSAndrew Lunn  */
2343ea89098eSAndrew Lunn static int mv88e6390_hidden_write(struct mv88e6xxx_chip *chip, int port,
2344ea89098eSAndrew Lunn 				  int reg, u16 val)
2345ea89098eSAndrew Lunn {
2346ea89098eSAndrew Lunn 	u16 ctrl;
2347ea89098eSAndrew Lunn 	int err;
2348ea89098eSAndrew Lunn 
2349ea89098eSAndrew Lunn 	err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_DATA_PORT,
2350ea89098eSAndrew Lunn 				   PORT_RESERVED_1A, val);
2351ea89098eSAndrew Lunn 	if (err)
2352ea89098eSAndrew Lunn 		return err;
2353ea89098eSAndrew Lunn 
2354ea89098eSAndrew Lunn 	ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_WRITE |
2355ea89098eSAndrew Lunn 	       PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT |
2356ea89098eSAndrew Lunn 	       reg;
2357ea89098eSAndrew Lunn 
2358ea89098eSAndrew Lunn 	return mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT,
2359ea89098eSAndrew Lunn 				    PORT_RESERVED_1A, ctrl);
2360ea89098eSAndrew Lunn }
2361ea89098eSAndrew Lunn 
2362ea89098eSAndrew Lunn static int mv88e6390_hidden_wait(struct mv88e6xxx_chip *chip)
2363ea89098eSAndrew Lunn {
2364ea89098eSAndrew Lunn 	return mv88e6xxx_wait(chip, PORT_RESERVED_1A_CTRL_PORT,
2365ea89098eSAndrew Lunn 			      PORT_RESERVED_1A, PORT_RESERVED_1A_BUSY);
2366ea89098eSAndrew Lunn }
2367ea89098eSAndrew Lunn 
2368ea89098eSAndrew Lunn 
2369ea89098eSAndrew Lunn static int mv88e6390_hidden_read(struct mv88e6xxx_chip *chip, int port,
2370ea89098eSAndrew Lunn 				  int reg, u16 *val)
2371ea89098eSAndrew Lunn {
2372ea89098eSAndrew Lunn 	u16 ctrl;
2373ea89098eSAndrew Lunn 	int err;
2374ea89098eSAndrew Lunn 
2375ea89098eSAndrew Lunn 	ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_READ |
2376ea89098eSAndrew Lunn 	       PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT |
2377ea89098eSAndrew Lunn 	       reg;
2378ea89098eSAndrew Lunn 
2379ea89098eSAndrew Lunn 	err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT,
2380ea89098eSAndrew Lunn 				   PORT_RESERVED_1A, ctrl);
2381ea89098eSAndrew Lunn 	if (err)
2382ea89098eSAndrew Lunn 		return err;
2383ea89098eSAndrew Lunn 
2384ea89098eSAndrew Lunn 	err = mv88e6390_hidden_wait(chip);
2385ea89098eSAndrew Lunn 	if (err)
2386ea89098eSAndrew Lunn 		return err;
2387ea89098eSAndrew Lunn 
2388ea89098eSAndrew Lunn 	return 	mv88e6xxx_port_read(chip, PORT_RESERVED_1A_DATA_PORT,
2389ea89098eSAndrew Lunn 				    PORT_RESERVED_1A, val);
2390ea89098eSAndrew Lunn }
2391ea89098eSAndrew Lunn 
2392ea89098eSAndrew Lunn /* Check if the errata has already been applied. */
2393ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
2394ea89098eSAndrew Lunn {
2395ea89098eSAndrew Lunn 	int port;
2396ea89098eSAndrew Lunn 	int err;
2397ea89098eSAndrew Lunn 	u16 val;
2398ea89098eSAndrew Lunn 
2399ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
2400ea89098eSAndrew Lunn 		err = mv88e6390_hidden_read(chip, port, 0, &val);
2401ea89098eSAndrew Lunn 		if (err) {
2402ea89098eSAndrew Lunn 			dev_err(chip->dev,
2403ea89098eSAndrew Lunn 				"Error reading hidden register: %d\n", err);
2404ea89098eSAndrew Lunn 			return false;
2405ea89098eSAndrew Lunn 		}
2406ea89098eSAndrew Lunn 		if (val != 0x01c0)
2407ea89098eSAndrew Lunn 			return false;
2408ea89098eSAndrew Lunn 	}
2409ea89098eSAndrew Lunn 
2410ea89098eSAndrew Lunn 	return true;
2411ea89098eSAndrew Lunn }
2412ea89098eSAndrew Lunn 
2413ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic
2414ea89098eSAndrew Lunn  * values into undocumented hidden registers and then performing a
2415ea89098eSAndrew Lunn  * software reset.
2416ea89098eSAndrew Lunn  */
2417ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
2418ea89098eSAndrew Lunn {
2419ea89098eSAndrew Lunn 	int port;
2420ea89098eSAndrew Lunn 	int err;
2421ea89098eSAndrew Lunn 
2422ea89098eSAndrew Lunn 	if (mv88e6390_setup_errata_applied(chip))
2423ea89098eSAndrew Lunn 		return 0;
2424ea89098eSAndrew Lunn 
2425ea89098eSAndrew Lunn 	/* Set the ports into blocking mode */
2426ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
2427ea89098eSAndrew Lunn 		err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED);
2428ea89098eSAndrew Lunn 		if (err)
2429ea89098eSAndrew Lunn 			return err;
2430ea89098eSAndrew Lunn 	}
2431ea89098eSAndrew Lunn 
2432ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
2433ea89098eSAndrew Lunn 		err = mv88e6390_hidden_write(chip, port, 0, 0x01c0);
2434ea89098eSAndrew Lunn 		if (err)
2435ea89098eSAndrew Lunn 			return err;
2436ea89098eSAndrew Lunn 	}
2437ea89098eSAndrew Lunn 
2438ea89098eSAndrew Lunn 	return mv88e6xxx_software_reset(chip);
2439ea89098eSAndrew Lunn }
2440ea89098eSAndrew Lunn 
2441fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds)
2442fad09c73SVivien Didelot {
244304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
24442d2e1dd2SAndrew Lunn 	u8 cmode;
2445fad09c73SVivien Didelot 	int err;
2446fad09c73SVivien Didelot 	int i;
2447fad09c73SVivien Didelot 
2448fad09c73SVivien Didelot 	chip->ds = ds;
2449a3c53be5SAndrew Lunn 	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
2450fad09c73SVivien Didelot 
2451fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
2452fad09c73SVivien Didelot 
2453ea89098eSAndrew Lunn 	if (chip->info->ops->setup_errata) {
2454ea89098eSAndrew Lunn 		err = chip->info->ops->setup_errata(chip);
2455ea89098eSAndrew Lunn 		if (err)
2456ea89098eSAndrew Lunn 			goto unlock;
2457ea89098eSAndrew Lunn 	}
2458ea89098eSAndrew Lunn 
24592d2e1dd2SAndrew Lunn 	/* Cache the cmode of each port. */
24602d2e1dd2SAndrew Lunn 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
24612d2e1dd2SAndrew Lunn 		if (chip->info->ops->port_get_cmode) {
24622d2e1dd2SAndrew Lunn 			err = chip->info->ops->port_get_cmode(chip, i, &cmode);
24632d2e1dd2SAndrew Lunn 			if (err)
2464e29129fcSDan Carpenter 				goto unlock;
24652d2e1dd2SAndrew Lunn 
24662d2e1dd2SAndrew Lunn 			chip->ports[i].cmode = cmode;
24672d2e1dd2SAndrew Lunn 		}
24682d2e1dd2SAndrew Lunn 	}
24692d2e1dd2SAndrew Lunn 
24709729934cSVivien Didelot 	/* Setup Switch Port Registers */
2471370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2472100a9b9dSAndrew Lunn 		if (dsa_is_unused_port(ds, i)) {
2473100a9b9dSAndrew Lunn 			err = mv88e6xxx_port_set_state(chip, i,
2474100a9b9dSAndrew Lunn 						       BR_STATE_DISABLED);
2475100a9b9dSAndrew Lunn 			if (err)
2476100a9b9dSAndrew Lunn 				goto unlock;
2477100a9b9dSAndrew Lunn 
2478100a9b9dSAndrew Lunn 			err = mv88e6xxx_serdes_power(chip, i, false);
2479100a9b9dSAndrew Lunn 			if (err)
2480100a9b9dSAndrew Lunn 				goto unlock;
2481100a9b9dSAndrew Lunn 
248291dee144SVivien Didelot 			continue;
2483100a9b9dSAndrew Lunn 		}
248491dee144SVivien Didelot 
24859729934cSVivien Didelot 		err = mv88e6xxx_setup_port(chip, i);
24869729934cSVivien Didelot 		if (err)
24879729934cSVivien Didelot 			goto unlock;
24889729934cSVivien Didelot 	}
24899729934cSVivien Didelot 
2490cd8da8bbSVivien Didelot 	err = mv88e6xxx_irl_setup(chip);
2491cd8da8bbSVivien Didelot 	if (err)
2492cd8da8bbSVivien Didelot 		goto unlock;
2493cd8da8bbSVivien Didelot 
249404a69a17SVivien Didelot 	err = mv88e6xxx_mac_setup(chip);
249504a69a17SVivien Didelot 	if (err)
249604a69a17SVivien Didelot 		goto unlock;
249704a69a17SVivien Didelot 
24981b17aedfSVivien Didelot 	err = mv88e6xxx_phy_setup(chip);
24991b17aedfSVivien Didelot 	if (err)
25001b17aedfSVivien Didelot 		goto unlock;
25011b17aedfSVivien Didelot 
2502b486d7c9SVivien Didelot 	err = mv88e6xxx_vtu_setup(chip);
2503b486d7c9SVivien Didelot 	if (err)
2504b486d7c9SVivien Didelot 		goto unlock;
2505b486d7c9SVivien Didelot 
250681228996SVivien Didelot 	err = mv88e6xxx_pvt_setup(chip);
250781228996SVivien Didelot 	if (err)
250881228996SVivien Didelot 		goto unlock;
250981228996SVivien Didelot 
2510a2ac29d2SVivien Didelot 	err = mv88e6xxx_atu_setup(chip);
2511a2ac29d2SVivien Didelot 	if (err)
2512a2ac29d2SVivien Didelot 		goto unlock;
2513a2ac29d2SVivien Didelot 
251487fa886eSAndrew Lunn 	err = mv88e6xxx_broadcast_setup(chip, 0);
251587fa886eSAndrew Lunn 	if (err)
251687fa886eSAndrew Lunn 		goto unlock;
251787fa886eSAndrew Lunn 
25189e907d73SVivien Didelot 	err = mv88e6xxx_pot_setup(chip);
25199e907d73SVivien Didelot 	if (err)
25209e907d73SVivien Didelot 		goto unlock;
25219e907d73SVivien Didelot 
25229e5baf9bSVivien Didelot 	err = mv88e6xxx_rmu_setup(chip);
25239e5baf9bSVivien Didelot 	if (err)
25249e5baf9bSVivien Didelot 		goto unlock;
25259e5baf9bSVivien Didelot 
252651c901a7SVivien Didelot 	err = mv88e6xxx_rsvd2cpu_setup(chip);
25276e55f698SAndrew Lunn 	if (err)
25286e55f698SAndrew Lunn 		goto unlock;
25296e55f698SAndrew Lunn 
2530b28f872dSVivien Didelot 	err = mv88e6xxx_trunk_setup(chip);
2531b28f872dSVivien Didelot 	if (err)
2532b28f872dSVivien Didelot 		goto unlock;
2533b28f872dSVivien Didelot 
2534c7f047b6SVivien Didelot 	err = mv88e6xxx_devmap_setup(chip);
2535c7f047b6SVivien Didelot 	if (err)
2536c7f047b6SVivien Didelot 		goto unlock;
2537c7f047b6SVivien Didelot 
253893e18d61SVivien Didelot 	err = mv88e6xxx_pri_setup(chip);
253993e18d61SVivien Didelot 	if (err)
254093e18d61SVivien Didelot 		goto unlock;
254193e18d61SVivien Didelot 
2542c6fe0ad2SBrandon Streiff 	/* Setup PTP Hardware Clock and timestamping */
25432fa8d3afSBrandon Streiff 	if (chip->info->ptp_support) {
25442fa8d3afSBrandon Streiff 		err = mv88e6xxx_ptp_setup(chip);
25452fa8d3afSBrandon Streiff 		if (err)
25462fa8d3afSBrandon Streiff 			goto unlock;
2547c6fe0ad2SBrandon Streiff 
2548c6fe0ad2SBrandon Streiff 		err = mv88e6xxx_hwtstamp_setup(chip);
2549c6fe0ad2SBrandon Streiff 		if (err)
2550c6fe0ad2SBrandon Streiff 			goto unlock;
25512fa8d3afSBrandon Streiff 	}
25522fa8d3afSBrandon Streiff 
2553447b1bb8SVivien Didelot 	err = mv88e6xxx_stats_setup(chip);
2554447b1bb8SVivien Didelot 	if (err)
2555447b1bb8SVivien Didelot 		goto unlock;
2556447b1bb8SVivien Didelot 
2557fad09c73SVivien Didelot unlock:
2558fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2559fad09c73SVivien Didelot 
2560fad09c73SVivien Didelot 	return err;
2561fad09c73SVivien Didelot }
2562fad09c73SVivien Didelot 
2563e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
2564fad09c73SVivien Didelot {
25650dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
25660dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
2567e57e5e77SVivien Didelot 	u16 val;
2568e57e5e77SVivien Didelot 	int err;
2569fad09c73SVivien Didelot 
2570ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_read)
2571ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
2572ee26a228SAndrew Lunn 
2573fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
2574ee26a228SAndrew Lunn 	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
2575fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2576e57e5e77SVivien Didelot 
2577da9f3301SAndrew Lunn 	if (reg == MII_PHYSID2) {
2578ddc49acbSAndrew Lunn 		/* Some internal PHYs don't have a model number. */
2579ddc49acbSAndrew Lunn 		if (chip->info->family != MV88E6XXX_FAMILY_6165)
2580ddc49acbSAndrew Lunn 			/* Then there is the 6165 family. It gets is
2581ddc49acbSAndrew Lunn 			 * PHYs correct. But it can also have two
2582ddc49acbSAndrew Lunn 			 * SERDES interfaces in the PHY address
2583ddc49acbSAndrew Lunn 			 * space. And these don't have a model
2584ddc49acbSAndrew Lunn 			 * number. But they are not PHYs, so we don't
2585ddc49acbSAndrew Lunn 			 * want to give them something a PHY driver
2586ddc49acbSAndrew Lunn 			 * will recognise.
2587ddc49acbSAndrew Lunn 			 *
2588ddc49acbSAndrew Lunn 			 * Use the mv88e6390 family model number
2589ddc49acbSAndrew Lunn 			 * instead, for anything which really could be
2590ddc49acbSAndrew Lunn 			 * a PHY,
2591da9f3301SAndrew Lunn 			 */
2592da9f3301SAndrew Lunn 			if (!(val & 0x3f0))
2593107fcc10SVivien Didelot 				val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4;
2594da9f3301SAndrew Lunn 	}
2595da9f3301SAndrew Lunn 
2596e57e5e77SVivien Didelot 	return err ? err : val;
2597fad09c73SVivien Didelot }
2598fad09c73SVivien Didelot 
2599e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
2600fad09c73SVivien Didelot {
26010dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
26020dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
2603e57e5e77SVivien Didelot 	int err;
2604fad09c73SVivien Didelot 
2605ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_write)
2606ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
2607ee26a228SAndrew Lunn 
2608fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
2609ee26a228SAndrew Lunn 	err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
2610fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2611e57e5e77SVivien Didelot 
2612e57e5e77SVivien Didelot 	return err;
2613fad09c73SVivien Didelot }
2614fad09c73SVivien Didelot 
2615fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
2616a3c53be5SAndrew Lunn 				   struct device_node *np,
2617a3c53be5SAndrew Lunn 				   bool external)
2618fad09c73SVivien Didelot {
2619fad09c73SVivien Didelot 	static int index;
26200dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
2621fad09c73SVivien Didelot 	struct mii_bus *bus;
2622fad09c73SVivien Didelot 	int err;
2623fad09c73SVivien Didelot 
26242510babcSAndrew Lunn 	if (external) {
26252510babcSAndrew Lunn 		mutex_lock(&chip->reg_lock);
26262510babcSAndrew Lunn 		err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
26272510babcSAndrew Lunn 		mutex_unlock(&chip->reg_lock);
26282510babcSAndrew Lunn 
26292510babcSAndrew Lunn 		if (err)
26302510babcSAndrew Lunn 			return err;
26312510babcSAndrew Lunn 	}
26322510babcSAndrew Lunn 
26330dd12d54SAndrew Lunn 	bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
2634fad09c73SVivien Didelot 	if (!bus)
2635fad09c73SVivien Didelot 		return -ENOMEM;
2636fad09c73SVivien Didelot 
26370dd12d54SAndrew Lunn 	mdio_bus = bus->priv;
2638a3c53be5SAndrew Lunn 	mdio_bus->bus = bus;
26390dd12d54SAndrew Lunn 	mdio_bus->chip = chip;
2640a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&mdio_bus->list);
2641a3c53be5SAndrew Lunn 	mdio_bus->external = external;
26420dd12d54SAndrew Lunn 
2643fad09c73SVivien Didelot 	if (np) {
2644fad09c73SVivien Didelot 		bus->name = np->full_name;
2645f7ce9103SRob Herring 		snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np);
2646fad09c73SVivien Didelot 	} else {
2647fad09c73SVivien Didelot 		bus->name = "mv88e6xxx SMI";
2648fad09c73SVivien Didelot 		snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
2649fad09c73SVivien Didelot 	}
2650fad09c73SVivien Didelot 
2651fad09c73SVivien Didelot 	bus->read = mv88e6xxx_mdio_read;
2652fad09c73SVivien Didelot 	bus->write = mv88e6xxx_mdio_write;
2653fad09c73SVivien Didelot 	bus->parent = chip->dev;
2654fad09c73SVivien Didelot 
26556f88284fSAndrew Lunn 	if (!external) {
26566f88284fSAndrew Lunn 		err = mv88e6xxx_g2_irq_mdio_setup(chip, bus);
26576f88284fSAndrew Lunn 		if (err)
26586f88284fSAndrew Lunn 			return err;
26596f88284fSAndrew Lunn 	}
26606f88284fSAndrew Lunn 
2661a3c53be5SAndrew Lunn 	err = of_mdiobus_register(bus, np);
2662fad09c73SVivien Didelot 	if (err) {
2663fad09c73SVivien Didelot 		dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
26646f88284fSAndrew Lunn 		mv88e6xxx_g2_irq_mdio_free(chip, bus);
2665fad09c73SVivien Didelot 		return err;
2666fad09c73SVivien Didelot 	}
2667fad09c73SVivien Didelot 
2668a3c53be5SAndrew Lunn 	if (external)
2669a3c53be5SAndrew Lunn 		list_add_tail(&mdio_bus->list, &chip->mdios);
2670a3c53be5SAndrew Lunn 	else
2671a3c53be5SAndrew Lunn 		list_add(&mdio_bus->list, &chip->mdios);
2672a3c53be5SAndrew Lunn 
2673a3c53be5SAndrew Lunn 	return 0;
2674a3c53be5SAndrew Lunn }
2675a3c53be5SAndrew Lunn 
2676a3c53be5SAndrew Lunn static const struct of_device_id mv88e6xxx_mdio_external_match[] = {
2677a3c53be5SAndrew Lunn 	{ .compatible = "marvell,mv88e6xxx-mdio-external",
2678a3c53be5SAndrew Lunn 	  .data = (void *)true },
2679a3c53be5SAndrew Lunn 	{ },
2680a3c53be5SAndrew Lunn };
2681a3c53be5SAndrew Lunn 
26823126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
26833126aeecSAndrew Lunn 
26843126aeecSAndrew Lunn {
26853126aeecSAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
26863126aeecSAndrew Lunn 	struct mii_bus *bus;
26873126aeecSAndrew Lunn 
26883126aeecSAndrew Lunn 	list_for_each_entry(mdio_bus, &chip->mdios, list) {
26893126aeecSAndrew Lunn 		bus = mdio_bus->bus;
26903126aeecSAndrew Lunn 
26916f88284fSAndrew Lunn 		if (!mdio_bus->external)
26926f88284fSAndrew Lunn 			mv88e6xxx_g2_irq_mdio_free(chip, bus);
26936f88284fSAndrew Lunn 
26943126aeecSAndrew Lunn 		mdiobus_unregister(bus);
26953126aeecSAndrew Lunn 	}
26963126aeecSAndrew Lunn }
26973126aeecSAndrew Lunn 
2698a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
2699a3c53be5SAndrew Lunn 				    struct device_node *np)
2700a3c53be5SAndrew Lunn {
2701a3c53be5SAndrew Lunn 	const struct of_device_id *match;
2702a3c53be5SAndrew Lunn 	struct device_node *child;
2703a3c53be5SAndrew Lunn 	int err;
2704a3c53be5SAndrew Lunn 
2705a3c53be5SAndrew Lunn 	/* Always register one mdio bus for the internal/default mdio
2706a3c53be5SAndrew Lunn 	 * bus. This maybe represented in the device tree, but is
2707a3c53be5SAndrew Lunn 	 * optional.
2708a3c53be5SAndrew Lunn 	 */
2709a3c53be5SAndrew Lunn 	child = of_get_child_by_name(np, "mdio");
2710a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdio_register(chip, child, false);
2711a3c53be5SAndrew Lunn 	if (err)
2712a3c53be5SAndrew Lunn 		return err;
2713a3c53be5SAndrew Lunn 
2714a3c53be5SAndrew Lunn 	/* Walk the device tree, and see if there are any other nodes
2715a3c53be5SAndrew Lunn 	 * which say they are compatible with the external mdio
2716a3c53be5SAndrew Lunn 	 * bus.
2717a3c53be5SAndrew Lunn 	 */
2718a3c53be5SAndrew Lunn 	for_each_available_child_of_node(np, child) {
2719a3c53be5SAndrew Lunn 		match = of_match_node(mv88e6xxx_mdio_external_match, child);
2720a3c53be5SAndrew Lunn 		if (match) {
2721a3c53be5SAndrew Lunn 			err = mv88e6xxx_mdio_register(chip, child, true);
27223126aeecSAndrew Lunn 			if (err) {
27233126aeecSAndrew Lunn 				mv88e6xxx_mdios_unregister(chip);
2724a3c53be5SAndrew Lunn 				return err;
2725a3c53be5SAndrew Lunn 			}
2726a3c53be5SAndrew Lunn 		}
27273126aeecSAndrew Lunn 	}
2728a3c53be5SAndrew Lunn 
2729a3c53be5SAndrew Lunn 	return 0;
2730a3c53be5SAndrew Lunn }
2731a3c53be5SAndrew Lunn 
2732855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
2733855b1932SVivien Didelot {
273404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2735855b1932SVivien Didelot 
2736855b1932SVivien Didelot 	return chip->eeprom_len;
2737855b1932SVivien Didelot }
2738855b1932SVivien Didelot 
2739855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
2740855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
2741855b1932SVivien Didelot {
274204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2743855b1932SVivien Didelot 	int err;
2744855b1932SVivien Didelot 
2745ee4dc2e7SVivien Didelot 	if (!chip->info->ops->get_eeprom)
2746ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
2747ee4dc2e7SVivien Didelot 
2748855b1932SVivien Didelot 	mutex_lock(&chip->reg_lock);
2749ee4dc2e7SVivien Didelot 	err = chip->info->ops->get_eeprom(chip, eeprom, data);
2750855b1932SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2751855b1932SVivien Didelot 
2752855b1932SVivien Didelot 	if (err)
2753855b1932SVivien Didelot 		return err;
2754855b1932SVivien Didelot 
2755855b1932SVivien Didelot 	eeprom->magic = 0xc3ec4951;
2756855b1932SVivien Didelot 
2757855b1932SVivien Didelot 	return 0;
2758855b1932SVivien Didelot }
2759855b1932SVivien Didelot 
2760855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
2761855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
2762855b1932SVivien Didelot {
276304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2764855b1932SVivien Didelot 	int err;
2765855b1932SVivien Didelot 
2766ee4dc2e7SVivien Didelot 	if (!chip->info->ops->set_eeprom)
2767ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
2768ee4dc2e7SVivien Didelot 
2769855b1932SVivien Didelot 	if (eeprom->magic != 0xc3ec4951)
2770855b1932SVivien Didelot 		return -EINVAL;
2771855b1932SVivien Didelot 
2772855b1932SVivien Didelot 	mutex_lock(&chip->reg_lock);
2773ee4dc2e7SVivien Didelot 	err = chip->info->ops->set_eeprom(chip, eeprom, data);
2774855b1932SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2775855b1932SVivien Didelot 
2776855b1932SVivien Didelot 	return err;
2777855b1932SVivien Didelot }
2778855b1932SVivien Didelot 
2779b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = {
27804b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6097 */
278193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
278293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2783cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
2784b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
27857e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
27867e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
278708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
27887f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
278996a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
2790ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
279156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2792601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
279356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
2794ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
27950898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
2796c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
27979dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
27986c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
27992d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
2800a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
280140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2802dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
2803dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
2804052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
2805fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
2806fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
2807fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
280851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
28099e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
2810a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
2811a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
281217e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
28139e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
2814f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
28150ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
28166c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
2817b3469dd8SVivien Didelot };
2818b3469dd8SVivien Didelot 
2819b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = {
28204b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6095 */
282193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
282293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2823b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
28247e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
28257e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
282608ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
28277f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
282896a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
282956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
2830601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
2831a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
28326c422e34SRussell King 	.port_link_state = mv88e6185_port_link_state,
28332d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
2834a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
283540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2836dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
2837dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
2838052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
283951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
2840a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
2841a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
284217e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
2843f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
28440ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
28456c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
2846b3469dd8SVivien Didelot };
2847b3469dd8SVivien Didelot 
28487d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = {
284915da3cc8SStefan Eichenberger 	/* MV88E6XXX_FAMILY_6097 */
285093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
285193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2852cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
28537d381a02SStefan Eichenberger 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
28547d381a02SStefan Eichenberger 	.phy_read = mv88e6xxx_g2_smi_phy_read,
28557d381a02SStefan Eichenberger 	.phy_write = mv88e6xxx_g2_smi_phy_write,
28567d381a02SStefan Eichenberger 	.port_set_link = mv88e6xxx_port_set_link,
28577d381a02SStefan Eichenberger 	.port_set_duplex = mv88e6xxx_port_set_duplex,
28587d381a02SStefan Eichenberger 	.port_set_speed = mv88e6185_port_set_speed,
2859ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
286056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2861601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
286256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
2863cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2864ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
28650898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
2866c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
28679dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
28686c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
28692d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
28707d381a02SStefan Eichenberger 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
287140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
28727d381a02SStefan Eichenberger 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
28737d381a02SStefan Eichenberger 	.stats_get_strings = mv88e6095_stats_get_strings,
28747d381a02SStefan Eichenberger 	.stats_get_stats = mv88e6095_stats_get_stats,
2875fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
2876fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
287791eaa475SVolodymyr Bendiuga 	.watchdog_ops = &mv88e6097_watchdog_ops,
287851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
28799e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
288017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
28819e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
2882f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
28830ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
28846c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
28857d381a02SStefan Eichenberger };
28867d381a02SStefan Eichenberger 
2887b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = {
28884b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
288993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
289093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2891cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
2892b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2893ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
2894ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
289508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
28967f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
289796a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
289856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
2899601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2900c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
29019dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
29026c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
29032d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
29040ac64c39SAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
290540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2906dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
2907dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
2908052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
2909fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
2910fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
2911fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
291251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
29139e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
291417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
2915f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
29160ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
29176c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
2918b3469dd8SVivien Didelot };
2919b3469dd8SVivien Didelot 
2920b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = {
29214b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
292293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
292393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2924b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
29257e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
29267e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
292708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
29287f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
292996a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
2930ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
293156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2932601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
293356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
2934a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
2935cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2936ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
29370898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
293854186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
29396c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
29402d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
2941a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
294240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2943dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
2944dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
2945052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
2946fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
2947fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
2948fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
294951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
2950a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
295102317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
2952a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
295317e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
2954f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
29550ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
29566c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
2957b3469dd8SVivien Didelot };
2958b3469dd8SVivien Didelot 
2959990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = {
2960990e27b0SVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
296193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
296293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2963cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
2964990e27b0SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
2965990e27b0SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
2966990e27b0SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2967990e27b0SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
2968990e27b0SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
2969990e27b0SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
2970990e27b0SVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
2971990e27b0SVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
297226422340SMarek Behún 	.port_set_speed = mv88e6341_port_set_speed,
29737cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
2974990e27b0SVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
2975990e27b0SVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2976990e27b0SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2977990e27b0SVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
2978cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2979990e27b0SVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
29800898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
2981990e27b0SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2982990e27b0SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
29836c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
29842d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
2985990e27b0SVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
298640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2987990e27b0SVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
2988990e27b0SVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
2989990e27b0SVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
2990fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
2991fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
2992990e27b0SVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
2993990e27b0SVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
29949e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
2995990e27b0SVivien Didelot 	.reset = mv88e6352_g1_reset,
2996f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
29970ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
29986751e7c6SAndrew Lunn 	.serdes_power = mv88e6341_serdes_power,
2999a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
3000e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
3001990e27b0SVivien Didelot };
3002990e27b0SVivien Didelot 
3003b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = {
30044b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
300593e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
300693e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3007cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3008b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3009ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3010ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
301108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
30127f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
301396a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3014ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
301556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3016601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
301756995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3018cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3019ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
30200898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3021c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
30229dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
30236c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
30242d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3025a6da21bbSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
302640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3027dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3028dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3029052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3030fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3031fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3032fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
303351c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
30349e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
303517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3036f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
30370ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3038a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3039dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
30406c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3041b3469dd8SVivien Didelot };
3042b3469dd8SVivien Didelot 
3043b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = {
30444b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
304593e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
304693e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3047cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3048b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3049efb3e74dSAndrew Lunn 	.phy_read = mv88e6165_phy_read,
3050efb3e74dSAndrew Lunn 	.phy_write = mv88e6165_phy_write,
305108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
30527f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
305396a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3054c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
30559dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
30566c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
30572d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3058a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
305940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3060dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3061dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3062052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3063fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3064fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3065fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
306651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
30679e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
306817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3069f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
30700ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3071a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3072dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
30736c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3074b3469dd8SVivien Didelot };
3075b3469dd8SVivien Didelot 
3076b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = {
30774b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
307893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
307993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3080cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3081b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3082b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3083b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
308408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
30857f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
308694d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
308796a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3088ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
308956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3090601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
309156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3092cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3093ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
30940898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3095c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
30969dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
30976c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
30982d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3099a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
310040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3101dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3102dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3103052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3104fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3105fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3106fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
310751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
31089e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
310917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3110f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
31110ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
31126c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3113b3469dd8SVivien Didelot };
3114b3469dd8SVivien Didelot 
3115b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = {
31164b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
311793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
311893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3119cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3120ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3121ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3122b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3123b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3124b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
312508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
31267f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3127a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
312896a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3129ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
313056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3131601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
313256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3133cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3134ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
31350898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3136c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
31379dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
31386c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
31392d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3140a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
314140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3142dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3143dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3144052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3145fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3146fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3147fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
314851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
31499e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
315017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
31519e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
3152f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
31530ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
31546d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
3155a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
31566c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3157b3469dd8SVivien Didelot };
3158b3469dd8SVivien Didelot 
3159b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = {
31604b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
316193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
316293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3163cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3164b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3165b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3166b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
316708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
31687f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
316994d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
317096a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3171ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
317256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3173601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
317456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3175cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3176ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
31770898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3178c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
31799dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
31806c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
31812d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3182a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
318340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3184dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3185dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3186052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3187fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3188fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3189fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
319051c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
31919e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
319217e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3193f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
31940ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
31956c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3196b3469dd8SVivien Didelot };
3197b3469dd8SVivien Didelot 
3198b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = {
31994b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
320093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
320193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3202cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3203ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3204ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3205b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3206b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3207b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
320808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
32097f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3210a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
321196a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3212ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
321356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3214601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
321556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3216cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3217ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
32180898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3219c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
32209dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
32216c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
32222d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3223a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
322440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3225dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3226dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3227052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3228fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3229fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3230fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
323151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
32329e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
323317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
32349e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
3235f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
32360ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
32376d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
32384382172fSAndrew Lunn 	.serdes_irq_setup = mv88e6352_serdes_irq_setup,
32394382172fSAndrew Lunn 	.serdes_irq_free = mv88e6352_serdes_irq_free,
3240a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
32416c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3242b3469dd8SVivien Didelot };
3243b3469dd8SVivien Didelot 
3244b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = {
32454b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
324693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
324793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3248b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
32497e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
32507e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
325108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
32527f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
325396a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
325456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3255601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
3256ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
3257a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
325854186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
32596c422e34SRussell King 	.port_link_state = mv88e6185_port_link_state,
32602d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3261a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
326240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3263dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3264dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3265052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3266fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3267fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3268fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
326951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
327002317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3271a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3272a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
327317e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3274f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
32750ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
32766c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3277b3469dd8SVivien Didelot };
3278b3469dd8SVivien Didelot 
32791a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = {
32804b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3281ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3282cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
328398fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
328498fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
32851a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
32861a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
32871a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
32881a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
32891a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
32901a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
32911a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
32927cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
3293ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
329456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3295601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
329656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
32970898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3298c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
32999dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
33006c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
33012d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3302fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
330379523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3304de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3305dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3306dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3307e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3308fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3309fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
331061303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
33116e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
33129e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
331317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
33149e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3315931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3316931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
33176335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
3318efd1ba6aSAndrew Lunn 	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
3319efd1ba6aSAndrew Lunn 	.serdes_irq_free = mv88e6390_serdes_irq_free,
3320a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
33216c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
33221a3b39ecSAndrew Lunn };
33231a3b39ecSAndrew Lunn 
33241a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = {
33254b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3326ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3327cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
332898fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
332998fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
33301a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
33311a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
33321a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
33331a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
33341a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
33351a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
33361a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390x_port_set_speed,
33377cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
3338ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
333956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3340601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
334156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
33420898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3343c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
33449dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
33456c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
33462d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3347fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
334879523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3349de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3350dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3351dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3352e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3353fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3354fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
335561303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
33566e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
33579e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
335817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
33599e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3360931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3361931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
336207ffbd74SAndrew Lunn 	.serdes_power = mv88e6390x_serdes_power,
33632defda1fSAndrew Lunn 	.serdes_irq_setup = mv88e6390x_serdes_irq_setup,
33642defda1fSAndrew Lunn 	.serdes_irq_free = mv88e6390x_serdes_irq_free,
3365a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
33666c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
33671a3b39ecSAndrew Lunn };
33681a3b39ecSAndrew Lunn 
33691a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = {
33704b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3371ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3372cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
337398fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
337498fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
33751a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
33761a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
33771a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
33781a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
33791a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
33801a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
33811a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
33827cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
3383ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
338456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3385601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
338656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
33870898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3388c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
33899dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
33906c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
33912d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3392fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
339379523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3394de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3395dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3396dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3397e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3398fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3399fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
340061303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
34016e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
34029e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
340317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
34049e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3405931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3406931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
34076335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
3408efd1ba6aSAndrew Lunn 	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
3409efd1ba6aSAndrew Lunn 	.serdes_irq_free = mv88e6390_serdes_irq_free,
34106d2ac8eeSAndrew Lunn 	.avb_ops = &mv88e6390_avb_ops,
34116d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
34126c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
34131a3b39ecSAndrew Lunn };
34141a3b39ecSAndrew Lunn 
3415b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = {
34164b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
341793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
341893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3419cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3420ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3421ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3422b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3423b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3424b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
342508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
34267f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3427a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
342896a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3429ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
343056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3431601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
343256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3433cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3434ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
34350898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3436c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
34379dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34386c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
34392d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3440a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
344140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3442dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3443dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3444052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3445fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3446fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3447fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
344851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
34499e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
345017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
34519e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
3452f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
34530ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
34546d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
34554382172fSAndrew Lunn 	.serdes_irq_setup = mv88e6352_serdes_irq_setup,
34564382172fSAndrew Lunn 	.serdes_irq_free = mv88e6352_serdes_irq_free,
3457a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
34580d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
34596d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
34606c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3461b3469dd8SVivien Didelot };
3462b3469dd8SVivien Didelot 
34631f71836fSRasmus Villemoes static const struct mv88e6xxx_ops mv88e6250_ops = {
34641f71836fSRasmus Villemoes 	/* MV88E6XXX_FAMILY_6250 */
34651f71836fSRasmus Villemoes 	.ieee_pri_map = mv88e6250_g1_ieee_pri_map,
34661f71836fSRasmus Villemoes 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
34671f71836fSRasmus Villemoes 	.irl_init_all = mv88e6352_g2_irl_init_all,
34681f71836fSRasmus Villemoes 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
34691f71836fSRasmus Villemoes 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
34701f71836fSRasmus Villemoes 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
34711f71836fSRasmus Villemoes 	.phy_read = mv88e6xxx_g2_smi_phy_read,
34721f71836fSRasmus Villemoes 	.phy_write = mv88e6xxx_g2_smi_phy_write,
34731f71836fSRasmus Villemoes 	.port_set_link = mv88e6xxx_port_set_link,
34741f71836fSRasmus Villemoes 	.port_set_duplex = mv88e6xxx_port_set_duplex,
34751f71836fSRasmus Villemoes 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
34761f71836fSRasmus Villemoes 	.port_set_speed = mv88e6250_port_set_speed,
34771f71836fSRasmus Villemoes 	.port_tag_remap = mv88e6095_port_tag_remap,
34781f71836fSRasmus Villemoes 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
34791f71836fSRasmus Villemoes 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
34801f71836fSRasmus Villemoes 	.port_set_ether_type = mv88e6351_port_set_ether_type,
34811f71836fSRasmus Villemoes 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
34821f71836fSRasmus Villemoes 	.port_pause_limit = mv88e6097_port_pause_limit,
34831f71836fSRasmus Villemoes 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34841f71836fSRasmus Villemoes 	.port_link_state = mv88e6250_port_link_state,
34851f71836fSRasmus Villemoes 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
34861f71836fSRasmus Villemoes 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
34871f71836fSRasmus Villemoes 	.stats_get_sset_count = mv88e6250_stats_get_sset_count,
34881f71836fSRasmus Villemoes 	.stats_get_strings = mv88e6250_stats_get_strings,
34891f71836fSRasmus Villemoes 	.stats_get_stats = mv88e6250_stats_get_stats,
34901f71836fSRasmus Villemoes 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
34911f71836fSRasmus Villemoes 	.set_egress_port = mv88e6095_g1_set_egress_port,
34921f71836fSRasmus Villemoes 	.watchdog_ops = &mv88e6250_watchdog_ops,
34931f71836fSRasmus Villemoes 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
34941f71836fSRasmus Villemoes 	.pot_clear = mv88e6xxx_g2_pot_clear,
34951f71836fSRasmus Villemoes 	.reset = mv88e6250_g1_reset,
34961f71836fSRasmus Villemoes 	.vtu_getnext = mv88e6250_g1_vtu_getnext,
34971f71836fSRasmus Villemoes 	.vtu_loadpurge = mv88e6250_g1_vtu_loadpurge,
34981f71836fSRasmus Villemoes 	.phylink_validate = mv88e6065_phylink_validate,
34991f71836fSRasmus Villemoes };
35001f71836fSRasmus Villemoes 
35011a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = {
35024b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3503ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3504cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
350598fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
350698fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
35071a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
35081a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
35091a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
35101a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
35111a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
35121a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
35131a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
35147cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
3515ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
351656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3517601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
351856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
35190898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3520c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
35219dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35226c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
35232d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3524fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
352579523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3526de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3527dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3528dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3529e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3530fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3531fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
353261303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
35336e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
35349e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
353517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
35369e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3537931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3538931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
35396335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
3540efd1ba6aSAndrew Lunn 	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
3541efd1ba6aSAndrew Lunn 	.serdes_irq_free = mv88e6390_serdes_irq_free,
3542a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
35430d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
35446d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
35456c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
35461a3b39ecSAndrew Lunn };
35471a3b39ecSAndrew Lunn 
3548b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = {
35494b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6320 */
355093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
355193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3552cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3553ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3554ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3555b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3556b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3557b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
355808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
35597f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
356096a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3561ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
356256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3563601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
356456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3565cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3566ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
35670898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3568c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
35699dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35706c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
35712d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3572a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
357340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3574dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3575dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3576052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
3577fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3578fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
35799c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
358051c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
35819e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
358217e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3583f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
35840ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
3585a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
35860d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
35876d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
35886c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3589b3469dd8SVivien Didelot };
3590b3469dd8SVivien Didelot 
3591b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = {
3592bd807204SVivien Didelot 	/* MV88E6XXX_FAMILY_6320 */
359393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
359493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3595cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3596ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3597ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3598b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3599b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3600b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
360108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
36027f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
360396a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3604ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
360556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3606601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
360756995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3608cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3609ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36100898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3611c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36129dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36136c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
36142d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3615a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
361640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3617dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3618dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3619052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
3620fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3621fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
36229c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
362317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3624f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
36250ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
3626a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
36270d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
36286d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
36296c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3630b3469dd8SVivien Didelot };
3631b3469dd8SVivien Didelot 
363216e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = {
363316e329aeSVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
363493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
363593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3636cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
363716e329aeSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
363816e329aeSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
363916e329aeSVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
364016e329aeSVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
364116e329aeSVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
364216e329aeSVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
364316e329aeSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
364416e329aeSVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
364526422340SMarek Behún 	.port_set_speed = mv88e6341_port_set_speed,
36467cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
364716e329aeSVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
364816e329aeSVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
364916e329aeSVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
365016e329aeSVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3651cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
365216e329aeSVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36530898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
365416e329aeSVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
365516e329aeSVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36566c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
36572d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
365816e329aeSVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
365940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
366016e329aeSVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
366116e329aeSVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
366216e329aeSVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
3663fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3664fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
366516e329aeSVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
366616e329aeSVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
36679e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
366816e329aeSVivien Didelot 	.reset = mv88e6352_g1_reset,
3669f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
36700ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
36716751e7c6SAndrew Lunn 	.serdes_power = mv88e6341_serdes_power,
3672a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
36730d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
36746d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
3675e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
367616e329aeSVivien Didelot };
367716e329aeSVivien Didelot 
3678b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = {
36794b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
368093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
368193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3682cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3683b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3684b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3685b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
368608ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
36877f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
368894d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
368996a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3690ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
369156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3692601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
369356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3694cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3695ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36960898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3697c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36989dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36996c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
37002d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3701a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
370240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3703dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3704dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3705052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3706fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3707fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3708fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
370951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
37109e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
371117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3712f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37130ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37146c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3715b3469dd8SVivien Didelot };
3716b3469dd8SVivien Didelot 
3717b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = {
37184b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
371993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
372093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3721cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3722b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3723b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3724b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
372508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
37267f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
372794d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
372896a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3729ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
373056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3731601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
373256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3733cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3734ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37350898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3736c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
37379dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37386c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
37392d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3740a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
374140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3742dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3743dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3744052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3745fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3746fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3747fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
374851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
37499e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
375017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3751f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37520ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37530d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
37546d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
37556c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3756b3469dd8SVivien Didelot };
3757b3469dd8SVivien Didelot 
3758b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = {
37594b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
376093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
376193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3762cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3763ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3764ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3765b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3766b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3767b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
376808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
37697f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3770a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
377196a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3772ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
377356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3774601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
377556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3776cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3777ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37780898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3779c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
37809dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37816c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
37822d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3783a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
378440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3785dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3786dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3787052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3788fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3789fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3790fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
379151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
37929e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
379317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
37949e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
3795f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37960ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37976d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
37984382172fSAndrew Lunn 	.serdes_irq_setup = mv88e6352_serdes_irq_setup,
37994382172fSAndrew Lunn 	.serdes_irq_free = mv88e6352_serdes_irq_free,
3800a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
38010d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
38026d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
3803cda9f4aaSAndrew Lunn 	.serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
3804cda9f4aaSAndrew Lunn 	.serdes_get_strings = mv88e6352_serdes_get_strings,
3805cda9f4aaSAndrew Lunn 	.serdes_get_stats = mv88e6352_serdes_get_stats,
38066c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3807b3469dd8SVivien Didelot };
3808b3469dd8SVivien Didelot 
38091a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = {
38104b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3811ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3812cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
381398fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
381498fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
38151a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
38161a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
38171a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
38181a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
38191a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
38201a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
38211a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
38227cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
3823ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
382456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3825601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
382656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3827cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3828ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
38290898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3830c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38319dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38326c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
38332d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3834fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
383579523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3836de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3837dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3838dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3839e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3840fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3841fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
384261303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
38436e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
38449e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
384517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
38469e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3847931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3848931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
38496335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
3850efd1ba6aSAndrew Lunn 	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
3851efd1ba6aSAndrew Lunn 	.serdes_irq_free = mv88e6390_serdes_irq_free,
3852a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
38530d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
38546d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
38556c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
38561a3b39ecSAndrew Lunn };
38571a3b39ecSAndrew Lunn 
38581a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = {
38594b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3860ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3861cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
386298fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
386398fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
38641a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
38651a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
38661a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
38671a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
38681a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
38691a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
38701a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390x_port_set_speed,
38717cbbee05SAndrew Lunn 	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
3872ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
387356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3874601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
387556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3876cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3877ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
38780898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3879c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38809dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38816c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
38822d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3883b3dce4daSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
388479523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3885de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3886dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3887dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3888e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3889fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3890fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
389161303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
38926e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
38939e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
389417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
38959e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3896931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3897931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
389807ffbd74SAndrew Lunn 	.serdes_power = mv88e6390x_serdes_power,
38992defda1fSAndrew Lunn 	.serdes_irq_setup = mv88e6390x_serdes_irq_setup,
39002defda1fSAndrew Lunn 	.serdes_irq_free = mv88e6390x_serdes_irq_free,
3901a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
39020d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
39036d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
39046c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
39051a3b39ecSAndrew Lunn };
39061a3b39ecSAndrew Lunn 
3907fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3908fad09c73SVivien Didelot 	[MV88E6085] = {
3909107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
3910fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6097,
3911fad09c73SVivien Didelot 		.name = "Marvell 88E6085",
3912fad09c73SVivien Didelot 		.num_databases = 4096,
3913fad09c73SVivien Didelot 		.num_ports = 10,
3914bc393155SAndrew Lunn 		.num_internal_phys = 5,
39153cf3c846SVivien Didelot 		.max_vid = 4095,
3916fad09c73SVivien Didelot 		.port_base_addr = 0x10,
39179255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
3918a935c052SVivien Didelot 		.global1_addr = 0x1b,
39199069c13aSVivien Didelot 		.global2_addr = 0x1c,
3920acddbd21SVivien Didelot 		.age_time_coeff = 15000,
3921dc30c35bSAndrew Lunn 		.g1_irqs = 8,
3922d6c5e6afSVivien Didelot 		.g2_irqs = 10,
3923e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
3924f3645652SVivien Didelot 		.pvt = true,
3925b3e05aa1SVivien Didelot 		.multi_chip = true,
3926443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
3927b3469dd8SVivien Didelot 		.ops = &mv88e6085_ops,
3928fad09c73SVivien Didelot 	},
3929fad09c73SVivien Didelot 
3930fad09c73SVivien Didelot 	[MV88E6095] = {
3931107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095,
3932fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6095,
3933fad09c73SVivien Didelot 		.name = "Marvell 88E6095/88E6095F",
3934fad09c73SVivien Didelot 		.num_databases = 256,
3935fad09c73SVivien Didelot 		.num_ports = 11,
3936bc393155SAndrew Lunn 		.num_internal_phys = 0,
39373cf3c846SVivien Didelot 		.max_vid = 4095,
3938fad09c73SVivien Didelot 		.port_base_addr = 0x10,
39399255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
3940a935c052SVivien Didelot 		.global1_addr = 0x1b,
39419069c13aSVivien Didelot 		.global2_addr = 0x1c,
3942acddbd21SVivien Didelot 		.age_time_coeff = 15000,
3943dc30c35bSAndrew Lunn 		.g1_irqs = 8,
3944e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
3945b3e05aa1SVivien Didelot 		.multi_chip = true,
3946443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
3947b3469dd8SVivien Didelot 		.ops = &mv88e6095_ops,
3948fad09c73SVivien Didelot 	},
3949fad09c73SVivien Didelot 
39507d381a02SStefan Eichenberger 	[MV88E6097] = {
3951107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097,
39527d381a02SStefan Eichenberger 		.family = MV88E6XXX_FAMILY_6097,
39537d381a02SStefan Eichenberger 		.name = "Marvell 88E6097/88E6097F",
39547d381a02SStefan Eichenberger 		.num_databases = 4096,
39557d381a02SStefan Eichenberger 		.num_ports = 11,
3956bc393155SAndrew Lunn 		.num_internal_phys = 8,
39573cf3c846SVivien Didelot 		.max_vid = 4095,
39587d381a02SStefan Eichenberger 		.port_base_addr = 0x10,
39599255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
39607d381a02SStefan Eichenberger 		.global1_addr = 0x1b,
39619069c13aSVivien Didelot 		.global2_addr = 0x1c,
39627d381a02SStefan Eichenberger 		.age_time_coeff = 15000,
3963c534178bSStefan Eichenberger 		.g1_irqs = 8,
3964d6c5e6afSVivien Didelot 		.g2_irqs = 10,
3965e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
3966f3645652SVivien Didelot 		.pvt = true,
3967b3e05aa1SVivien Didelot 		.multi_chip = true,
39682bfcfcd3SStefan Eichenberger 		.tag_protocol = DSA_TAG_PROTO_EDSA,
39697d381a02SStefan Eichenberger 		.ops = &mv88e6097_ops,
39707d381a02SStefan Eichenberger 	},
39717d381a02SStefan Eichenberger 
3972fad09c73SVivien Didelot 	[MV88E6123] = {
3973107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123,
3974fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
3975fad09c73SVivien Didelot 		.name = "Marvell 88E6123",
3976fad09c73SVivien Didelot 		.num_databases = 4096,
3977fad09c73SVivien Didelot 		.num_ports = 3,
3978bc393155SAndrew Lunn 		.num_internal_phys = 5,
39793cf3c846SVivien Didelot 		.max_vid = 4095,
3980fad09c73SVivien Didelot 		.port_base_addr = 0x10,
39819255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
3982a935c052SVivien Didelot 		.global1_addr = 0x1b,
39839069c13aSVivien Didelot 		.global2_addr = 0x1c,
3984acddbd21SVivien Didelot 		.age_time_coeff = 15000,
3985dc30c35bSAndrew Lunn 		.g1_irqs = 9,
3986d6c5e6afSVivien Didelot 		.g2_irqs = 10,
3987e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
3988f3645652SVivien Didelot 		.pvt = true,
3989b3e05aa1SVivien Didelot 		.multi_chip = true,
39905ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
3991b3469dd8SVivien Didelot 		.ops = &mv88e6123_ops,
3992fad09c73SVivien Didelot 	},
3993fad09c73SVivien Didelot 
3994fad09c73SVivien Didelot 	[MV88E6131] = {
3995107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131,
3996fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
3997fad09c73SVivien Didelot 		.name = "Marvell 88E6131",
3998fad09c73SVivien Didelot 		.num_databases = 256,
3999fad09c73SVivien Didelot 		.num_ports = 8,
4000bc393155SAndrew Lunn 		.num_internal_phys = 0,
40013cf3c846SVivien Didelot 		.max_vid = 4095,
4002fad09c73SVivien Didelot 		.port_base_addr = 0x10,
40039255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4004a935c052SVivien Didelot 		.global1_addr = 0x1b,
40059069c13aSVivien Didelot 		.global2_addr = 0x1c,
4006acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4007dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4008e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4009b3e05aa1SVivien Didelot 		.multi_chip = true,
4010443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4011b3469dd8SVivien Didelot 		.ops = &mv88e6131_ops,
4012fad09c73SVivien Didelot 	},
4013fad09c73SVivien Didelot 
4014990e27b0SVivien Didelot 	[MV88E6141] = {
4015107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141,
4016990e27b0SVivien Didelot 		.family = MV88E6XXX_FAMILY_6341,
401779a68b26SUwe Kleine-König 		.name = "Marvell 88E6141",
4018990e27b0SVivien Didelot 		.num_databases = 4096,
4019990e27b0SVivien Didelot 		.num_ports = 6,
4020bc393155SAndrew Lunn 		.num_internal_phys = 5,
4021a73ccd61SBrandon Streiff 		.num_gpio = 11,
40223cf3c846SVivien Didelot 		.max_vid = 4095,
4023990e27b0SVivien Didelot 		.port_base_addr = 0x10,
40249255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
4025990e27b0SVivien Didelot 		.global1_addr = 0x1b,
40269069c13aSVivien Didelot 		.global2_addr = 0x1c,
4027990e27b0SVivien Didelot 		.age_time_coeff = 3750,
4028990e27b0SVivien Didelot 		.atu_move_port_mask = 0x1f,
4029adfccf11SAndrew Lunn 		.g1_irqs = 9,
4030d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4031f3645652SVivien Didelot 		.pvt = true,
4032b3e05aa1SVivien Didelot 		.multi_chip = true,
4033990e27b0SVivien Didelot 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4034990e27b0SVivien Didelot 		.ops = &mv88e6141_ops,
4035990e27b0SVivien Didelot 	},
4036990e27b0SVivien Didelot 
4037fad09c73SVivien Didelot 	[MV88E6161] = {
4038107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161,
4039fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4040fad09c73SVivien Didelot 		.name = "Marvell 88E6161",
4041fad09c73SVivien Didelot 		.num_databases = 4096,
4042fad09c73SVivien Didelot 		.num_ports = 6,
4043bc393155SAndrew Lunn 		.num_internal_phys = 5,
40443cf3c846SVivien Didelot 		.max_vid = 4095,
4045fad09c73SVivien Didelot 		.port_base_addr = 0x10,
40469255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4047a935c052SVivien Didelot 		.global1_addr = 0x1b,
40489069c13aSVivien Didelot 		.global2_addr = 0x1c,
4049acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4050dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4051d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4052e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4053f3645652SVivien Didelot 		.pvt = true,
4054b3e05aa1SVivien Didelot 		.multi_chip = true,
40555ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4056dfa54348SAndrew Lunn 		.ptp_support = true,
4057b3469dd8SVivien Didelot 		.ops = &mv88e6161_ops,
4058fad09c73SVivien Didelot 	},
4059fad09c73SVivien Didelot 
4060fad09c73SVivien Didelot 	[MV88E6165] = {
4061107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165,
4062fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4063fad09c73SVivien Didelot 		.name = "Marvell 88E6165",
4064fad09c73SVivien Didelot 		.num_databases = 4096,
4065fad09c73SVivien Didelot 		.num_ports = 6,
4066bc393155SAndrew Lunn 		.num_internal_phys = 0,
40673cf3c846SVivien Didelot 		.max_vid = 4095,
4068fad09c73SVivien Didelot 		.port_base_addr = 0x10,
40699255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4070a935c052SVivien Didelot 		.global1_addr = 0x1b,
40719069c13aSVivien Didelot 		.global2_addr = 0x1c,
4072acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4073dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4074d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4075e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4076f3645652SVivien Didelot 		.pvt = true,
4077b3e05aa1SVivien Didelot 		.multi_chip = true,
4078443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4079dfa54348SAndrew Lunn 		.ptp_support = true,
4080b3469dd8SVivien Didelot 		.ops = &mv88e6165_ops,
4081fad09c73SVivien Didelot 	},
4082fad09c73SVivien Didelot 
4083fad09c73SVivien Didelot 	[MV88E6171] = {
4084107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171,
4085fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4086fad09c73SVivien Didelot 		.name = "Marvell 88E6171",
4087fad09c73SVivien Didelot 		.num_databases = 4096,
4088fad09c73SVivien Didelot 		.num_ports = 7,
4089bc393155SAndrew Lunn 		.num_internal_phys = 5,
40903cf3c846SVivien Didelot 		.max_vid = 4095,
4091fad09c73SVivien Didelot 		.port_base_addr = 0x10,
40929255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4093a935c052SVivien Didelot 		.global1_addr = 0x1b,
40949069c13aSVivien Didelot 		.global2_addr = 0x1c,
4095acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4096dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4097d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4098e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4099f3645652SVivien Didelot 		.pvt = true,
4100b3e05aa1SVivien Didelot 		.multi_chip = true,
4101443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4102b3469dd8SVivien Didelot 		.ops = &mv88e6171_ops,
4103fad09c73SVivien Didelot 	},
4104fad09c73SVivien Didelot 
4105fad09c73SVivien Didelot 	[MV88E6172] = {
4106107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172,
4107fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4108fad09c73SVivien Didelot 		.name = "Marvell 88E6172",
4109fad09c73SVivien Didelot 		.num_databases = 4096,
4110fad09c73SVivien Didelot 		.num_ports = 7,
4111bc393155SAndrew Lunn 		.num_internal_phys = 5,
4112a73ccd61SBrandon Streiff 		.num_gpio = 15,
41133cf3c846SVivien Didelot 		.max_vid = 4095,
4114fad09c73SVivien Didelot 		.port_base_addr = 0x10,
41159255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4116a935c052SVivien Didelot 		.global1_addr = 0x1b,
41179069c13aSVivien Didelot 		.global2_addr = 0x1c,
4118acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4119dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4120d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4121e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4122f3645652SVivien Didelot 		.pvt = true,
4123b3e05aa1SVivien Didelot 		.multi_chip = true,
4124443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4125b3469dd8SVivien Didelot 		.ops = &mv88e6172_ops,
4126fad09c73SVivien Didelot 	},
4127fad09c73SVivien Didelot 
4128fad09c73SVivien Didelot 	[MV88E6175] = {
4129107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175,
4130fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4131fad09c73SVivien Didelot 		.name = "Marvell 88E6175",
4132fad09c73SVivien Didelot 		.num_databases = 4096,
4133fad09c73SVivien Didelot 		.num_ports = 7,
4134bc393155SAndrew Lunn 		.num_internal_phys = 5,
41353cf3c846SVivien Didelot 		.max_vid = 4095,
4136fad09c73SVivien Didelot 		.port_base_addr = 0x10,
41379255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4138a935c052SVivien Didelot 		.global1_addr = 0x1b,
41399069c13aSVivien Didelot 		.global2_addr = 0x1c,
4140acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4141dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4142d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4143e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4144f3645652SVivien Didelot 		.pvt = true,
4145b3e05aa1SVivien Didelot 		.multi_chip = true,
4146443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4147b3469dd8SVivien Didelot 		.ops = &mv88e6175_ops,
4148fad09c73SVivien Didelot 	},
4149fad09c73SVivien Didelot 
4150fad09c73SVivien Didelot 	[MV88E6176] = {
4151107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176,
4152fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4153fad09c73SVivien Didelot 		.name = "Marvell 88E6176",
4154fad09c73SVivien Didelot 		.num_databases = 4096,
4155fad09c73SVivien Didelot 		.num_ports = 7,
4156bc393155SAndrew Lunn 		.num_internal_phys = 5,
4157a73ccd61SBrandon Streiff 		.num_gpio = 15,
41583cf3c846SVivien Didelot 		.max_vid = 4095,
4159fad09c73SVivien Didelot 		.port_base_addr = 0x10,
41609255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4161a935c052SVivien Didelot 		.global1_addr = 0x1b,
41629069c13aSVivien Didelot 		.global2_addr = 0x1c,
4163acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4164dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4165d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4166e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4167f3645652SVivien Didelot 		.pvt = true,
4168b3e05aa1SVivien Didelot 		.multi_chip = true,
4169443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4170b3469dd8SVivien Didelot 		.ops = &mv88e6176_ops,
4171fad09c73SVivien Didelot 	},
4172fad09c73SVivien Didelot 
4173fad09c73SVivien Didelot 	[MV88E6185] = {
4174107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185,
4175fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
4176fad09c73SVivien Didelot 		.name = "Marvell 88E6185",
4177fad09c73SVivien Didelot 		.num_databases = 256,
4178fad09c73SVivien Didelot 		.num_ports = 10,
4179bc393155SAndrew Lunn 		.num_internal_phys = 0,
41803cf3c846SVivien Didelot 		.max_vid = 4095,
4181fad09c73SVivien Didelot 		.port_base_addr = 0x10,
41829255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4183a935c052SVivien Didelot 		.global1_addr = 0x1b,
41849069c13aSVivien Didelot 		.global2_addr = 0x1c,
4185acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4186dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4187e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4188b3e05aa1SVivien Didelot 		.multi_chip = true,
4189443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4190b3469dd8SVivien Didelot 		.ops = &mv88e6185_ops,
4191fad09c73SVivien Didelot 	},
4192fad09c73SVivien Didelot 
41931a3b39ecSAndrew Lunn 	[MV88E6190] = {
4194107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190,
41951a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
41961a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190",
41971a3b39ecSAndrew Lunn 		.num_databases = 4096,
41981a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
419995150f29SHeiner Kallweit 		.num_internal_phys = 9,
4200a73ccd61SBrandon Streiff 		.num_gpio = 16,
4201931d1822SVivien Didelot 		.max_vid = 8191,
42021a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
42039255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
42041a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
42059069c13aSVivien Didelot 		.global2_addr = 0x1c,
4206443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4207b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
42081a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4209d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4210f3645652SVivien Didelot 		.pvt = true,
4211b3e05aa1SVivien Didelot 		.multi_chip = true,
4212e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
42131a3b39ecSAndrew Lunn 		.ops = &mv88e6190_ops,
42141a3b39ecSAndrew Lunn 	},
42151a3b39ecSAndrew Lunn 
42161a3b39ecSAndrew Lunn 	[MV88E6190X] = {
4217107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X,
42181a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
42191a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190X",
42201a3b39ecSAndrew Lunn 		.num_databases = 4096,
42211a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
422295150f29SHeiner Kallweit 		.num_internal_phys = 9,
4223a73ccd61SBrandon Streiff 		.num_gpio = 16,
4224931d1822SVivien Didelot 		.max_vid = 8191,
42251a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
42269255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
42271a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
42289069c13aSVivien Didelot 		.global2_addr = 0x1c,
4229b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
42301a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4231d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4232e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4233f3645652SVivien Didelot 		.pvt = true,
4234b3e05aa1SVivien Didelot 		.multi_chip = true,
4235443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
42361a3b39ecSAndrew Lunn 		.ops = &mv88e6190x_ops,
42371a3b39ecSAndrew Lunn 	},
42381a3b39ecSAndrew Lunn 
42391a3b39ecSAndrew Lunn 	[MV88E6191] = {
4240107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191,
42411a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
42421a3b39ecSAndrew Lunn 		.name = "Marvell 88E6191",
42431a3b39ecSAndrew Lunn 		.num_databases = 4096,
42441a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
424595150f29SHeiner Kallweit 		.num_internal_phys = 9,
4246931d1822SVivien Didelot 		.max_vid = 8191,
42471a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
42489255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
42491a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
42509069c13aSVivien Didelot 		.global2_addr = 0x1c,
4251b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
4252443d5a1bSAndrew Lunn 		.g1_irqs = 9,
4253d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4254e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4255f3645652SVivien Didelot 		.pvt = true,
4256b3e05aa1SVivien Didelot 		.multi_chip = true,
4257443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
42582fa8d3afSBrandon Streiff 		.ptp_support = true,
42592cf4cefbSVivien Didelot 		.ops = &mv88e6191_ops,
42601a3b39ecSAndrew Lunn 	},
42611a3b39ecSAndrew Lunn 
4262fad09c73SVivien Didelot 	[MV88E6240] = {
4263107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240,
4264fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4265fad09c73SVivien Didelot 		.name = "Marvell 88E6240",
4266fad09c73SVivien Didelot 		.num_databases = 4096,
4267fad09c73SVivien Didelot 		.num_ports = 7,
4268bc393155SAndrew Lunn 		.num_internal_phys = 5,
4269a73ccd61SBrandon Streiff 		.num_gpio = 15,
42703cf3c846SVivien Didelot 		.max_vid = 4095,
4271fad09c73SVivien Didelot 		.port_base_addr = 0x10,
42729255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4273a935c052SVivien Didelot 		.global1_addr = 0x1b,
42749069c13aSVivien Didelot 		.global2_addr = 0x1c,
4275acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4276dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4277d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4278e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4279f3645652SVivien Didelot 		.pvt = true,
4280b3e05aa1SVivien Didelot 		.multi_chip = true,
4281443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
42822fa8d3afSBrandon Streiff 		.ptp_support = true,
4283b3469dd8SVivien Didelot 		.ops = &mv88e6240_ops,
4284fad09c73SVivien Didelot 	},
4285fad09c73SVivien Didelot 
42861f71836fSRasmus Villemoes 	[MV88E6250] = {
42871f71836fSRasmus Villemoes 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250,
42881f71836fSRasmus Villemoes 		.family = MV88E6XXX_FAMILY_6250,
42891f71836fSRasmus Villemoes 		.name = "Marvell 88E6250",
42901f71836fSRasmus Villemoes 		.num_databases = 64,
42911f71836fSRasmus Villemoes 		.num_ports = 7,
42921f71836fSRasmus Villemoes 		.num_internal_phys = 5,
42931f71836fSRasmus Villemoes 		.max_vid = 4095,
42941f71836fSRasmus Villemoes 		.port_base_addr = 0x08,
42951f71836fSRasmus Villemoes 		.phy_base_addr = 0x00,
42961f71836fSRasmus Villemoes 		.global1_addr = 0x0f,
42971f71836fSRasmus Villemoes 		.global2_addr = 0x07,
42981f71836fSRasmus Villemoes 		.age_time_coeff = 15000,
42991f71836fSRasmus Villemoes 		.g1_irqs = 9,
43001f71836fSRasmus Villemoes 		.g2_irqs = 10,
43011f71836fSRasmus Villemoes 		.atu_move_port_mask = 0xf,
43021f71836fSRasmus Villemoes 		.dual_chip = true,
43031f71836fSRasmus Villemoes 		.tag_protocol = DSA_TAG_PROTO_DSA,
43041f71836fSRasmus Villemoes 		.ops = &mv88e6250_ops,
43051f71836fSRasmus Villemoes 	},
43061f71836fSRasmus Villemoes 
43071a3b39ecSAndrew Lunn 	[MV88E6290] = {
4308107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
43091a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
43101a3b39ecSAndrew Lunn 		.name = "Marvell 88E6290",
43111a3b39ecSAndrew Lunn 		.num_databases = 4096,
43121a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
431395150f29SHeiner Kallweit 		.num_internal_phys = 9,
4314a73ccd61SBrandon Streiff 		.num_gpio = 16,
4315931d1822SVivien Didelot 		.max_vid = 8191,
43161a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
43179255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
43181a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
43199069c13aSVivien Didelot 		.global2_addr = 0x1c,
4320b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
43211a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4322d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4323e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4324f3645652SVivien Didelot 		.pvt = true,
4325b3e05aa1SVivien Didelot 		.multi_chip = true,
4326443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
43272fa8d3afSBrandon Streiff 		.ptp_support = true,
43281a3b39ecSAndrew Lunn 		.ops = &mv88e6290_ops,
43291a3b39ecSAndrew Lunn 	},
43301a3b39ecSAndrew Lunn 
4331fad09c73SVivien Didelot 	[MV88E6320] = {
4332107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320,
4333fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
4334fad09c73SVivien Didelot 		.name = "Marvell 88E6320",
4335fad09c73SVivien Didelot 		.num_databases = 4096,
4336fad09c73SVivien Didelot 		.num_ports = 7,
4337bc393155SAndrew Lunn 		.num_internal_phys = 5,
4338a73ccd61SBrandon Streiff 		.num_gpio = 15,
43393cf3c846SVivien Didelot 		.max_vid = 4095,
4340fad09c73SVivien Didelot 		.port_base_addr = 0x10,
43419255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4342a935c052SVivien Didelot 		.global1_addr = 0x1b,
43439069c13aSVivien Didelot 		.global2_addr = 0x1c,
4344acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4345dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4346bc393155SAndrew Lunn 		.g2_irqs = 10,
4347e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4348f3645652SVivien Didelot 		.pvt = true,
4349b3e05aa1SVivien Didelot 		.multi_chip = true,
4350443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
43512fa8d3afSBrandon Streiff 		.ptp_support = true,
4352b3469dd8SVivien Didelot 		.ops = &mv88e6320_ops,
4353fad09c73SVivien Didelot 	},
4354fad09c73SVivien Didelot 
4355fad09c73SVivien Didelot 	[MV88E6321] = {
4356107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321,
4357fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
4358fad09c73SVivien Didelot 		.name = "Marvell 88E6321",
4359fad09c73SVivien Didelot 		.num_databases = 4096,
4360fad09c73SVivien Didelot 		.num_ports = 7,
4361bc393155SAndrew Lunn 		.num_internal_phys = 5,
4362a73ccd61SBrandon Streiff 		.num_gpio = 15,
43633cf3c846SVivien Didelot 		.max_vid = 4095,
4364fad09c73SVivien Didelot 		.port_base_addr = 0x10,
43659255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4366a935c052SVivien Didelot 		.global1_addr = 0x1b,
43679069c13aSVivien Didelot 		.global2_addr = 0x1c,
4368acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4369dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4370bc393155SAndrew Lunn 		.g2_irqs = 10,
4371e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4372b3e05aa1SVivien Didelot 		.multi_chip = true,
4373443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
43742fa8d3afSBrandon Streiff 		.ptp_support = true,
4375b3469dd8SVivien Didelot 		.ops = &mv88e6321_ops,
4376fad09c73SVivien Didelot 	},
4377fad09c73SVivien Didelot 
4378a75961d0SGregory CLEMENT 	[MV88E6341] = {
4379107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
4380a75961d0SGregory CLEMENT 		.family = MV88E6XXX_FAMILY_6341,
4381a75961d0SGregory CLEMENT 		.name = "Marvell 88E6341",
4382a75961d0SGregory CLEMENT 		.num_databases = 4096,
4383bc393155SAndrew Lunn 		.num_internal_phys = 5,
4384a75961d0SGregory CLEMENT 		.num_ports = 6,
4385a73ccd61SBrandon Streiff 		.num_gpio = 11,
43863cf3c846SVivien Didelot 		.max_vid = 4095,
4387a75961d0SGregory CLEMENT 		.port_base_addr = 0x10,
43889255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
4389a75961d0SGregory CLEMENT 		.global1_addr = 0x1b,
43909069c13aSVivien Didelot 		.global2_addr = 0x1c,
4391a75961d0SGregory CLEMENT 		.age_time_coeff = 3750,
4392e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4393adfccf11SAndrew Lunn 		.g1_irqs = 9,
4394d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4395f3645652SVivien Didelot 		.pvt = true,
4396b3e05aa1SVivien Didelot 		.multi_chip = true,
4397a75961d0SGregory CLEMENT 		.tag_protocol = DSA_TAG_PROTO_EDSA,
43982fa8d3afSBrandon Streiff 		.ptp_support = true,
4399a75961d0SGregory CLEMENT 		.ops = &mv88e6341_ops,
4400a75961d0SGregory CLEMENT 	},
4401a75961d0SGregory CLEMENT 
4402fad09c73SVivien Didelot 	[MV88E6350] = {
4403107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350,
4404fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4405fad09c73SVivien Didelot 		.name = "Marvell 88E6350",
4406fad09c73SVivien Didelot 		.num_databases = 4096,
4407fad09c73SVivien Didelot 		.num_ports = 7,
4408bc393155SAndrew Lunn 		.num_internal_phys = 5,
44093cf3c846SVivien Didelot 		.max_vid = 4095,
4410fad09c73SVivien Didelot 		.port_base_addr = 0x10,
44119255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4412a935c052SVivien Didelot 		.global1_addr = 0x1b,
44139069c13aSVivien Didelot 		.global2_addr = 0x1c,
4414acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4415dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4416d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4417e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4418f3645652SVivien Didelot 		.pvt = true,
4419b3e05aa1SVivien Didelot 		.multi_chip = true,
4420443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4421b3469dd8SVivien Didelot 		.ops = &mv88e6350_ops,
4422fad09c73SVivien Didelot 	},
4423fad09c73SVivien Didelot 
4424fad09c73SVivien Didelot 	[MV88E6351] = {
4425107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351,
4426fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4427fad09c73SVivien Didelot 		.name = "Marvell 88E6351",
4428fad09c73SVivien Didelot 		.num_databases = 4096,
4429fad09c73SVivien Didelot 		.num_ports = 7,
4430bc393155SAndrew Lunn 		.num_internal_phys = 5,
44313cf3c846SVivien Didelot 		.max_vid = 4095,
4432fad09c73SVivien Didelot 		.port_base_addr = 0x10,
44339255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4434a935c052SVivien Didelot 		.global1_addr = 0x1b,
44359069c13aSVivien Didelot 		.global2_addr = 0x1c,
4436acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4437dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4438d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4439e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4440f3645652SVivien Didelot 		.pvt = true,
4441b3e05aa1SVivien Didelot 		.multi_chip = true,
4442443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4443b3469dd8SVivien Didelot 		.ops = &mv88e6351_ops,
4444fad09c73SVivien Didelot 	},
4445fad09c73SVivien Didelot 
4446fad09c73SVivien Didelot 	[MV88E6352] = {
4447107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352,
4448fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4449fad09c73SVivien Didelot 		.name = "Marvell 88E6352",
4450fad09c73SVivien Didelot 		.num_databases = 4096,
4451fad09c73SVivien Didelot 		.num_ports = 7,
4452bc393155SAndrew Lunn 		.num_internal_phys = 5,
4453a73ccd61SBrandon Streiff 		.num_gpio = 15,
44543cf3c846SVivien Didelot 		.max_vid = 4095,
4455fad09c73SVivien Didelot 		.port_base_addr = 0x10,
44569255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4457a935c052SVivien Didelot 		.global1_addr = 0x1b,
44589069c13aSVivien Didelot 		.global2_addr = 0x1c,
4459acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4460dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4461d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4462e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4463f3645652SVivien Didelot 		.pvt = true,
4464b3e05aa1SVivien Didelot 		.multi_chip = true,
4465443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
44662fa8d3afSBrandon Streiff 		.ptp_support = true,
4467b3469dd8SVivien Didelot 		.ops = &mv88e6352_ops,
4468fad09c73SVivien Didelot 	},
44691a3b39ecSAndrew Lunn 	[MV88E6390] = {
4470107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
44711a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
44721a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390",
44731a3b39ecSAndrew Lunn 		.num_databases = 4096,
44741a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
447595150f29SHeiner Kallweit 		.num_internal_phys = 9,
4476a73ccd61SBrandon Streiff 		.num_gpio = 16,
4477931d1822SVivien Didelot 		.max_vid = 8191,
44781a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
44799255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
44801a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
44819069c13aSVivien Didelot 		.global2_addr = 0x1c,
4482b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
44831a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4484d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4485e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4486f3645652SVivien Didelot 		.pvt = true,
4487b3e05aa1SVivien Didelot 		.multi_chip = true,
4488443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
44892fa8d3afSBrandon Streiff 		.ptp_support = true,
44901a3b39ecSAndrew Lunn 		.ops = &mv88e6390_ops,
44911a3b39ecSAndrew Lunn 	},
44921a3b39ecSAndrew Lunn 	[MV88E6390X] = {
4493107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X,
44941a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
44951a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390X",
44961a3b39ecSAndrew Lunn 		.num_databases = 4096,
44971a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
449895150f29SHeiner Kallweit 		.num_internal_phys = 9,
4499a73ccd61SBrandon Streiff 		.num_gpio = 16,
4500931d1822SVivien Didelot 		.max_vid = 8191,
45011a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
45029255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
45031a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
45049069c13aSVivien Didelot 		.global2_addr = 0x1c,
4505b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
45061a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4507d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4508e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4509f3645652SVivien Didelot 		.pvt = true,
4510b3e05aa1SVivien Didelot 		.multi_chip = true,
4511443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
45122fa8d3afSBrandon Streiff 		.ptp_support = true,
45131a3b39ecSAndrew Lunn 		.ops = &mv88e6390x_ops,
45141a3b39ecSAndrew Lunn 	},
4515fad09c73SVivien Didelot };
4516fad09c73SVivien Didelot 
4517fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
4518fad09c73SVivien Didelot {
4519fad09c73SVivien Didelot 	int i;
4520fad09c73SVivien Didelot 
4521fad09c73SVivien Didelot 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
4522fad09c73SVivien Didelot 		if (mv88e6xxx_table[i].prod_num == prod_num)
4523fad09c73SVivien Didelot 			return &mv88e6xxx_table[i];
4524fad09c73SVivien Didelot 
4525fad09c73SVivien Didelot 	return NULL;
4526fad09c73SVivien Didelot }
4527fad09c73SVivien Didelot 
4528fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
4529fad09c73SVivien Didelot {
4530fad09c73SVivien Didelot 	const struct mv88e6xxx_info *info;
45318f6345b2SVivien Didelot 	unsigned int prod_num, rev;
45328f6345b2SVivien Didelot 	u16 id;
45338f6345b2SVivien Didelot 	int err;
4534fad09c73SVivien Didelot 
45358f6345b2SVivien Didelot 	mutex_lock(&chip->reg_lock);
4536107fcc10SVivien Didelot 	err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
45378f6345b2SVivien Didelot 	mutex_unlock(&chip->reg_lock);
45388f6345b2SVivien Didelot 	if (err)
45398f6345b2SVivien Didelot 		return err;
4540fad09c73SVivien Didelot 
4541107fcc10SVivien Didelot 	prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK;
4542107fcc10SVivien Didelot 	rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK;
4543fad09c73SVivien Didelot 
4544fad09c73SVivien Didelot 	info = mv88e6xxx_lookup_info(prod_num);
4545fad09c73SVivien Didelot 	if (!info)
4546fad09c73SVivien Didelot 		return -ENODEV;
4547fad09c73SVivien Didelot 
4548fad09c73SVivien Didelot 	/* Update the compatible info with the probed one */
4549fad09c73SVivien Didelot 	chip->info = info;
4550fad09c73SVivien Didelot 
4551ca070c10SVivien Didelot 	err = mv88e6xxx_g2_require(chip);
4552ca070c10SVivien Didelot 	if (err)
4553ca070c10SVivien Didelot 		return err;
4554ca070c10SVivien Didelot 
4555fad09c73SVivien Didelot 	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
4556fad09c73SVivien Didelot 		 chip->info->prod_num, chip->info->name, rev);
4557fad09c73SVivien Didelot 
4558fad09c73SVivien Didelot 	return 0;
4559fad09c73SVivien Didelot }
4560fad09c73SVivien Didelot 
4561fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
4562fad09c73SVivien Didelot {
4563fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
4564fad09c73SVivien Didelot 
4565fad09c73SVivien Didelot 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
4566fad09c73SVivien Didelot 	if (!chip)
4567fad09c73SVivien Didelot 		return NULL;
4568fad09c73SVivien Didelot 
4569fad09c73SVivien Didelot 	chip->dev = dev;
4570fad09c73SVivien Didelot 
4571fad09c73SVivien Didelot 	mutex_init(&chip->reg_lock);
4572a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&chip->mdios);
4573fad09c73SVivien Didelot 
4574fad09c73SVivien Didelot 	return chip;
4575fad09c73SVivien Didelot }
4576fad09c73SVivien Didelot 
45775ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
45785ed4e3ebSFlorian Fainelli 							int port)
45797b314362SAndrew Lunn {
458004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
45812bbb33beSAndrew Lunn 
4582443d5a1bSAndrew Lunn 	return chip->info->tag_protocol;
45837b314362SAndrew Lunn }
45847b314362SAndrew Lunn 
45857df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port,
45863709aadcSVivien Didelot 				      const struct switchdev_obj_port_mdb *mdb)
45877df8fbddSVivien Didelot {
45887df8fbddSVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
45897df8fbddSVivien Didelot 	 * so skip the prepare phase.
45907df8fbddSVivien Didelot 	 */
45917df8fbddSVivien Didelot 
45927df8fbddSVivien Didelot 	return 0;
45937df8fbddSVivien Didelot }
45947df8fbddSVivien Didelot 
45957df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
45963709aadcSVivien Didelot 				   const struct switchdev_obj_port_mdb *mdb)
45977df8fbddSVivien Didelot {
459804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
45997df8fbddSVivien Didelot 
46007df8fbddSVivien Didelot 	mutex_lock(&chip->reg_lock);
46017df8fbddSVivien Didelot 	if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
460227c0e600SVivien Didelot 					 MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC))
4603774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to load multicast MAC address\n",
4604774439e5SVivien Didelot 			port);
46057df8fbddSVivien Didelot 	mutex_unlock(&chip->reg_lock);
46067df8fbddSVivien Didelot }
46077df8fbddSVivien Didelot 
46087df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
46097df8fbddSVivien Didelot 				  const struct switchdev_obj_port_mdb *mdb)
46107df8fbddSVivien Didelot {
461104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
46127df8fbddSVivien Didelot 	int err;
46137df8fbddSVivien Didelot 
46147df8fbddSVivien Didelot 	mutex_lock(&chip->reg_lock);
46157df8fbddSVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
461627c0e600SVivien Didelot 					   MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
46177df8fbddSVivien Didelot 	mutex_unlock(&chip->reg_lock);
46187df8fbddSVivien Didelot 
46197df8fbddSVivien Didelot 	return err;
46207df8fbddSVivien Didelot }
46217df8fbddSVivien Didelot 
46224f85901fSRussell King static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
46234f85901fSRussell King 					 bool unicast, bool multicast)
46244f85901fSRussell King {
46254f85901fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
46264f85901fSRussell King 	int err = -EOPNOTSUPP;
46274f85901fSRussell King 
46284f85901fSRussell King 	mutex_lock(&chip->reg_lock);
46294f85901fSRussell King 	if (chip->info->ops->port_set_egress_floods)
46304f85901fSRussell King 		err = chip->info->ops->port_set_egress_floods(chip, port,
46314f85901fSRussell King 							      unicast,
46324f85901fSRussell King 							      multicast);
46334f85901fSRussell King 	mutex_unlock(&chip->reg_lock);
46344f85901fSRussell King 
46354f85901fSRussell King 	return err;
46364f85901fSRussell King }
46374f85901fSRussell King 
4638a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
46397b314362SAndrew Lunn 	.get_tag_protocol	= mv88e6xxx_get_tag_protocol,
4640fad09c73SVivien Didelot 	.setup			= mv88e6xxx_setup,
4641fad09c73SVivien Didelot 	.adjust_link		= mv88e6xxx_adjust_link,
4642c9a2356fSRussell King 	.phylink_validate	= mv88e6xxx_validate,
4643c9a2356fSRussell King 	.phylink_mac_link_state	= mv88e6xxx_link_state,
4644c9a2356fSRussell King 	.phylink_mac_config	= mv88e6xxx_mac_config,
4645c9a2356fSRussell King 	.phylink_mac_link_down	= mv88e6xxx_mac_link_down,
4646c9a2356fSRussell King 	.phylink_mac_link_up	= mv88e6xxx_mac_link_up,
4647fad09c73SVivien Didelot 	.get_strings		= mv88e6xxx_get_strings,
4648fad09c73SVivien Didelot 	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
4649fad09c73SVivien Didelot 	.get_sset_count		= mv88e6xxx_get_sset_count,
465004aca993SAndrew Lunn 	.port_enable		= mv88e6xxx_port_enable,
465104aca993SAndrew Lunn 	.port_disable		= mv88e6xxx_port_disable,
465208f50061SVivien Didelot 	.get_mac_eee		= mv88e6xxx_get_mac_eee,
465308f50061SVivien Didelot 	.set_mac_eee		= mv88e6xxx_set_mac_eee,
4654fad09c73SVivien Didelot 	.get_eeprom_len		= mv88e6xxx_get_eeprom_len,
4655fad09c73SVivien Didelot 	.get_eeprom		= mv88e6xxx_get_eeprom,
4656fad09c73SVivien Didelot 	.set_eeprom		= mv88e6xxx_set_eeprom,
4657fad09c73SVivien Didelot 	.get_regs_len		= mv88e6xxx_get_regs_len,
4658fad09c73SVivien Didelot 	.get_regs		= mv88e6xxx_get_regs,
46592cfcd964SVivien Didelot 	.set_ageing_time	= mv88e6xxx_set_ageing_time,
4660fad09c73SVivien Didelot 	.port_bridge_join	= mv88e6xxx_port_bridge_join,
4661fad09c73SVivien Didelot 	.port_bridge_leave	= mv88e6xxx_port_bridge_leave,
46624f85901fSRussell King 	.port_egress_floods	= mv88e6xxx_port_egress_floods,
4663fad09c73SVivien Didelot 	.port_stp_state_set	= mv88e6xxx_port_stp_state_set,
4664749efcb8SVivien Didelot 	.port_fast_age		= mv88e6xxx_port_fast_age,
4665fad09c73SVivien Didelot 	.port_vlan_filtering	= mv88e6xxx_port_vlan_filtering,
4666fad09c73SVivien Didelot 	.port_vlan_prepare	= mv88e6xxx_port_vlan_prepare,
4667fad09c73SVivien Didelot 	.port_vlan_add		= mv88e6xxx_port_vlan_add,
4668fad09c73SVivien Didelot 	.port_vlan_del		= mv88e6xxx_port_vlan_del,
4669fad09c73SVivien Didelot 	.port_fdb_add           = mv88e6xxx_port_fdb_add,
4670fad09c73SVivien Didelot 	.port_fdb_del           = mv88e6xxx_port_fdb_del,
4671fad09c73SVivien Didelot 	.port_fdb_dump          = mv88e6xxx_port_fdb_dump,
46727df8fbddSVivien Didelot 	.port_mdb_prepare       = mv88e6xxx_port_mdb_prepare,
46737df8fbddSVivien Didelot 	.port_mdb_add           = mv88e6xxx_port_mdb_add,
46747df8fbddSVivien Didelot 	.port_mdb_del           = mv88e6xxx_port_mdb_del,
4675aec5ac88SVivien Didelot 	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
4676aec5ac88SVivien Didelot 	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
4677c6fe0ad2SBrandon Streiff 	.port_hwtstamp_set	= mv88e6xxx_port_hwtstamp_set,
4678c6fe0ad2SBrandon Streiff 	.port_hwtstamp_get	= mv88e6xxx_port_hwtstamp_get,
4679c6fe0ad2SBrandon Streiff 	.port_txtstamp		= mv88e6xxx_port_txtstamp,
4680c6fe0ad2SBrandon Streiff 	.port_rxtstamp		= mv88e6xxx_port_rxtstamp,
4681c6fe0ad2SBrandon Streiff 	.get_ts_info		= mv88e6xxx_get_ts_info,
4682fad09c73SVivien Didelot };
4683fad09c73SVivien Didelot 
468455ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
4685fad09c73SVivien Didelot {
4686fad09c73SVivien Didelot 	struct device *dev = chip->dev;
4687fad09c73SVivien Didelot 	struct dsa_switch *ds;
4688fad09c73SVivien Didelot 
468973b1204dSVivien Didelot 	ds = dsa_switch_alloc(dev, mv88e6xxx_num_ports(chip));
4690fad09c73SVivien Didelot 	if (!ds)
4691fad09c73SVivien Didelot 		return -ENOMEM;
4692fad09c73SVivien Didelot 
4693fad09c73SVivien Didelot 	ds->priv = chip;
4694877b7cb0SAndrew Lunn 	ds->dev = dev;
46959d490b4eSVivien Didelot 	ds->ops = &mv88e6xxx_switch_ops;
46969ff74f24SVivien Didelot 	ds->ageing_time_min = chip->info->age_time_coeff;
46979ff74f24SVivien Didelot 	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
4698fad09c73SVivien Didelot 
4699fad09c73SVivien Didelot 	dev_set_drvdata(dev, ds);
4700fad09c73SVivien Didelot 
470123c9ee49SVivien Didelot 	return dsa_register_switch(ds);
4702fad09c73SVivien Didelot }
4703fad09c73SVivien Didelot 
4704fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
4705fad09c73SVivien Didelot {
4706fad09c73SVivien Didelot 	dsa_unregister_switch(chip->ds);
4707fad09c73SVivien Didelot }
4708fad09c73SVivien Didelot 
4709877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev)
4710877b7cb0SAndrew Lunn {
4711877b7cb0SAndrew Lunn 	const struct of_device_id *matches = dev->driver->of_match_table;
4712877b7cb0SAndrew Lunn 	const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data;
4713877b7cb0SAndrew Lunn 
4714877b7cb0SAndrew Lunn 	for (; matches->name[0] || matches->type[0] || matches->compatible[0];
4715877b7cb0SAndrew Lunn 	     matches++) {
4716877b7cb0SAndrew Lunn 		if (!strcmp(pdata->compatible, matches->compatible))
4717877b7cb0SAndrew Lunn 			return matches->data;
4718877b7cb0SAndrew Lunn 	}
4719877b7cb0SAndrew Lunn 	return NULL;
4720877b7cb0SAndrew Lunn }
4721877b7cb0SAndrew Lunn 
4722bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration
4723bcd3d9d9SMiquel Raynal  * would be lost after a power cycle so prevent it to be suspended.
4724bcd3d9d9SMiquel Raynal  */
4725bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev)
4726bcd3d9d9SMiquel Raynal {
4727bcd3d9d9SMiquel Raynal 	return -EOPNOTSUPP;
4728bcd3d9d9SMiquel Raynal }
4729bcd3d9d9SMiquel Raynal 
4730bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev)
4731bcd3d9d9SMiquel Raynal {
4732bcd3d9d9SMiquel Raynal 	return 0;
4733bcd3d9d9SMiquel Raynal }
4734bcd3d9d9SMiquel Raynal 
4735bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume);
4736bcd3d9d9SMiquel Raynal 
4737fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev)
4738fad09c73SVivien Didelot {
4739877b7cb0SAndrew Lunn 	struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data;
47407ddae24fSDavid S. Miller 	const struct mv88e6xxx_info *compat_info = NULL;
4741fad09c73SVivien Didelot 	struct device *dev = &mdiodev->dev;
4742fad09c73SVivien Didelot 	struct device_node *np = dev->of_node;
4743fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
4744877b7cb0SAndrew Lunn 	int port;
4745fad09c73SVivien Didelot 	int err;
4746fad09c73SVivien Didelot 
47477bb8c996SAndrew Lunn 	if (!np && !pdata)
47487bb8c996SAndrew Lunn 		return -EINVAL;
47497bb8c996SAndrew Lunn 
4750877b7cb0SAndrew Lunn 	if (np)
4751fad09c73SVivien Didelot 		compat_info = of_device_get_match_data(dev);
4752877b7cb0SAndrew Lunn 
4753877b7cb0SAndrew Lunn 	if (pdata) {
4754877b7cb0SAndrew Lunn 		compat_info = pdata_device_get_match_data(dev);
4755877b7cb0SAndrew Lunn 
4756877b7cb0SAndrew Lunn 		if (!pdata->netdev)
4757877b7cb0SAndrew Lunn 			return -EINVAL;
4758877b7cb0SAndrew Lunn 
4759877b7cb0SAndrew Lunn 		for (port = 0; port < DSA_MAX_PORTS; port++) {
4760877b7cb0SAndrew Lunn 			if (!(pdata->enabled_ports & (1 << port)))
4761877b7cb0SAndrew Lunn 				continue;
4762877b7cb0SAndrew Lunn 			if (strcmp(pdata->cd.port_names[port], "cpu"))
4763877b7cb0SAndrew Lunn 				continue;
4764877b7cb0SAndrew Lunn 			pdata->cd.netdev[port] = &pdata->netdev->dev;
4765877b7cb0SAndrew Lunn 			break;
4766877b7cb0SAndrew Lunn 		}
4767877b7cb0SAndrew Lunn 	}
4768877b7cb0SAndrew Lunn 
4769fad09c73SVivien Didelot 	if (!compat_info)
4770fad09c73SVivien Didelot 		return -EINVAL;
4771fad09c73SVivien Didelot 
4772fad09c73SVivien Didelot 	chip = mv88e6xxx_alloc_chip(dev);
4773877b7cb0SAndrew Lunn 	if (!chip) {
4774877b7cb0SAndrew Lunn 		err = -ENOMEM;
4775877b7cb0SAndrew Lunn 		goto out;
4776877b7cb0SAndrew Lunn 	}
4777fad09c73SVivien Didelot 
4778fad09c73SVivien Didelot 	chip->info = compat_info;
4779fad09c73SVivien Didelot 
4780fad09c73SVivien Didelot 	err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
4781fad09c73SVivien Didelot 	if (err)
4782877b7cb0SAndrew Lunn 		goto out;
4783fad09c73SVivien Didelot 
4784b4308f04SAndrew Lunn 	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
4785877b7cb0SAndrew Lunn 	if (IS_ERR(chip->reset)) {
4786877b7cb0SAndrew Lunn 		err = PTR_ERR(chip->reset);
4787877b7cb0SAndrew Lunn 		goto out;
4788877b7cb0SAndrew Lunn 	}
4789b4308f04SAndrew Lunn 
4790fad09c73SVivien Didelot 	err = mv88e6xxx_detect(chip);
4791fad09c73SVivien Didelot 	if (err)
4792877b7cb0SAndrew Lunn 		goto out;
4793fad09c73SVivien Didelot 
4794e57e5e77SVivien Didelot 	mv88e6xxx_phy_init(chip);
4795e57e5e77SVivien Didelot 
479600baabe5SAndrew Lunn 	if (chip->info->ops->get_eeprom) {
479700baabe5SAndrew Lunn 		if (np)
479800baabe5SAndrew Lunn 			of_property_read_u32(np, "eeprom-length",
479900baabe5SAndrew Lunn 					     &chip->eeprom_len);
480000baabe5SAndrew Lunn 		else
480100baabe5SAndrew Lunn 			chip->eeprom_len = pdata->eeprom_len;
480200baabe5SAndrew Lunn 	}
4803fad09c73SVivien Didelot 
4804dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
4805dc30c35bSAndrew Lunn 	err = mv88e6xxx_switch_reset(chip);
4806dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
4807fad09c73SVivien Didelot 	if (err)
4808dc30c35bSAndrew Lunn 		goto out;
4809fad09c73SVivien Didelot 
4810a27415deSAndrew Lunn 	if (np) {
4811dc30c35bSAndrew Lunn 		chip->irq = of_irq_get(np, 0);
4812dc30c35bSAndrew Lunn 		if (chip->irq == -EPROBE_DEFER) {
4813dc30c35bSAndrew Lunn 			err = chip->irq;
4814dc30c35bSAndrew Lunn 			goto out;
4815fad09c73SVivien Didelot 		}
4816a27415deSAndrew Lunn 	}
4817a27415deSAndrew Lunn 
4818a27415deSAndrew Lunn 	if (pdata)
4819a27415deSAndrew Lunn 		chip->irq = pdata->irq;
4820fad09c73SVivien Didelot 
4821294d711eSAndrew Lunn 	/* Has to be performed before the MDIO bus is created, because
4822a708767eSUwe Kleine-König 	 * the PHYs will link their interrupts to these interrupt
4823294d711eSAndrew Lunn 	 * controllers
4824dc30c35bSAndrew Lunn 	 */
4825dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
4826294d711eSAndrew Lunn 	if (chip->irq > 0)
4827dc30c35bSAndrew Lunn 		err = mv88e6xxx_g1_irq_setup(chip);
4828294d711eSAndrew Lunn 	else
4829294d711eSAndrew Lunn 		err = mv88e6xxx_irq_poll_setup(chip);
4830dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
4831dc30c35bSAndrew Lunn 
4832dc30c35bSAndrew Lunn 	if (err)
4833dc30c35bSAndrew Lunn 		goto out;
4834dc30c35bSAndrew Lunn 
4835d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0) {
4836dc30c35bSAndrew Lunn 		err = mv88e6xxx_g2_irq_setup(chip);
4837dc30c35bSAndrew Lunn 		if (err)
4838dc30c35bSAndrew Lunn 			goto out_g1_irq;
4839dc30c35bSAndrew Lunn 	}
48400977644cSAndrew Lunn 
48410977644cSAndrew Lunn 	err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
48420977644cSAndrew Lunn 	if (err)
48430977644cSAndrew Lunn 		goto out_g2_irq;
484462eb1162SAndrew Lunn 
484562eb1162SAndrew Lunn 	err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
484662eb1162SAndrew Lunn 	if (err)
484762eb1162SAndrew Lunn 		goto out_g1_atu_prob_irq;
4848dc30c35bSAndrew Lunn 
4849a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdios_register(chip, np);
4850dc30c35bSAndrew Lunn 	if (err)
485162eb1162SAndrew Lunn 		goto out_g1_vtu_prob_irq;
4852dc30c35bSAndrew Lunn 
485355ed0ce0SFlorian Fainelli 	err = mv88e6xxx_register_switch(chip);
4854dc30c35bSAndrew Lunn 	if (err)
4855dc30c35bSAndrew Lunn 		goto out_mdio;
4856dc30c35bSAndrew Lunn 
4857fad09c73SVivien Didelot 	return 0;
4858dc30c35bSAndrew Lunn 
4859dc30c35bSAndrew Lunn out_mdio:
4860a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
486162eb1162SAndrew Lunn out_g1_vtu_prob_irq:
486262eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
48630977644cSAndrew Lunn out_g1_atu_prob_irq:
48640977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
4865dc30c35bSAndrew Lunn out_g2_irq:
4866294d711eSAndrew Lunn 	if (chip->info->g2_irqs > 0)
4867dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
4868dc30c35bSAndrew Lunn out_g1_irq:
4869294d711eSAndrew Lunn 	if (chip->irq > 0)
4870dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
4871294d711eSAndrew Lunn 	else
4872294d711eSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
4873dc30c35bSAndrew Lunn out:
4874877b7cb0SAndrew Lunn 	if (pdata)
4875877b7cb0SAndrew Lunn 		dev_put(pdata->netdev);
4876877b7cb0SAndrew Lunn 
4877dc30c35bSAndrew Lunn 	return err;
4878fad09c73SVivien Didelot }
4879fad09c73SVivien Didelot 
4880fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev)
4881fad09c73SVivien Didelot {
4882fad09c73SVivien Didelot 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
488304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
4884fad09c73SVivien Didelot 
4885c6fe0ad2SBrandon Streiff 	if (chip->info->ptp_support) {
4886c6fe0ad2SBrandon Streiff 		mv88e6xxx_hwtstamp_free(chip);
48872fa8d3afSBrandon Streiff 		mv88e6xxx_ptp_free(chip);
4888c6fe0ad2SBrandon Streiff 	}
48892fa8d3afSBrandon Streiff 
4890930188ceSAndrew Lunn 	mv88e6xxx_phy_destroy(chip);
4891fad09c73SVivien Didelot 	mv88e6xxx_unregister_switch(chip);
4892a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
4893dc30c35bSAndrew Lunn 
489462eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
48950977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
489676f38f1fSAndrew Lunn 
4897d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0)
4898dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
489976f38f1fSAndrew Lunn 
490076f38f1fSAndrew Lunn 	if (chip->irq > 0)
4901dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
490276f38f1fSAndrew Lunn 	else
490376f38f1fSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
4904fad09c73SVivien Didelot }
4905fad09c73SVivien Didelot 
4906fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = {
4907fad09c73SVivien Didelot 	{
4908fad09c73SVivien Didelot 		.compatible = "marvell,mv88e6085",
4909fad09c73SVivien Didelot 		.data = &mv88e6xxx_table[MV88E6085],
4910fad09c73SVivien Didelot 	},
49111a3b39ecSAndrew Lunn 	{
49121a3b39ecSAndrew Lunn 		.compatible = "marvell,mv88e6190",
49131a3b39ecSAndrew Lunn 		.data = &mv88e6xxx_table[MV88E6190],
49141a3b39ecSAndrew Lunn 	},
49151f71836fSRasmus Villemoes 	{
49161f71836fSRasmus Villemoes 		.compatible = "marvell,mv88e6250",
49171f71836fSRasmus Villemoes 		.data = &mv88e6xxx_table[MV88E6250],
49181f71836fSRasmus Villemoes 	},
4919fad09c73SVivien Didelot 	{ /* sentinel */ },
4920fad09c73SVivien Didelot };
4921fad09c73SVivien Didelot 
4922fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);
4923fad09c73SVivien Didelot 
4924fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = {
4925fad09c73SVivien Didelot 	.probe	= mv88e6xxx_probe,
4926fad09c73SVivien Didelot 	.remove = mv88e6xxx_remove,
4927fad09c73SVivien Didelot 	.mdiodrv.driver = {
4928fad09c73SVivien Didelot 		.name = "mv88e6085",
4929fad09c73SVivien Didelot 		.of_match_table = mv88e6xxx_of_match,
4930bcd3d9d9SMiquel Raynal 		.pm = &mv88e6xxx_pm_ops,
4931fad09c73SVivien Didelot 	},
4932fad09c73SVivien Didelot };
4933fad09c73SVivien Didelot 
49347324d50eSAndrew Lunn mdio_module_driver(mv88e6xxx_driver);
4935fad09c73SVivien Didelot 
4936fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
4937fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
4938fad09c73SVivien Didelot MODULE_LICENSE("GPL");
4939