xref: /openbmc/linux/drivers/net/dsa/mv88e6xxx/chip.c (revision 72d8b4fd)
1fad09c73SVivien Didelot /*
2fad09c73SVivien Didelot  * Marvell 88e6xxx Ethernet switch single-chip support
3fad09c73SVivien Didelot  *
4fad09c73SVivien Didelot  * Copyright (c) 2008 Marvell Semiconductor
5fad09c73SVivien Didelot  *
6fad09c73SVivien Didelot  * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
7fad09c73SVivien Didelot  *
84333d619SVivien Didelot  * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
94333d619SVivien Didelot  *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
104333d619SVivien Didelot  *
11fad09c73SVivien Didelot  * This program is free software; you can redistribute it and/or modify
12fad09c73SVivien Didelot  * it under the terms of the GNU General Public License as published by
13fad09c73SVivien Didelot  * the Free Software Foundation; either version 2 of the License, or
14fad09c73SVivien Didelot  * (at your option) any later version.
15fad09c73SVivien Didelot  */
16fad09c73SVivien Didelot 
17fad09c73SVivien Didelot #include <linux/delay.h>
18fad09c73SVivien Didelot #include <linux/etherdevice.h>
19fad09c73SVivien Didelot #include <linux/ethtool.h>
20fad09c73SVivien Didelot #include <linux/if_bridge.h>
21dc30c35bSAndrew Lunn #include <linux/interrupt.h>
22dc30c35bSAndrew Lunn #include <linux/irq.h>
23dc30c35bSAndrew Lunn #include <linux/irqdomain.h>
24fad09c73SVivien Didelot #include <linux/jiffies.h>
25fad09c73SVivien Didelot #include <linux/list.h>
26fad09c73SVivien Didelot #include <linux/mdio.h>
27fad09c73SVivien Didelot #include <linux/module.h>
28fad09c73SVivien Didelot #include <linux/of_device.h>
29dc30c35bSAndrew Lunn #include <linux/of_irq.h>
30fad09c73SVivien Didelot #include <linux/of_mdio.h>
31877b7cb0SAndrew Lunn #include <linux/platform_data/mv88e6xxx.h>
32fad09c73SVivien Didelot #include <linux/netdevice.h>
33fad09c73SVivien Didelot #include <linux/gpio/consumer.h>
34fad09c73SVivien Didelot #include <linux/phy.h>
35c9a2356fSRussell King #include <linux/phylink.h>
36fad09c73SVivien Didelot #include <net/dsa.h>
37ec561276SVivien Didelot 
384d5f2ba7SVivien Didelot #include "chip.h"
39a935c052SVivien Didelot #include "global1.h"
40ec561276SVivien Didelot #include "global2.h"
41c6fe0ad2SBrandon Streiff #include "hwtstamp.h"
4210fa5bfcSAndrew Lunn #include "phy.h"
4318abed21SVivien Didelot #include "port.h"
442fa8d3afSBrandon Streiff #include "ptp.h"
456d91782fSAndrew Lunn #include "serdes.h"
46fad09c73SVivien Didelot 
47fad09c73SVivien Didelot static void assert_reg_lock(struct mv88e6xxx_chip *chip)
48fad09c73SVivien Didelot {
49fad09c73SVivien Didelot 	if (unlikely(!mutex_is_locked(&chip->reg_lock))) {
50fad09c73SVivien Didelot 		dev_err(chip->dev, "Switch registers lock not held!\n");
51fad09c73SVivien Didelot 		dump_stack();
52fad09c73SVivien Didelot 	}
53fad09c73SVivien Didelot }
54fad09c73SVivien Didelot 
55fad09c73SVivien Didelot /* The switch ADDR[4:1] configuration pins define the chip SMI device address
56fad09c73SVivien Didelot  * (ADDR[0] is always zero, thus only even SMI addresses can be strapped).
57fad09c73SVivien Didelot  *
58fad09c73SVivien Didelot  * When ADDR is all zero, the chip uses Single-chip Addressing Mode, assuming it
59fad09c73SVivien Didelot  * is the only device connected to the SMI master. In this mode it responds to
60fad09c73SVivien Didelot  * all 32 possible SMI addresses, and thus maps directly the internal devices.
61fad09c73SVivien Didelot  *
62fad09c73SVivien Didelot  * When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing
63fad09c73SVivien Didelot  * multiple devices to share the SMI interface. In this mode it responds to only
64fad09c73SVivien Didelot  * 2 registers, used to indirectly access the internal SMI devices.
65fad09c73SVivien Didelot  */
66fad09c73SVivien Didelot 
67fad09c73SVivien Didelot static int mv88e6xxx_smi_read(struct mv88e6xxx_chip *chip,
68fad09c73SVivien Didelot 			      int addr, int reg, u16 *val)
69fad09c73SVivien Didelot {
70fad09c73SVivien Didelot 	if (!chip->smi_ops)
71fad09c73SVivien Didelot 		return -EOPNOTSUPP;
72fad09c73SVivien Didelot 
73fad09c73SVivien Didelot 	return chip->smi_ops->read(chip, addr, reg, val);
74fad09c73SVivien Didelot }
75fad09c73SVivien Didelot 
76fad09c73SVivien Didelot static int mv88e6xxx_smi_write(struct mv88e6xxx_chip *chip,
77fad09c73SVivien Didelot 			       int addr, int reg, u16 val)
78fad09c73SVivien Didelot {
79fad09c73SVivien Didelot 	if (!chip->smi_ops)
80fad09c73SVivien Didelot 		return -EOPNOTSUPP;
81fad09c73SVivien Didelot 
82fad09c73SVivien Didelot 	return chip->smi_ops->write(chip, addr, reg, val);
83fad09c73SVivien Didelot }
84fad09c73SVivien Didelot 
85fad09c73SVivien Didelot static int mv88e6xxx_smi_single_chip_read(struct mv88e6xxx_chip *chip,
86fad09c73SVivien Didelot 					  int addr, int reg, u16 *val)
87fad09c73SVivien Didelot {
88fad09c73SVivien Didelot 	int ret;
89fad09c73SVivien Didelot 
90fad09c73SVivien Didelot 	ret = mdiobus_read_nested(chip->bus, addr, reg);
91fad09c73SVivien Didelot 	if (ret < 0)
92fad09c73SVivien Didelot 		return ret;
93fad09c73SVivien Didelot 
94fad09c73SVivien Didelot 	*val = ret & 0xffff;
95fad09c73SVivien Didelot 
96fad09c73SVivien Didelot 	return 0;
97fad09c73SVivien Didelot }
98fad09c73SVivien Didelot 
99fad09c73SVivien Didelot static int mv88e6xxx_smi_single_chip_write(struct mv88e6xxx_chip *chip,
100fad09c73SVivien Didelot 					   int addr, int reg, u16 val)
101fad09c73SVivien Didelot {
102fad09c73SVivien Didelot 	int ret;
103fad09c73SVivien Didelot 
104fad09c73SVivien Didelot 	ret = mdiobus_write_nested(chip->bus, addr, reg, val);
105fad09c73SVivien Didelot 	if (ret < 0)
106fad09c73SVivien Didelot 		return ret;
107fad09c73SVivien Didelot 
108fad09c73SVivien Didelot 	return 0;
109fad09c73SVivien Didelot }
110fad09c73SVivien Didelot 
111c08026abSVivien Didelot static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_single_chip_ops = {
112fad09c73SVivien Didelot 	.read = mv88e6xxx_smi_single_chip_read,
113fad09c73SVivien Didelot 	.write = mv88e6xxx_smi_single_chip_write,
114fad09c73SVivien Didelot };
115fad09c73SVivien Didelot 
116fad09c73SVivien Didelot static int mv88e6xxx_smi_multi_chip_wait(struct mv88e6xxx_chip *chip)
117fad09c73SVivien Didelot {
118fad09c73SVivien Didelot 	int ret;
119fad09c73SVivien Didelot 	int i;
120fad09c73SVivien Didelot 
121fad09c73SVivien Didelot 	for (i = 0; i < 16; i++) {
122fad09c73SVivien Didelot 		ret = mdiobus_read_nested(chip->bus, chip->sw_addr, SMI_CMD);
123fad09c73SVivien Didelot 		if (ret < 0)
124fad09c73SVivien Didelot 			return ret;
125fad09c73SVivien Didelot 
126fad09c73SVivien Didelot 		if ((ret & SMI_CMD_BUSY) == 0)
127fad09c73SVivien Didelot 			return 0;
128fad09c73SVivien Didelot 	}
129fad09c73SVivien Didelot 
130fad09c73SVivien Didelot 	return -ETIMEDOUT;
131fad09c73SVivien Didelot }
132fad09c73SVivien Didelot 
133fad09c73SVivien Didelot static int mv88e6xxx_smi_multi_chip_read(struct mv88e6xxx_chip *chip,
134fad09c73SVivien Didelot 					 int addr, int reg, u16 *val)
135fad09c73SVivien Didelot {
136fad09c73SVivien Didelot 	int ret;
137fad09c73SVivien Didelot 
138fad09c73SVivien Didelot 	/* Wait for the bus to become free. */
139fad09c73SVivien Didelot 	ret = mv88e6xxx_smi_multi_chip_wait(chip);
140fad09c73SVivien Didelot 	if (ret < 0)
141fad09c73SVivien Didelot 		return ret;
142fad09c73SVivien Didelot 
143fad09c73SVivien Didelot 	/* Transmit the read command. */
144fad09c73SVivien Didelot 	ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_CMD,
145fad09c73SVivien Didelot 				   SMI_CMD_OP_22_READ | (addr << 5) | reg);
146fad09c73SVivien Didelot 	if (ret < 0)
147fad09c73SVivien Didelot 		return ret;
148fad09c73SVivien Didelot 
149fad09c73SVivien Didelot 	/* Wait for the read command to complete. */
150fad09c73SVivien Didelot 	ret = mv88e6xxx_smi_multi_chip_wait(chip);
151fad09c73SVivien Didelot 	if (ret < 0)
152fad09c73SVivien Didelot 		return ret;
153fad09c73SVivien Didelot 
154fad09c73SVivien Didelot 	/* Read the data. */
155fad09c73SVivien Didelot 	ret = mdiobus_read_nested(chip->bus, chip->sw_addr, SMI_DATA);
156fad09c73SVivien Didelot 	if (ret < 0)
157fad09c73SVivien Didelot 		return ret;
158fad09c73SVivien Didelot 
159fad09c73SVivien Didelot 	*val = ret & 0xffff;
160fad09c73SVivien Didelot 
161fad09c73SVivien Didelot 	return 0;
162fad09c73SVivien Didelot }
163fad09c73SVivien Didelot 
164fad09c73SVivien Didelot static int mv88e6xxx_smi_multi_chip_write(struct mv88e6xxx_chip *chip,
165fad09c73SVivien Didelot 					  int addr, int reg, u16 val)
166fad09c73SVivien Didelot {
167fad09c73SVivien Didelot 	int ret;
168fad09c73SVivien Didelot 
169fad09c73SVivien Didelot 	/* Wait for the bus to become free. */
170fad09c73SVivien Didelot 	ret = mv88e6xxx_smi_multi_chip_wait(chip);
171fad09c73SVivien Didelot 	if (ret < 0)
172fad09c73SVivien Didelot 		return ret;
173fad09c73SVivien Didelot 
174fad09c73SVivien Didelot 	/* Transmit the data to write. */
175fad09c73SVivien Didelot 	ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_DATA, val);
176fad09c73SVivien Didelot 	if (ret < 0)
177fad09c73SVivien Didelot 		return ret;
178fad09c73SVivien Didelot 
179fad09c73SVivien Didelot 	/* Transmit the write command. */
180fad09c73SVivien Didelot 	ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_CMD,
181fad09c73SVivien Didelot 				   SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
182fad09c73SVivien Didelot 	if (ret < 0)
183fad09c73SVivien Didelot 		return ret;
184fad09c73SVivien Didelot 
185fad09c73SVivien Didelot 	/* Wait for the write command to complete. */
186fad09c73SVivien Didelot 	ret = mv88e6xxx_smi_multi_chip_wait(chip);
187fad09c73SVivien Didelot 	if (ret < 0)
188fad09c73SVivien Didelot 		return ret;
189fad09c73SVivien Didelot 
190fad09c73SVivien Didelot 	return 0;
191fad09c73SVivien Didelot }
192fad09c73SVivien Didelot 
193c08026abSVivien Didelot static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_multi_chip_ops = {
194fad09c73SVivien Didelot 	.read = mv88e6xxx_smi_multi_chip_read,
195fad09c73SVivien Didelot 	.write = mv88e6xxx_smi_multi_chip_write,
196fad09c73SVivien Didelot };
197fad09c73SVivien Didelot 
198ec561276SVivien Didelot int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
199fad09c73SVivien Didelot {
200fad09c73SVivien Didelot 	int err;
201fad09c73SVivien Didelot 
202fad09c73SVivien Didelot 	assert_reg_lock(chip);
203fad09c73SVivien Didelot 
204fad09c73SVivien Didelot 	err = mv88e6xxx_smi_read(chip, addr, reg, val);
205fad09c73SVivien Didelot 	if (err)
206fad09c73SVivien Didelot 		return err;
207fad09c73SVivien Didelot 
208fad09c73SVivien Didelot 	dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
209fad09c73SVivien Didelot 		addr, reg, *val);
210fad09c73SVivien Didelot 
211fad09c73SVivien Didelot 	return 0;
212fad09c73SVivien Didelot }
213fad09c73SVivien Didelot 
214ec561276SVivien Didelot int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
215fad09c73SVivien Didelot {
216fad09c73SVivien Didelot 	int err;
217fad09c73SVivien Didelot 
218fad09c73SVivien Didelot 	assert_reg_lock(chip);
219fad09c73SVivien Didelot 
220fad09c73SVivien Didelot 	err = mv88e6xxx_smi_write(chip, addr, reg, val);
221fad09c73SVivien Didelot 	if (err)
222fad09c73SVivien Didelot 		return err;
223fad09c73SVivien Didelot 
224fad09c73SVivien Didelot 	dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
225fad09c73SVivien Didelot 		addr, reg, val);
226fad09c73SVivien Didelot 
227fad09c73SVivien Didelot 	return 0;
228fad09c73SVivien Didelot }
229fad09c73SVivien Didelot 
23010fa5bfcSAndrew Lunn struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
231a3c53be5SAndrew Lunn {
232a3c53be5SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
233a3c53be5SAndrew Lunn 
234a3c53be5SAndrew Lunn 	mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus,
235a3c53be5SAndrew Lunn 				    list);
236a3c53be5SAndrew Lunn 	if (!mdio_bus)
237a3c53be5SAndrew Lunn 		return NULL;
238a3c53be5SAndrew Lunn 
239a3c53be5SAndrew Lunn 	return mdio_bus->bus;
240a3c53be5SAndrew Lunn }
241a3c53be5SAndrew Lunn 
242dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_mask(struct irq_data *d)
243dc30c35bSAndrew Lunn {
244dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
245dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
246dc30c35bSAndrew Lunn 
247dc30c35bSAndrew Lunn 	chip->g1_irq.masked |= (1 << n);
248dc30c35bSAndrew Lunn }
249dc30c35bSAndrew Lunn 
250dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_unmask(struct irq_data *d)
251dc30c35bSAndrew Lunn {
252dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
253dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
254dc30c35bSAndrew Lunn 
255dc30c35bSAndrew Lunn 	chip->g1_irq.masked &= ~(1 << n);
256dc30c35bSAndrew Lunn }
257dc30c35bSAndrew Lunn 
258294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip)
259dc30c35bSAndrew Lunn {
260dc30c35bSAndrew Lunn 	unsigned int nhandled = 0;
261dc30c35bSAndrew Lunn 	unsigned int sub_irq;
262dc30c35bSAndrew Lunn 	unsigned int n;
263dc30c35bSAndrew Lunn 	u16 reg;
2647c0db24cSJohn David Anglin 	u16 ctl1;
265dc30c35bSAndrew Lunn 	int err;
266dc30c35bSAndrew Lunn 
267dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
26882466921SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
269dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
270dc30c35bSAndrew Lunn 
271dc30c35bSAndrew Lunn 	if (err)
272dc30c35bSAndrew Lunn 		goto out;
273dc30c35bSAndrew Lunn 
2747c0db24cSJohn David Anglin 	do {
275dc30c35bSAndrew Lunn 		for (n = 0; n < chip->g1_irq.nirqs; ++n) {
276dc30c35bSAndrew Lunn 			if (reg & (1 << n)) {
2777c0db24cSJohn David Anglin 				sub_irq = irq_find_mapping(chip->g1_irq.domain,
2787c0db24cSJohn David Anglin 							   n);
279dc30c35bSAndrew Lunn 				handle_nested_irq(sub_irq);
280dc30c35bSAndrew Lunn 				++nhandled;
281dc30c35bSAndrew Lunn 			}
282dc30c35bSAndrew Lunn 		}
2837c0db24cSJohn David Anglin 
2847c0db24cSJohn David Anglin 		mutex_lock(&chip->reg_lock);
2857c0db24cSJohn David Anglin 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1);
2867c0db24cSJohn David Anglin 		if (err)
2877c0db24cSJohn David Anglin 			goto unlock;
2887c0db24cSJohn David Anglin 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
2897c0db24cSJohn David Anglin unlock:
2907c0db24cSJohn David Anglin 		mutex_unlock(&chip->reg_lock);
2917c0db24cSJohn David Anglin 		if (err)
2927c0db24cSJohn David Anglin 			goto out;
2937c0db24cSJohn David Anglin 		ctl1 &= GENMASK(chip->g1_irq.nirqs, 0);
2947c0db24cSJohn David Anglin 	} while (reg & ctl1);
2957c0db24cSJohn David Anglin 
296dc30c35bSAndrew Lunn out:
297dc30c35bSAndrew Lunn 	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
298dc30c35bSAndrew Lunn }
299dc30c35bSAndrew Lunn 
300294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
301294d711eSAndrew Lunn {
302294d711eSAndrew Lunn 	struct mv88e6xxx_chip *chip = dev_id;
303294d711eSAndrew Lunn 
304294d711eSAndrew Lunn 	return mv88e6xxx_g1_irq_thread_work(chip);
305294d711eSAndrew Lunn }
306294d711eSAndrew Lunn 
307dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
308dc30c35bSAndrew Lunn {
309dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
310dc30c35bSAndrew Lunn 
311dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
312dc30c35bSAndrew Lunn }
313dc30c35bSAndrew Lunn 
314dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
315dc30c35bSAndrew Lunn {
316dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
317dc30c35bSAndrew Lunn 	u16 mask = GENMASK(chip->g1_irq.nirqs, 0);
318dc30c35bSAndrew Lunn 	u16 reg;
319dc30c35bSAndrew Lunn 	int err;
320dc30c35bSAndrew Lunn 
321d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &reg);
322dc30c35bSAndrew Lunn 	if (err)
323dc30c35bSAndrew Lunn 		goto out;
324dc30c35bSAndrew Lunn 
325dc30c35bSAndrew Lunn 	reg &= ~mask;
326dc30c35bSAndrew Lunn 	reg |= (~chip->g1_irq.masked & mask);
327dc30c35bSAndrew Lunn 
328d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg);
329dc30c35bSAndrew Lunn 	if (err)
330dc30c35bSAndrew Lunn 		goto out;
331dc30c35bSAndrew Lunn 
332dc30c35bSAndrew Lunn out:
333dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
334dc30c35bSAndrew Lunn }
335dc30c35bSAndrew Lunn 
3366eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g1_irq_chip = {
337dc30c35bSAndrew Lunn 	.name			= "mv88e6xxx-g1",
338dc30c35bSAndrew Lunn 	.irq_mask		= mv88e6xxx_g1_irq_mask,
339dc30c35bSAndrew Lunn 	.irq_unmask		= mv88e6xxx_g1_irq_unmask,
340dc30c35bSAndrew Lunn 	.irq_bus_lock		= mv88e6xxx_g1_irq_bus_lock,
341dc30c35bSAndrew Lunn 	.irq_bus_sync_unlock	= mv88e6xxx_g1_irq_bus_sync_unlock,
342dc30c35bSAndrew Lunn };
343dc30c35bSAndrew Lunn 
344dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d,
345dc30c35bSAndrew Lunn 				       unsigned int irq,
346dc30c35bSAndrew Lunn 				       irq_hw_number_t hwirq)
347dc30c35bSAndrew Lunn {
348dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = d->host_data;
349dc30c35bSAndrew Lunn 
350dc30c35bSAndrew Lunn 	irq_set_chip_data(irq, d->host_data);
351dc30c35bSAndrew Lunn 	irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq);
352dc30c35bSAndrew Lunn 	irq_set_noprobe(irq);
353dc30c35bSAndrew Lunn 
354dc30c35bSAndrew Lunn 	return 0;
355dc30c35bSAndrew Lunn }
356dc30c35bSAndrew Lunn 
357dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = {
358dc30c35bSAndrew Lunn 	.map	= mv88e6xxx_g1_irq_domain_map,
359dc30c35bSAndrew Lunn 	.xlate	= irq_domain_xlate_twocell,
360dc30c35bSAndrew Lunn };
361dc30c35bSAndrew Lunn 
3623d82475aSUwe Kleine-König /* To be called with reg_lock held */
363294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip)
364dc30c35bSAndrew Lunn {
365dc30c35bSAndrew Lunn 	int irq, virq;
3663460a577SAndrew Lunn 	u16 mask;
3673460a577SAndrew Lunn 
368d77f4321SVivien Didelot 	mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
3693d5fdba1SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
370d77f4321SVivien Didelot 	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
3713460a577SAndrew Lunn 
3725edef2f2SAndreas Färber 	for (irq = 0; irq < chip->g1_irq.nirqs; irq++) {
373a3db3d3aSAndrew Lunn 		virq = irq_find_mapping(chip->g1_irq.domain, irq);
374dc30c35bSAndrew Lunn 		irq_dispose_mapping(virq);
375dc30c35bSAndrew Lunn 	}
376dc30c35bSAndrew Lunn 
377a3db3d3aSAndrew Lunn 	irq_domain_remove(chip->g1_irq.domain);
378dc30c35bSAndrew Lunn }
379dc30c35bSAndrew Lunn 
380294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
381294d711eSAndrew Lunn {
3823d82475aSUwe Kleine-König 	/*
3833d82475aSUwe Kleine-König 	 * free_irq must be called without reg_lock taken because the irq
3843d82475aSUwe Kleine-König 	 * handler takes this lock, too.
3853d82475aSUwe Kleine-König 	 */
386294d711eSAndrew Lunn 	free_irq(chip->irq, chip);
3873d82475aSUwe Kleine-König 
3883d82475aSUwe Kleine-König 	mutex_lock(&chip->reg_lock);
3893d82475aSUwe Kleine-König 	mv88e6xxx_g1_irq_free_common(chip);
3903d82475aSUwe Kleine-König 	mutex_unlock(&chip->reg_lock);
391294d711eSAndrew Lunn }
392294d711eSAndrew Lunn 
393294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip)
394dc30c35bSAndrew Lunn {
3953dd0ef05SAndrew Lunn 	int err, irq, virq;
3963dd0ef05SAndrew Lunn 	u16 reg, mask;
397dc30c35bSAndrew Lunn 
398dc30c35bSAndrew Lunn 	chip->g1_irq.nirqs = chip->info->g1_irqs;
399dc30c35bSAndrew Lunn 	chip->g1_irq.domain = irq_domain_add_simple(
400dc30c35bSAndrew Lunn 		NULL, chip->g1_irq.nirqs, 0,
401dc30c35bSAndrew Lunn 		&mv88e6xxx_g1_irq_domain_ops, chip);
402dc30c35bSAndrew Lunn 	if (!chip->g1_irq.domain)
403dc30c35bSAndrew Lunn 		return -ENOMEM;
404dc30c35bSAndrew Lunn 
405dc30c35bSAndrew Lunn 	for (irq = 0; irq < chip->g1_irq.nirqs; irq++)
406dc30c35bSAndrew Lunn 		irq_create_mapping(chip->g1_irq.domain, irq);
407dc30c35bSAndrew Lunn 
408dc30c35bSAndrew Lunn 	chip->g1_irq.chip = mv88e6xxx_g1_irq_chip;
409dc30c35bSAndrew Lunn 	chip->g1_irq.masked = ~0;
410dc30c35bSAndrew Lunn 
411d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
412dc30c35bSAndrew Lunn 	if (err)
4133dd0ef05SAndrew Lunn 		goto out_mapping;
414dc30c35bSAndrew Lunn 
4153dd0ef05SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
416dc30c35bSAndrew Lunn 
417d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
418dc30c35bSAndrew Lunn 	if (err)
4193dd0ef05SAndrew Lunn 		goto out_disable;
420dc30c35bSAndrew Lunn 
421dc30c35bSAndrew Lunn 	/* Reading the interrupt status clears (most of) them */
42282466921SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
423dc30c35bSAndrew Lunn 	if (err)
4243dd0ef05SAndrew Lunn 		goto out_disable;
425dc30c35bSAndrew Lunn 
426dc30c35bSAndrew Lunn 	return 0;
427dc30c35bSAndrew Lunn 
4283dd0ef05SAndrew Lunn out_disable:
4293d5fdba1SAndrew Lunn 	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
430d77f4321SVivien Didelot 	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
4313dd0ef05SAndrew Lunn 
4323dd0ef05SAndrew Lunn out_mapping:
4333dd0ef05SAndrew Lunn 	for (irq = 0; irq < 16; irq++) {
4343dd0ef05SAndrew Lunn 		virq = irq_find_mapping(chip->g1_irq.domain, irq);
4353dd0ef05SAndrew Lunn 		irq_dispose_mapping(virq);
4363dd0ef05SAndrew Lunn 	}
4373dd0ef05SAndrew Lunn 
4383dd0ef05SAndrew Lunn 	irq_domain_remove(chip->g1_irq.domain);
439dc30c35bSAndrew Lunn 
440dc30c35bSAndrew Lunn 	return err;
441dc30c35bSAndrew Lunn }
442dc30c35bSAndrew Lunn 
443294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
444294d711eSAndrew Lunn {
445f6d9758bSAndrew Lunn 	static struct lock_class_key lock_key;
446f6d9758bSAndrew Lunn 	static struct lock_class_key request_key;
447294d711eSAndrew Lunn 	int err;
448294d711eSAndrew Lunn 
449294d711eSAndrew Lunn 	err = mv88e6xxx_g1_irq_setup_common(chip);
450294d711eSAndrew Lunn 	if (err)
451294d711eSAndrew Lunn 		return err;
452294d711eSAndrew Lunn 
453f6d9758bSAndrew Lunn 	/* These lock classes tells lockdep that global 1 irqs are in
454f6d9758bSAndrew Lunn 	 * a different category than their parent GPIO, so it won't
455f6d9758bSAndrew Lunn 	 * report false recursion.
456f6d9758bSAndrew Lunn 	 */
457f6d9758bSAndrew Lunn 	irq_set_lockdep_class(chip->irq, &lock_key, &request_key);
458f6d9758bSAndrew Lunn 
459342a0ee7SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
460294d711eSAndrew Lunn 	err = request_threaded_irq(chip->irq, NULL,
461294d711eSAndrew Lunn 				   mv88e6xxx_g1_irq_thread_fn,
4620340376eSMarek Behún 				   IRQF_ONESHOT | IRQF_SHARED,
463294d711eSAndrew Lunn 				   dev_name(chip->dev), chip);
464342a0ee7SAndrew Lunn 	mutex_lock(&chip->reg_lock);
465294d711eSAndrew Lunn 	if (err)
466294d711eSAndrew Lunn 		mv88e6xxx_g1_irq_free_common(chip);
467294d711eSAndrew Lunn 
468294d711eSAndrew Lunn 	return err;
469294d711eSAndrew Lunn }
470294d711eSAndrew Lunn 
471294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work)
472294d711eSAndrew Lunn {
473294d711eSAndrew Lunn 	struct mv88e6xxx_chip *chip = container_of(work,
474294d711eSAndrew Lunn 						   struct mv88e6xxx_chip,
475294d711eSAndrew Lunn 						   irq_poll_work.work);
476294d711eSAndrew Lunn 	mv88e6xxx_g1_irq_thread_work(chip);
477294d711eSAndrew Lunn 
478294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
479294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
480294d711eSAndrew Lunn }
481294d711eSAndrew Lunn 
482294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip)
483294d711eSAndrew Lunn {
484294d711eSAndrew Lunn 	int err;
485294d711eSAndrew Lunn 
486294d711eSAndrew Lunn 	err = mv88e6xxx_g1_irq_setup_common(chip);
487294d711eSAndrew Lunn 	if (err)
488294d711eSAndrew Lunn 		return err;
489294d711eSAndrew Lunn 
490294d711eSAndrew Lunn 	kthread_init_delayed_work(&chip->irq_poll_work,
491294d711eSAndrew Lunn 				  mv88e6xxx_irq_poll);
492294d711eSAndrew Lunn 
4933f8b8696SFlorian Fainelli 	chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev));
494294d711eSAndrew Lunn 	if (IS_ERR(chip->kworker))
495294d711eSAndrew Lunn 		return PTR_ERR(chip->kworker);
496294d711eSAndrew Lunn 
497294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
498294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
499294d711eSAndrew Lunn 
500294d711eSAndrew Lunn 	return 0;
501294d711eSAndrew Lunn }
502294d711eSAndrew Lunn 
503294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip)
504294d711eSAndrew Lunn {
505294d711eSAndrew Lunn 	kthread_cancel_delayed_work_sync(&chip->irq_poll_work);
506294d711eSAndrew Lunn 	kthread_destroy_worker(chip->kworker);
5073d82475aSUwe Kleine-König 
5083d82475aSUwe Kleine-König 	mutex_lock(&chip->reg_lock);
5093d82475aSUwe Kleine-König 	mv88e6xxx_g1_irq_free_common(chip);
5103d82475aSUwe Kleine-König 	mutex_unlock(&chip->reg_lock);
511294d711eSAndrew Lunn }
512294d711eSAndrew Lunn 
513ec561276SVivien Didelot int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask)
5142d79af6eSVivien Didelot {
5156441e669SAndrew Lunn 	int i;
5162d79af6eSVivien Didelot 
5176441e669SAndrew Lunn 	for (i = 0; i < 16; i++) {
5182d79af6eSVivien Didelot 		u16 val;
5192d79af6eSVivien Didelot 		int err;
5202d79af6eSVivien Didelot 
5212d79af6eSVivien Didelot 		err = mv88e6xxx_read(chip, addr, reg, &val);
5222d79af6eSVivien Didelot 		if (err)
5232d79af6eSVivien Didelot 			return err;
5242d79af6eSVivien Didelot 
5252d79af6eSVivien Didelot 		if (!(val & mask))
5262d79af6eSVivien Didelot 			return 0;
5272d79af6eSVivien Didelot 
5282d79af6eSVivien Didelot 		usleep_range(1000, 2000);
5292d79af6eSVivien Didelot 	}
5302d79af6eSVivien Didelot 
53130853553SAndrew Lunn 	dev_err(chip->dev, "Timeout while waiting for switch\n");
5322d79af6eSVivien Didelot 	return -ETIMEDOUT;
5332d79af6eSVivien Didelot }
5342d79af6eSVivien Didelot 
535f22ab641SVivien Didelot /* Indirect write to single pointer-data register with an Update bit */
536ec561276SVivien Didelot int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update)
537f22ab641SVivien Didelot {
538f22ab641SVivien Didelot 	u16 val;
5390f02b4f7SAndrew Lunn 	int err;
540f22ab641SVivien Didelot 
541f22ab641SVivien Didelot 	/* Wait until the previous operation is completed */
5420f02b4f7SAndrew Lunn 	err = mv88e6xxx_wait(chip, addr, reg, BIT(15));
543f22ab641SVivien Didelot 	if (err)
544f22ab641SVivien Didelot 		return err;
545f22ab641SVivien Didelot 
546f22ab641SVivien Didelot 	/* Set the Update bit to trigger a write operation */
547f22ab641SVivien Didelot 	val = BIT(15) | update;
548f22ab641SVivien Didelot 
549f22ab641SVivien Didelot 	return mv88e6xxx_write(chip, addr, reg, val);
550f22ab641SVivien Didelot }
551f22ab641SVivien Didelot 
55272d8b4fdSHeiner Kallweit int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
55372d8b4fdSHeiner Kallweit 			     int speed, int duplex, int pause,
554d78343d2SVivien Didelot 			     phy_interface_t mode)
555d78343d2SVivien Didelot {
556d78343d2SVivien Didelot 	int err;
557d78343d2SVivien Didelot 
558d78343d2SVivien Didelot 	if (!chip->info->ops->port_set_link)
559d78343d2SVivien Didelot 		return 0;
560d78343d2SVivien Didelot 
561d78343d2SVivien Didelot 	/* Port's MAC control must not be changed unless the link is down */
562d78343d2SVivien Didelot 	err = chip->info->ops->port_set_link(chip, port, 0);
563d78343d2SVivien Didelot 	if (err)
564d78343d2SVivien Didelot 		return err;
565d78343d2SVivien Didelot 
566d78343d2SVivien Didelot 	if (chip->info->ops->port_set_speed) {
567d78343d2SVivien Didelot 		err = chip->info->ops->port_set_speed(chip, port, speed);
568d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
569d78343d2SVivien Didelot 			goto restore_link;
570d78343d2SVivien Didelot 	}
571d78343d2SVivien Didelot 
57254186b91SAndrew Lunn 	if (chip->info->ops->port_set_pause) {
57354186b91SAndrew Lunn 		err = chip->info->ops->port_set_pause(chip, port, pause);
57454186b91SAndrew Lunn 		if (err)
57554186b91SAndrew Lunn 			goto restore_link;
57654186b91SAndrew Lunn 	}
57754186b91SAndrew Lunn 
578d78343d2SVivien Didelot 	if (chip->info->ops->port_set_duplex) {
579d78343d2SVivien Didelot 		err = chip->info->ops->port_set_duplex(chip, port, duplex);
580d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
581d78343d2SVivien Didelot 			goto restore_link;
582d78343d2SVivien Didelot 	}
583d78343d2SVivien Didelot 
584d78343d2SVivien Didelot 	if (chip->info->ops->port_set_rgmii_delay) {
585d78343d2SVivien Didelot 		err = chip->info->ops->port_set_rgmii_delay(chip, port, mode);
586d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
587d78343d2SVivien Didelot 			goto restore_link;
588d78343d2SVivien Didelot 	}
589d78343d2SVivien Didelot 
590f39908d3SAndrew Lunn 	if (chip->info->ops->port_set_cmode) {
591f39908d3SAndrew Lunn 		err = chip->info->ops->port_set_cmode(chip, port, mode);
592f39908d3SAndrew Lunn 		if (err && err != -EOPNOTSUPP)
593f39908d3SAndrew Lunn 			goto restore_link;
594f39908d3SAndrew Lunn 	}
595f39908d3SAndrew Lunn 
596d78343d2SVivien Didelot 	err = 0;
597d78343d2SVivien Didelot restore_link:
598d78343d2SVivien Didelot 	if (chip->info->ops->port_set_link(chip, port, link))
599774439e5SVivien Didelot 		dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
600d78343d2SVivien Didelot 
601d78343d2SVivien Didelot 	return err;
602d78343d2SVivien Didelot }
603d78343d2SVivien Didelot 
604d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
605d700ec41SMarek Vasut {
606d700ec41SMarek Vasut 	struct mv88e6xxx_chip *chip = ds->priv;
607d700ec41SMarek Vasut 
608d700ec41SMarek Vasut 	return port < chip->info->num_internal_phys;
609d700ec41SMarek Vasut }
610d700ec41SMarek Vasut 
611fad09c73SVivien Didelot /* We expect the switch to perform auto negotiation if there is a real
612fad09c73SVivien Didelot  * phy. However, in the case of a fixed link phy, we force the port
613fad09c73SVivien Didelot  * settings from the fixed link settings.
614fad09c73SVivien Didelot  */
615fad09c73SVivien Didelot static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
616fad09c73SVivien Didelot 				  struct phy_device *phydev)
617fad09c73SVivien Didelot {
61804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
6190e7b9925SAndrew Lunn 	int err;
620fad09c73SVivien Didelot 
621d700ec41SMarek Vasut 	if (!phy_is_pseudo_fixed_link(phydev) &&
622d700ec41SMarek Vasut 	    mv88e6xxx_phy_is_internal(ds, port))
623fad09c73SVivien Didelot 		return;
624fad09c73SVivien Didelot 
625fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
626d78343d2SVivien Didelot 	err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
62754186b91SAndrew Lunn 				       phydev->duplex, phydev->pause,
62854186b91SAndrew Lunn 				       phydev->interface);
629fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
630d78343d2SVivien Didelot 
631d78343d2SVivien Didelot 	if (err && err != -EOPNOTSUPP)
632774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
633fad09c73SVivien Didelot }
634fad09c73SVivien Didelot 
6356c422e34SRussell King static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6366c422e34SRussell King 				       unsigned long *mask,
6376c422e34SRussell King 				       struct phylink_link_state *state)
6386c422e34SRussell King {
6396c422e34SRussell King 	if (!phy_interface_mode_is_8023z(state->interface)) {
6406c422e34SRussell King 		/* 10M and 100M are only supported in non-802.3z mode */
6416c422e34SRussell King 		phylink_set(mask, 10baseT_Half);
6426c422e34SRussell King 		phylink_set(mask, 10baseT_Full);
6436c422e34SRussell King 		phylink_set(mask, 100baseT_Half);
6446c422e34SRussell King 		phylink_set(mask, 100baseT_Full);
6456c422e34SRussell King 	}
6466c422e34SRussell King }
6476c422e34SRussell King 
6486c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6496c422e34SRussell King 				       unsigned long *mask,
6506c422e34SRussell King 				       struct phylink_link_state *state)
6516c422e34SRussell King {
6526c422e34SRussell King 	/* FIXME: if the port is in 1000Base-X mode, then it only supports
6536c422e34SRussell King 	 * 1000M FD speeds.  In this case, CMODE will indicate 5.
6546c422e34SRussell King 	 */
6556c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
6566c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
6576c422e34SRussell King 
6586c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
6596c422e34SRussell King }
6606c422e34SRussell King 
661e3af71a3SMarek Behún static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port,
662e3af71a3SMarek Behún 				       unsigned long *mask,
663e3af71a3SMarek Behún 				       struct phylink_link_state *state)
664e3af71a3SMarek Behún {
665e3af71a3SMarek Behún 	if (port >= 5)
666e3af71a3SMarek Behún 		phylink_set(mask, 2500baseX_Full);
667e3af71a3SMarek Behún 
668e3af71a3SMarek Behún 	/* No ethtool bits for 200Mbps */
669e3af71a3SMarek Behún 	phylink_set(mask, 1000baseT_Full);
670e3af71a3SMarek Behún 	phylink_set(mask, 1000baseX_Full);
671e3af71a3SMarek Behún 
672e3af71a3SMarek Behún 	mv88e6065_phylink_validate(chip, port, mask, state);
673e3af71a3SMarek Behún }
674e3af71a3SMarek Behún 
6756c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6766c422e34SRussell King 				       unsigned long *mask,
6776c422e34SRussell King 				       struct phylink_link_state *state)
6786c422e34SRussell King {
6796c422e34SRussell King 	/* No ethtool bits for 200Mbps */
6806c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
6816c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
6826c422e34SRussell King 
6836c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
6846c422e34SRussell King }
6856c422e34SRussell King 
6866c422e34SRussell King static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6876c422e34SRussell King 				       unsigned long *mask,
6886c422e34SRussell King 				       struct phylink_link_state *state)
6896c422e34SRussell King {
690ec26016bSAndrew Lunn 	if (port >= 9) {
6916c422e34SRussell King 		phylink_set(mask, 2500baseX_Full);
692ec26016bSAndrew Lunn 		phylink_set(mask, 2500baseT_Full);
693ec26016bSAndrew Lunn 	}
6946c422e34SRussell King 
6956c422e34SRussell King 	/* No ethtool bits for 200Mbps */
6966c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
6976c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
6986c422e34SRussell King 
6996c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
7006c422e34SRussell King }
7016c422e34SRussell King 
7026c422e34SRussell King static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
7036c422e34SRussell King 					unsigned long *mask,
7046c422e34SRussell King 					struct phylink_link_state *state)
7056c422e34SRussell King {
7066c422e34SRussell King 	if (port >= 9) {
7076c422e34SRussell King 		phylink_set(mask, 10000baseT_Full);
7086c422e34SRussell King 		phylink_set(mask, 10000baseKR_Full);
7096c422e34SRussell King 	}
7106c422e34SRussell King 
7116c422e34SRussell King 	mv88e6390_phylink_validate(chip, port, mask, state);
7126c422e34SRussell King }
7136c422e34SRussell King 
714c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
715c9a2356fSRussell King 			       unsigned long *supported,
716c9a2356fSRussell King 			       struct phylink_link_state *state)
717c9a2356fSRussell King {
7186c422e34SRussell King 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
7196c422e34SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
7206c422e34SRussell King 
7216c422e34SRussell King 	/* Allow all the expected bits */
7226c422e34SRussell King 	phylink_set(mask, Autoneg);
7236c422e34SRussell King 	phylink_set(mask, Pause);
7246c422e34SRussell King 	phylink_set_port_modes(mask);
7256c422e34SRussell King 
7266c422e34SRussell King 	if (chip->info->ops->phylink_validate)
7276c422e34SRussell King 		chip->info->ops->phylink_validate(chip, port, mask, state);
7286c422e34SRussell King 
7296c422e34SRussell King 	bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
7306c422e34SRussell King 	bitmap_and(state->advertising, state->advertising, mask,
7316c422e34SRussell King 		   __ETHTOOL_LINK_MODE_MASK_NBITS);
7326c422e34SRussell King 
7336c422e34SRussell King 	/* We can only operate at 2500BaseX or 1000BaseX.  If requested
7346c422e34SRussell King 	 * to advertise both, only report advertising at 2500BaseX.
7356c422e34SRussell King 	 */
7366c422e34SRussell King 	phylink_helper_basex_speed(state);
737c9a2356fSRussell King }
738c9a2356fSRussell King 
739c9a2356fSRussell King static int mv88e6xxx_link_state(struct dsa_switch *ds, int port,
740c9a2356fSRussell King 				struct phylink_link_state *state)
741c9a2356fSRussell King {
742c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
743c9a2356fSRussell King 	int err;
744c9a2356fSRussell King 
745c9a2356fSRussell King 	mutex_lock(&chip->reg_lock);
7466c422e34SRussell King 	if (chip->info->ops->port_link_state)
7476c422e34SRussell King 		err = chip->info->ops->port_link_state(chip, port, state);
7486c422e34SRussell King 	else
7496c422e34SRussell King 		err = -EOPNOTSUPP;
750c9a2356fSRussell King 	mutex_unlock(&chip->reg_lock);
751c9a2356fSRussell King 
752c9a2356fSRussell King 	return err;
753c9a2356fSRussell King }
754c9a2356fSRussell King 
755c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
756c9a2356fSRussell King 				 unsigned int mode,
757c9a2356fSRussell King 				 const struct phylink_link_state *state)
758c9a2356fSRussell King {
759c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
76054186b91SAndrew Lunn 	int speed, duplex, link, pause, err;
761c9a2356fSRussell King 
762d700ec41SMarek Vasut 	if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port))
763c9a2356fSRussell King 		return;
764c9a2356fSRussell King 
765c9a2356fSRussell King 	if (mode == MLO_AN_FIXED) {
766c9a2356fSRussell King 		link = LINK_FORCED_UP;
767c9a2356fSRussell King 		speed = state->speed;
768c9a2356fSRussell King 		duplex = state->duplex;
769d700ec41SMarek Vasut 	} else if (!mv88e6xxx_phy_is_internal(ds, port)) {
770d700ec41SMarek Vasut 		link = state->link;
771d700ec41SMarek Vasut 		speed = state->speed;
772d700ec41SMarek Vasut 		duplex = state->duplex;
773c9a2356fSRussell King 	} else {
774c9a2356fSRussell King 		speed = SPEED_UNFORCED;
775c9a2356fSRussell King 		duplex = DUPLEX_UNFORCED;
776c9a2356fSRussell King 		link = LINK_UNFORCED;
777c9a2356fSRussell King 	}
77854186b91SAndrew Lunn 	pause = !!phylink_test(state->advertising, Pause);
779c9a2356fSRussell King 
780c9a2356fSRussell King 	mutex_lock(&chip->reg_lock);
78154186b91SAndrew Lunn 	err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, pause,
782c9a2356fSRussell King 				       state->interface);
783c9a2356fSRussell King 	mutex_unlock(&chip->reg_lock);
784c9a2356fSRussell King 
785c9a2356fSRussell King 	if (err && err != -EOPNOTSUPP)
786c9a2356fSRussell King 		dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
787c9a2356fSRussell King }
788c9a2356fSRussell King 
789c9a2356fSRussell King static void mv88e6xxx_mac_link_force(struct dsa_switch *ds, int port, int link)
790c9a2356fSRussell King {
791c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
792c9a2356fSRussell King 	int err;
793c9a2356fSRussell King 
794c9a2356fSRussell King 	mutex_lock(&chip->reg_lock);
795c9a2356fSRussell King 	err = chip->info->ops->port_set_link(chip, port, link);
796c9a2356fSRussell King 	mutex_unlock(&chip->reg_lock);
797c9a2356fSRussell King 
798c9a2356fSRussell King 	if (err)
799c9a2356fSRussell King 		dev_err(chip->dev, "p%d: failed to force MAC link\n", port);
800c9a2356fSRussell King }
801c9a2356fSRussell King 
802c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
803c9a2356fSRussell King 				    unsigned int mode,
804c9a2356fSRussell King 				    phy_interface_t interface)
805c9a2356fSRussell King {
806c9a2356fSRussell King 	if (mode == MLO_AN_FIXED)
807c9a2356fSRussell King 		mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_DOWN);
808c9a2356fSRussell King }
809c9a2356fSRussell King 
810c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
811c9a2356fSRussell King 				  unsigned int mode, phy_interface_t interface,
812c9a2356fSRussell King 				  struct phy_device *phydev)
813c9a2356fSRussell King {
814c9a2356fSRussell King 	if (mode == MLO_AN_FIXED)
815c9a2356fSRussell King 		mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_UP);
816c9a2356fSRussell King }
817c9a2356fSRussell King 
818a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
819fad09c73SVivien Didelot {
820a605a0feSAndrew Lunn 	if (!chip->info->ops->stats_snapshot)
821a605a0feSAndrew Lunn 		return -EOPNOTSUPP;
822fad09c73SVivien Didelot 
823a605a0feSAndrew Lunn 	return chip->info->ops->stats_snapshot(chip, port);
824fad09c73SVivien Didelot }
825fad09c73SVivien Didelot 
826fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
827dfafe449SAndrew Lunn 	{ "in_good_octets",		8, 0x00, STATS_TYPE_BANK0, },
828dfafe449SAndrew Lunn 	{ "in_bad_octets",		4, 0x02, STATS_TYPE_BANK0, },
829dfafe449SAndrew Lunn 	{ "in_unicast",			4, 0x04, STATS_TYPE_BANK0, },
830dfafe449SAndrew Lunn 	{ "in_broadcasts",		4, 0x06, STATS_TYPE_BANK0, },
831dfafe449SAndrew Lunn 	{ "in_multicasts",		4, 0x07, STATS_TYPE_BANK0, },
832dfafe449SAndrew Lunn 	{ "in_pause",			4, 0x16, STATS_TYPE_BANK0, },
833dfafe449SAndrew Lunn 	{ "in_undersize",		4, 0x18, STATS_TYPE_BANK0, },
834dfafe449SAndrew Lunn 	{ "in_fragments",		4, 0x19, STATS_TYPE_BANK0, },
835dfafe449SAndrew Lunn 	{ "in_oversize",		4, 0x1a, STATS_TYPE_BANK0, },
836dfafe449SAndrew Lunn 	{ "in_jabber",			4, 0x1b, STATS_TYPE_BANK0, },
837dfafe449SAndrew Lunn 	{ "in_rx_error",		4, 0x1c, STATS_TYPE_BANK0, },
838dfafe449SAndrew Lunn 	{ "in_fcs_error",		4, 0x1d, STATS_TYPE_BANK0, },
839dfafe449SAndrew Lunn 	{ "out_octets",			8, 0x0e, STATS_TYPE_BANK0, },
840dfafe449SAndrew Lunn 	{ "out_unicast",		4, 0x10, STATS_TYPE_BANK0, },
841dfafe449SAndrew Lunn 	{ "out_broadcasts",		4, 0x13, STATS_TYPE_BANK0, },
842dfafe449SAndrew Lunn 	{ "out_multicasts",		4, 0x12, STATS_TYPE_BANK0, },
843dfafe449SAndrew Lunn 	{ "out_pause",			4, 0x15, STATS_TYPE_BANK0, },
844dfafe449SAndrew Lunn 	{ "excessive",			4, 0x11, STATS_TYPE_BANK0, },
845dfafe449SAndrew Lunn 	{ "collisions",			4, 0x1e, STATS_TYPE_BANK0, },
846dfafe449SAndrew Lunn 	{ "deferred",			4, 0x05, STATS_TYPE_BANK0, },
847dfafe449SAndrew Lunn 	{ "single",			4, 0x14, STATS_TYPE_BANK0, },
848dfafe449SAndrew Lunn 	{ "multiple",			4, 0x17, STATS_TYPE_BANK0, },
849dfafe449SAndrew Lunn 	{ "out_fcs_error",		4, 0x03, STATS_TYPE_BANK0, },
850dfafe449SAndrew Lunn 	{ "late",			4, 0x1f, STATS_TYPE_BANK0, },
851dfafe449SAndrew Lunn 	{ "hist_64bytes",		4, 0x08, STATS_TYPE_BANK0, },
852dfafe449SAndrew Lunn 	{ "hist_65_127bytes",		4, 0x09, STATS_TYPE_BANK0, },
853dfafe449SAndrew Lunn 	{ "hist_128_255bytes",		4, 0x0a, STATS_TYPE_BANK0, },
854dfafe449SAndrew Lunn 	{ "hist_256_511bytes",		4, 0x0b, STATS_TYPE_BANK0, },
855dfafe449SAndrew Lunn 	{ "hist_512_1023bytes",		4, 0x0c, STATS_TYPE_BANK0, },
856dfafe449SAndrew Lunn 	{ "hist_1024_max_bytes",	4, 0x0d, STATS_TYPE_BANK0, },
857dfafe449SAndrew Lunn 	{ "sw_in_discards",		4, 0x10, STATS_TYPE_PORT, },
858dfafe449SAndrew Lunn 	{ "sw_in_filtered",		2, 0x12, STATS_TYPE_PORT, },
859dfafe449SAndrew Lunn 	{ "sw_out_filtered",		2, 0x13, STATS_TYPE_PORT, },
860dfafe449SAndrew Lunn 	{ "in_discards",		4, 0x00, STATS_TYPE_BANK1, },
861dfafe449SAndrew Lunn 	{ "in_filtered",		4, 0x01, STATS_TYPE_BANK1, },
862dfafe449SAndrew Lunn 	{ "in_accepted",		4, 0x02, STATS_TYPE_BANK1, },
863dfafe449SAndrew Lunn 	{ "in_bad_accepted",		4, 0x03, STATS_TYPE_BANK1, },
864dfafe449SAndrew Lunn 	{ "in_good_avb_class_a",	4, 0x04, STATS_TYPE_BANK1, },
865dfafe449SAndrew Lunn 	{ "in_good_avb_class_b",	4, 0x05, STATS_TYPE_BANK1, },
866dfafe449SAndrew Lunn 	{ "in_bad_avb_class_a",		4, 0x06, STATS_TYPE_BANK1, },
867dfafe449SAndrew Lunn 	{ "in_bad_avb_class_b",		4, 0x07, STATS_TYPE_BANK1, },
868dfafe449SAndrew Lunn 	{ "tcam_counter_0",		4, 0x08, STATS_TYPE_BANK1, },
869dfafe449SAndrew Lunn 	{ "tcam_counter_1",		4, 0x09, STATS_TYPE_BANK1, },
870dfafe449SAndrew Lunn 	{ "tcam_counter_2",		4, 0x0a, STATS_TYPE_BANK1, },
871dfafe449SAndrew Lunn 	{ "tcam_counter_3",		4, 0x0b, STATS_TYPE_BANK1, },
872dfafe449SAndrew Lunn 	{ "in_da_unknown",		4, 0x0e, STATS_TYPE_BANK1, },
873dfafe449SAndrew Lunn 	{ "in_management",		4, 0x0f, STATS_TYPE_BANK1, },
874dfafe449SAndrew Lunn 	{ "out_queue_0",		4, 0x10, STATS_TYPE_BANK1, },
875dfafe449SAndrew Lunn 	{ "out_queue_1",		4, 0x11, STATS_TYPE_BANK1, },
876dfafe449SAndrew Lunn 	{ "out_queue_2",		4, 0x12, STATS_TYPE_BANK1, },
877dfafe449SAndrew Lunn 	{ "out_queue_3",		4, 0x13, STATS_TYPE_BANK1, },
878dfafe449SAndrew Lunn 	{ "out_queue_4",		4, 0x14, STATS_TYPE_BANK1, },
879dfafe449SAndrew Lunn 	{ "out_queue_5",		4, 0x15, STATS_TYPE_BANK1, },
880dfafe449SAndrew Lunn 	{ "out_queue_6",		4, 0x16, STATS_TYPE_BANK1, },
881dfafe449SAndrew Lunn 	{ "out_queue_7",		4, 0x17, STATS_TYPE_BANK1, },
882dfafe449SAndrew Lunn 	{ "out_cut_through",		4, 0x18, STATS_TYPE_BANK1, },
883dfafe449SAndrew Lunn 	{ "out_octets_a",		4, 0x1a, STATS_TYPE_BANK1, },
884dfafe449SAndrew Lunn 	{ "out_octets_b",		4, 0x1b, STATS_TYPE_BANK1, },
885dfafe449SAndrew Lunn 	{ "out_management",		4, 0x1f, STATS_TYPE_BANK1, },
886fad09c73SVivien Didelot };
887fad09c73SVivien Didelot 
888fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
889fad09c73SVivien Didelot 					    struct mv88e6xxx_hw_stat *s,
890e0d8b615SAndrew Lunn 					    int port, u16 bank1_select,
891e0d8b615SAndrew Lunn 					    u16 histogram)
892fad09c73SVivien Didelot {
893fad09c73SVivien Didelot 	u32 low;
894fad09c73SVivien Didelot 	u32 high = 0;
895dfafe449SAndrew Lunn 	u16 reg = 0;
8960e7b9925SAndrew Lunn 	int err;
897fad09c73SVivien Didelot 	u64 value;
898fad09c73SVivien Didelot 
899fad09c73SVivien Didelot 	switch (s->type) {
900dfafe449SAndrew Lunn 	case STATS_TYPE_PORT:
9010e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
9020e7b9925SAndrew Lunn 		if (err)
9036c3442f5SJisheng Zhang 			return U64_MAX;
904fad09c73SVivien Didelot 
9050e7b9925SAndrew Lunn 		low = reg;
906cda9f4aaSAndrew Lunn 		if (s->size == 4) {
9070e7b9925SAndrew Lunn 			err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
9080e7b9925SAndrew Lunn 			if (err)
9096c3442f5SJisheng Zhang 				return U64_MAX;
9100e7b9925SAndrew Lunn 			high = reg;
911fad09c73SVivien Didelot 		}
912fad09c73SVivien Didelot 		break;
913dfafe449SAndrew Lunn 	case STATS_TYPE_BANK1:
914e0d8b615SAndrew Lunn 		reg = bank1_select;
915dfafe449SAndrew Lunn 		/* fall through */
916dfafe449SAndrew Lunn 	case STATS_TYPE_BANK0:
917e0d8b615SAndrew Lunn 		reg |= s->reg | histogram;
9187f9ef3afSAndrew Lunn 		mv88e6xxx_g1_stats_read(chip, reg, &low);
919cda9f4aaSAndrew Lunn 		if (s->size == 8)
9207f9ef3afSAndrew Lunn 			mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
9219fc3e4dcSGustavo A. R. Silva 		break;
9229fc3e4dcSGustavo A. R. Silva 	default:
9236c3442f5SJisheng Zhang 		return U64_MAX;
924fad09c73SVivien Didelot 	}
9256e46e2d8SAndrew Lunn 	value = (((u64)high) << 32) | low;
926fad09c73SVivien Didelot 	return value;
927fad09c73SVivien Didelot }
928fad09c73SVivien Didelot 
929436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
930dfafe449SAndrew Lunn 				       uint8_t *data, int types)
931fad09c73SVivien Didelot {
932fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
933fad09c73SVivien Didelot 	int i, j;
934fad09c73SVivien Didelot 
935fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
936fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
937dfafe449SAndrew Lunn 		if (stat->type & types) {
938fad09c73SVivien Didelot 			memcpy(data + j * ETH_GSTRING_LEN, stat->string,
939fad09c73SVivien Didelot 			       ETH_GSTRING_LEN);
940fad09c73SVivien Didelot 			j++;
941fad09c73SVivien Didelot 		}
942fad09c73SVivien Didelot 	}
943436fe17dSAndrew Lunn 
944436fe17dSAndrew Lunn 	return j;
945fad09c73SVivien Didelot }
946fad09c73SVivien Didelot 
947436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
948dfafe449SAndrew Lunn 				       uint8_t *data)
949dfafe449SAndrew Lunn {
950436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
951dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_PORT);
952dfafe449SAndrew Lunn }
953dfafe449SAndrew Lunn 
954436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
955dfafe449SAndrew Lunn 				       uint8_t *data)
956dfafe449SAndrew Lunn {
957436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
958dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
959dfafe449SAndrew Lunn }
960dfafe449SAndrew Lunn 
96165f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = {
96265f60e45SAndrew Lunn 	"atu_member_violation",
96365f60e45SAndrew Lunn 	"atu_miss_violation",
96465f60e45SAndrew Lunn 	"atu_full_violation",
96565f60e45SAndrew Lunn 	"vtu_member_violation",
96665f60e45SAndrew Lunn 	"vtu_miss_violation",
96765f60e45SAndrew Lunn };
96865f60e45SAndrew Lunn 
96965f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data)
97065f60e45SAndrew Lunn {
97165f60e45SAndrew Lunn 	unsigned int i;
97265f60e45SAndrew Lunn 
97365f60e45SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++)
97465f60e45SAndrew Lunn 		strlcpy(data + i * ETH_GSTRING_LEN,
97565f60e45SAndrew Lunn 			mv88e6xxx_atu_vtu_stats_strings[i],
97665f60e45SAndrew Lunn 			ETH_GSTRING_LEN);
97765f60e45SAndrew Lunn }
97865f60e45SAndrew Lunn 
979dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
98089f09048SFlorian Fainelli 				  u32 stringset, uint8_t *data)
981fad09c73SVivien Didelot {
98204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
983436fe17dSAndrew Lunn 	int count = 0;
984dfafe449SAndrew Lunn 
98589f09048SFlorian Fainelli 	if (stringset != ETH_SS_STATS)
98689f09048SFlorian Fainelli 		return;
98789f09048SFlorian Fainelli 
988c6c8cd5eSAndrew Lunn 	mutex_lock(&chip->reg_lock);
989c6c8cd5eSAndrew Lunn 
990dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_strings)
991436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_strings(chip, data);
992436fe17dSAndrew Lunn 
993436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_strings) {
994436fe17dSAndrew Lunn 		data += count * ETH_GSTRING_LEN;
99565f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_strings(chip, port, data);
996436fe17dSAndrew Lunn 	}
997c6c8cd5eSAndrew Lunn 
99865f60e45SAndrew Lunn 	data += count * ETH_GSTRING_LEN;
99965f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_strings(data);
100065f60e45SAndrew Lunn 
1001c6c8cd5eSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
1002dfafe449SAndrew Lunn }
1003dfafe449SAndrew Lunn 
1004dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
1005dfafe449SAndrew Lunn 					  int types)
1006dfafe449SAndrew Lunn {
1007fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
1008fad09c73SVivien Didelot 	int i, j;
1009fad09c73SVivien Didelot 
1010fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
1011fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
1012dfafe449SAndrew Lunn 		if (stat->type & types)
1013fad09c73SVivien Didelot 			j++;
1014fad09c73SVivien Didelot 	}
1015fad09c73SVivien Didelot 	return j;
1016fad09c73SVivien Didelot }
1017fad09c73SVivien Didelot 
1018dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
1019dfafe449SAndrew Lunn {
1020dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
1021dfafe449SAndrew Lunn 					      STATS_TYPE_PORT);
1022dfafe449SAndrew Lunn }
1023dfafe449SAndrew Lunn 
1024dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
1025dfafe449SAndrew Lunn {
1026dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
1027dfafe449SAndrew Lunn 					      STATS_TYPE_BANK1);
1028dfafe449SAndrew Lunn }
1029dfafe449SAndrew Lunn 
103089f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
1031dfafe449SAndrew Lunn {
1032dfafe449SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
1033436fe17dSAndrew Lunn 	int serdes_count = 0;
1034436fe17dSAndrew Lunn 	int count = 0;
1035dfafe449SAndrew Lunn 
103689f09048SFlorian Fainelli 	if (sset != ETH_SS_STATS)
103789f09048SFlorian Fainelli 		return 0;
103889f09048SFlorian Fainelli 
1039c6c8cd5eSAndrew Lunn 	mutex_lock(&chip->reg_lock);
1040dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_sset_count)
1041436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_sset_count(chip);
1042436fe17dSAndrew Lunn 	if (count < 0)
1043436fe17dSAndrew Lunn 		goto out;
1044436fe17dSAndrew Lunn 
1045436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_sset_count)
1046436fe17dSAndrew Lunn 		serdes_count = chip->info->ops->serdes_get_sset_count(chip,
1047436fe17dSAndrew Lunn 								      port);
104865f60e45SAndrew Lunn 	if (serdes_count < 0) {
1049436fe17dSAndrew Lunn 		count = serdes_count;
105065f60e45SAndrew Lunn 		goto out;
105165f60e45SAndrew Lunn 	}
1052436fe17dSAndrew Lunn 	count += serdes_count;
105365f60e45SAndrew Lunn 	count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings);
105465f60e45SAndrew Lunn 
1055436fe17dSAndrew Lunn out:
1056c6c8cd5eSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
1057dfafe449SAndrew Lunn 
1058436fe17dSAndrew Lunn 	return count;
1059dfafe449SAndrew Lunn }
1060dfafe449SAndrew Lunn 
1061436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1062e0d8b615SAndrew Lunn 				     uint64_t *data, int types,
1063e0d8b615SAndrew Lunn 				     u16 bank1_select, u16 histogram)
1064052f947fSAndrew Lunn {
1065052f947fSAndrew Lunn 	struct mv88e6xxx_hw_stat *stat;
1066052f947fSAndrew Lunn 	int i, j;
1067052f947fSAndrew Lunn 
1068052f947fSAndrew Lunn 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
1069052f947fSAndrew Lunn 		stat = &mv88e6xxx_hw_stats[i];
1070052f947fSAndrew Lunn 		if (stat->type & types) {
1071377cda13SAndrew Lunn 			mutex_lock(&chip->reg_lock);
1072e0d8b615SAndrew Lunn 			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
1073e0d8b615SAndrew Lunn 							      bank1_select,
1074e0d8b615SAndrew Lunn 							      histogram);
1075377cda13SAndrew Lunn 			mutex_unlock(&chip->reg_lock);
1076377cda13SAndrew Lunn 
1077052f947fSAndrew Lunn 			j++;
1078052f947fSAndrew Lunn 		}
1079052f947fSAndrew Lunn 	}
1080436fe17dSAndrew Lunn 	return j;
1081052f947fSAndrew Lunn }
1082052f947fSAndrew Lunn 
1083436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1084052f947fSAndrew Lunn 				     uint64_t *data)
1085052f947fSAndrew Lunn {
1086052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1087e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
108857d1ef38SVivien Didelot 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1089052f947fSAndrew Lunn }
1090052f947fSAndrew Lunn 
1091436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1092052f947fSAndrew Lunn 				     uint64_t *data)
1093052f947fSAndrew Lunn {
1094052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1095e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
109657d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
109757d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1098e0d8b615SAndrew Lunn }
1099e0d8b615SAndrew Lunn 
1100436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1101e0d8b615SAndrew Lunn 				     uint64_t *data)
1102e0d8b615SAndrew Lunn {
1103e0d8b615SAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1104e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
110557d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
110657d1ef38SVivien Didelot 					 0);
1107052f947fSAndrew Lunn }
1108052f947fSAndrew Lunn 
110965f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
111065f60e45SAndrew Lunn 					uint64_t *data)
111165f60e45SAndrew Lunn {
111265f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_member_violation;
111365f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_miss_violation;
111465f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_full_violation;
111565f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_member_violation;
111665f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_miss_violation;
111765f60e45SAndrew Lunn }
111865f60e45SAndrew Lunn 
1119052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
1120052f947fSAndrew Lunn 				uint64_t *data)
1121052f947fSAndrew Lunn {
1122436fe17dSAndrew Lunn 	int count = 0;
1123436fe17dSAndrew Lunn 
1124052f947fSAndrew Lunn 	if (chip->info->ops->stats_get_stats)
1125436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_stats(chip, port, data);
1126436fe17dSAndrew Lunn 
112765f60e45SAndrew Lunn 	mutex_lock(&chip->reg_lock);
1128436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_stats) {
1129436fe17dSAndrew Lunn 		data += count;
113065f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_stats(chip, port, data);
1131436fe17dSAndrew Lunn 	}
113265f60e45SAndrew Lunn 	data += count;
113365f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_stats(chip, port, data);
113465f60e45SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
1135052f947fSAndrew Lunn }
1136052f947fSAndrew Lunn 
1137fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
1138fad09c73SVivien Didelot 					uint64_t *data)
1139fad09c73SVivien Didelot {
114004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1141fad09c73SVivien Didelot 	int ret;
1142fad09c73SVivien Didelot 
1143fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1144fad09c73SVivien Didelot 
1145a605a0feSAndrew Lunn 	ret = mv88e6xxx_stats_snapshot(chip, port);
1146fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1147377cda13SAndrew Lunn 
1148377cda13SAndrew Lunn 	if (ret < 0)
1149fad09c73SVivien Didelot 		return;
1150052f947fSAndrew Lunn 
1151052f947fSAndrew Lunn 	mv88e6xxx_get_stats(chip, port, data);
1152fad09c73SVivien Didelot 
1153fad09c73SVivien Didelot }
1154fad09c73SVivien Didelot 
1155fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
1156fad09c73SVivien Didelot {
1157fad09c73SVivien Didelot 	return 32 * sizeof(u16);
1158fad09c73SVivien Didelot }
1159fad09c73SVivien Didelot 
1160fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
1161fad09c73SVivien Didelot 			       struct ethtool_regs *regs, void *_p)
1162fad09c73SVivien Didelot {
116304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
11640e7b9925SAndrew Lunn 	int err;
11650e7b9925SAndrew Lunn 	u16 reg;
1166fad09c73SVivien Didelot 	u16 *p = _p;
1167fad09c73SVivien Didelot 	int i;
1168fad09c73SVivien Didelot 
1169a5f39326SVivien Didelot 	regs->version = chip->info->prod_num;
1170fad09c73SVivien Didelot 
1171fad09c73SVivien Didelot 	memset(p, 0xff, 32 * sizeof(u16));
1172fad09c73SVivien Didelot 
1173fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1174fad09c73SVivien Didelot 
1175fad09c73SVivien Didelot 	for (i = 0; i < 32; i++) {
1176fad09c73SVivien Didelot 
11770e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, i, &reg);
11780e7b9925SAndrew Lunn 		if (!err)
11790e7b9925SAndrew Lunn 			p[i] = reg;
1180fad09c73SVivien Didelot 	}
1181fad09c73SVivien Didelot 
1182fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1183fad09c73SVivien Didelot }
1184fad09c73SVivien Didelot 
118508f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
1186fad09c73SVivien Didelot 				 struct ethtool_eee *e)
1187fad09c73SVivien Didelot {
11885480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
11895480db69SVivien Didelot 	return 0;
1190fad09c73SVivien Didelot }
1191fad09c73SVivien Didelot 
119208f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port,
119346587e4aSVivien Didelot 				 struct ethtool_eee *e)
1194fad09c73SVivien Didelot {
11955480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
11965480db69SVivien Didelot 	return 0;
1197fad09c73SVivien Didelot }
1198fad09c73SVivien Didelot 
1199e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
1200fad09c73SVivien Didelot {
1201e5887a2aSVivien Didelot 	struct dsa_switch *ds = NULL;
1202e5887a2aSVivien Didelot 	struct net_device *br;
1203e5887a2aSVivien Didelot 	u16 pvlan;
1204fad09c73SVivien Didelot 	int i;
1205fad09c73SVivien Didelot 
1206e5887a2aSVivien Didelot 	if (dev < DSA_MAX_SWITCHES)
1207e5887a2aSVivien Didelot 		ds = chip->ds->dst->ds[dev];
1208fad09c73SVivien Didelot 
1209e5887a2aSVivien Didelot 	/* Prevent frames from unknown switch or port */
1210e5887a2aSVivien Didelot 	if (!ds || port >= ds->num_ports)
1211e5887a2aSVivien Didelot 		return 0;
1212e5887a2aSVivien Didelot 
1213e5887a2aSVivien Didelot 	/* Frames from DSA links and CPU ports can egress any local port */
1214e5887a2aSVivien Didelot 	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
1215e5887a2aSVivien Didelot 		return mv88e6xxx_port_mask(chip);
1216e5887a2aSVivien Didelot 
1217e5887a2aSVivien Didelot 	br = ds->ports[port].bridge_dev;
1218e5887a2aSVivien Didelot 	pvlan = 0;
1219e5887a2aSVivien Didelot 
1220e5887a2aSVivien Didelot 	/* Frames from user ports can egress any local DSA links and CPU ports,
1221e5887a2aSVivien Didelot 	 * as well as any local member of their bridge group.
1222e5887a2aSVivien Didelot 	 */
1223e5887a2aSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
1224e5887a2aSVivien Didelot 		if (dsa_is_cpu_port(chip->ds, i) ||
1225e5887a2aSVivien Didelot 		    dsa_is_dsa_port(chip->ds, i) ||
1226c8652c83SVivien Didelot 		    (br && dsa_to_port(chip->ds, i)->bridge_dev == br))
1227e5887a2aSVivien Didelot 			pvlan |= BIT(i);
1228e5887a2aSVivien Didelot 
1229e5887a2aSVivien Didelot 	return pvlan;
1230fad09c73SVivien Didelot }
1231e5887a2aSVivien Didelot 
1232240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port)
1233e5887a2aSVivien Didelot {
1234e5887a2aSVivien Didelot 	u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port);
1235fad09c73SVivien Didelot 
1236fad09c73SVivien Didelot 	/* prevent frames from going back out of the port they came in on */
1237fad09c73SVivien Didelot 	output_ports &= ~BIT(port);
1238fad09c73SVivien Didelot 
12395a7921f4SVivien Didelot 	return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
1240fad09c73SVivien Didelot }
1241fad09c73SVivien Didelot 
1242fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
1243fad09c73SVivien Didelot 					 u8 state)
1244fad09c73SVivien Didelot {
124504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1246fad09c73SVivien Didelot 	int err;
1247fad09c73SVivien Didelot 
1248fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1249f894c29cSVivien Didelot 	err = mv88e6xxx_port_set_state(chip, port, state);
1250fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1251fad09c73SVivien Didelot 
1252fad09c73SVivien Didelot 	if (err)
1253774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to update state\n", port);
1254fad09c73SVivien Didelot }
1255fad09c73SVivien Didelot 
125693e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip)
125793e18d61SVivien Didelot {
125893e18d61SVivien Didelot 	int err;
125993e18d61SVivien Didelot 
126093e18d61SVivien Didelot 	if (chip->info->ops->ieee_pri_map) {
126193e18d61SVivien Didelot 		err = chip->info->ops->ieee_pri_map(chip);
126293e18d61SVivien Didelot 		if (err)
126393e18d61SVivien Didelot 			return err;
126493e18d61SVivien Didelot 	}
126593e18d61SVivien Didelot 
126693e18d61SVivien Didelot 	if (chip->info->ops->ip_pri_map) {
126793e18d61SVivien Didelot 		err = chip->info->ops->ip_pri_map(chip);
126893e18d61SVivien Didelot 		if (err)
126993e18d61SVivien Didelot 			return err;
127093e18d61SVivien Didelot 	}
127193e18d61SVivien Didelot 
127293e18d61SVivien Didelot 	return 0;
127393e18d61SVivien Didelot }
127493e18d61SVivien Didelot 
1275c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
1276c7f047b6SVivien Didelot {
1277c7f047b6SVivien Didelot 	int target, port;
1278c7f047b6SVivien Didelot 	int err;
1279c7f047b6SVivien Didelot 
1280c7f047b6SVivien Didelot 	if (!chip->info->global2_addr)
1281c7f047b6SVivien Didelot 		return 0;
1282c7f047b6SVivien Didelot 
1283c7f047b6SVivien Didelot 	/* Initialize the routing port to the 32 possible target devices */
1284c7f047b6SVivien Didelot 	for (target = 0; target < 32; target++) {
1285c7f047b6SVivien Didelot 		port = 0x1f;
1286c7f047b6SVivien Didelot 		if (target < DSA_MAX_SWITCHES)
1287c7f047b6SVivien Didelot 			if (chip->ds->rtable[target] != DSA_RTABLE_NONE)
1288c7f047b6SVivien Didelot 				port = chip->ds->rtable[target];
1289c7f047b6SVivien Didelot 
1290c7f047b6SVivien Didelot 		err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
1291c7f047b6SVivien Didelot 		if (err)
1292c7f047b6SVivien Didelot 			return err;
1293c7f047b6SVivien Didelot 	}
1294c7f047b6SVivien Didelot 
129502317e68SVivien Didelot 	if (chip->info->ops->set_cascade_port) {
129602317e68SVivien Didelot 		port = MV88E6XXX_CASCADE_PORT_MULTIPLE;
129702317e68SVivien Didelot 		err = chip->info->ops->set_cascade_port(chip, port);
129802317e68SVivien Didelot 		if (err)
129902317e68SVivien Didelot 			return err;
130002317e68SVivien Didelot 	}
130102317e68SVivien Didelot 
130223c98919SVivien Didelot 	err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index);
130323c98919SVivien Didelot 	if (err)
130423c98919SVivien Didelot 		return err;
130523c98919SVivien Didelot 
1306c7f047b6SVivien Didelot 	return 0;
1307c7f047b6SVivien Didelot }
1308c7f047b6SVivien Didelot 
1309b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip)
1310b28f872dSVivien Didelot {
1311b28f872dSVivien Didelot 	/* Clear all trunk masks and mapping */
1312b28f872dSVivien Didelot 	if (chip->info->global2_addr)
1313b28f872dSVivien Didelot 		return mv88e6xxx_g2_trunk_clear(chip);
1314b28f872dSVivien Didelot 
1315b28f872dSVivien Didelot 	return 0;
1316b28f872dSVivien Didelot }
1317b28f872dSVivien Didelot 
13189e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
13199e5baf9bSVivien Didelot {
13209e5baf9bSVivien Didelot 	if (chip->info->ops->rmu_disable)
13219e5baf9bSVivien Didelot 		return chip->info->ops->rmu_disable(chip);
13229e5baf9bSVivien Didelot 
13239e5baf9bSVivien Didelot 	return 0;
13249e5baf9bSVivien Didelot }
13259e5baf9bSVivien Didelot 
13269e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
13279e907d73SVivien Didelot {
13289e907d73SVivien Didelot 	if (chip->info->ops->pot_clear)
13299e907d73SVivien Didelot 		return chip->info->ops->pot_clear(chip);
13309e907d73SVivien Didelot 
13319e907d73SVivien Didelot 	return 0;
13329e907d73SVivien Didelot }
13339e907d73SVivien Didelot 
133451c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip)
133551c901a7SVivien Didelot {
133651c901a7SVivien Didelot 	if (chip->info->ops->mgmt_rsvd2cpu)
133751c901a7SVivien Didelot 		return chip->info->ops->mgmt_rsvd2cpu(chip);
133851c901a7SVivien Didelot 
133951c901a7SVivien Didelot 	return 0;
134051c901a7SVivien Didelot }
134151c901a7SVivien Didelot 
1342a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
1343a2ac29d2SVivien Didelot {
1344c3a7d4adSVivien Didelot 	int err;
1345c3a7d4adSVivien Didelot 
1346daefc943SVivien Didelot 	err = mv88e6xxx_g1_atu_flush(chip, 0, true);
1347daefc943SVivien Didelot 	if (err)
1348daefc943SVivien Didelot 		return err;
1349daefc943SVivien Didelot 
1350c3a7d4adSVivien Didelot 	err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
1351c3a7d4adSVivien Didelot 	if (err)
1352c3a7d4adSVivien Didelot 		return err;
1353c3a7d4adSVivien Didelot 
1354a2ac29d2SVivien Didelot 	return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
1355a2ac29d2SVivien Didelot }
1356a2ac29d2SVivien Didelot 
1357cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip)
1358cd8da8bbSVivien Didelot {
1359cd8da8bbSVivien Didelot 	int port;
1360cd8da8bbSVivien Didelot 	int err;
1361cd8da8bbSVivien Didelot 
1362cd8da8bbSVivien Didelot 	if (!chip->info->ops->irl_init_all)
1363cd8da8bbSVivien Didelot 		return 0;
1364cd8da8bbSVivien Didelot 
1365cd8da8bbSVivien Didelot 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
1366cd8da8bbSVivien Didelot 		/* Disable ingress rate limiting by resetting all per port
1367cd8da8bbSVivien Didelot 		 * ingress rate limit resources to their initial state.
1368cd8da8bbSVivien Didelot 		 */
1369cd8da8bbSVivien Didelot 		err = chip->info->ops->irl_init_all(chip, port);
1370cd8da8bbSVivien Didelot 		if (err)
1371cd8da8bbSVivien Didelot 			return err;
1372cd8da8bbSVivien Didelot 	}
1373cd8da8bbSVivien Didelot 
1374cd8da8bbSVivien Didelot 	return 0;
1375cd8da8bbSVivien Didelot }
1376cd8da8bbSVivien Didelot 
137704a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip)
137804a69a17SVivien Didelot {
137904a69a17SVivien Didelot 	if (chip->info->ops->set_switch_mac) {
138004a69a17SVivien Didelot 		u8 addr[ETH_ALEN];
138104a69a17SVivien Didelot 
138204a69a17SVivien Didelot 		eth_random_addr(addr);
138304a69a17SVivien Didelot 
138404a69a17SVivien Didelot 		return chip->info->ops->set_switch_mac(chip, addr);
138504a69a17SVivien Didelot 	}
138604a69a17SVivien Didelot 
138704a69a17SVivien Didelot 	return 0;
138804a69a17SVivien Didelot }
138904a69a17SVivien Didelot 
139017a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
139117a1594eSVivien Didelot {
139217a1594eSVivien Didelot 	u16 pvlan = 0;
139317a1594eSVivien Didelot 
139417a1594eSVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
139517a1594eSVivien Didelot 		return -EOPNOTSUPP;
139617a1594eSVivien Didelot 
139717a1594eSVivien Didelot 	/* Skip the local source device, which uses in-chip port VLAN */
139817a1594eSVivien Didelot 	if (dev != chip->ds->index)
1399aec5ac88SVivien Didelot 		pvlan = mv88e6xxx_port_vlan(chip, dev, port);
140017a1594eSVivien Didelot 
140117a1594eSVivien Didelot 	return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
140217a1594eSVivien Didelot }
140317a1594eSVivien Didelot 
140481228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
140581228996SVivien Didelot {
140617a1594eSVivien Didelot 	int dev, port;
140717a1594eSVivien Didelot 	int err;
140817a1594eSVivien Didelot 
140981228996SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
141081228996SVivien Didelot 		return 0;
141181228996SVivien Didelot 
141281228996SVivien Didelot 	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
141381228996SVivien Didelot 	 * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
141481228996SVivien Didelot 	 */
141517a1594eSVivien Didelot 	err = mv88e6xxx_g2_misc_4_bit_port(chip);
141617a1594eSVivien Didelot 	if (err)
141717a1594eSVivien Didelot 		return err;
141817a1594eSVivien Didelot 
141917a1594eSVivien Didelot 	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) {
142017a1594eSVivien Didelot 		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) {
142117a1594eSVivien Didelot 			err = mv88e6xxx_pvt_map(chip, dev, port);
142217a1594eSVivien Didelot 			if (err)
142317a1594eSVivien Didelot 				return err;
142417a1594eSVivien Didelot 		}
142517a1594eSVivien Didelot 	}
142617a1594eSVivien Didelot 
142717a1594eSVivien Didelot 	return 0;
142881228996SVivien Didelot }
142981228996SVivien Didelot 
1430749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
1431749efcb8SVivien Didelot {
1432749efcb8SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1433749efcb8SVivien Didelot 	int err;
1434749efcb8SVivien Didelot 
1435749efcb8SVivien Didelot 	mutex_lock(&chip->reg_lock);
1436e606ca36SVivien Didelot 	err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
1437749efcb8SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1438749efcb8SVivien Didelot 
1439749efcb8SVivien Didelot 	if (err)
1440774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to flush ATU\n", port);
1441749efcb8SVivien Didelot }
1442749efcb8SVivien Didelot 
1443b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)
1444b486d7c9SVivien Didelot {
1445b486d7c9SVivien Didelot 	if (!chip->info->max_vid)
1446b486d7c9SVivien Didelot 		return 0;
1447b486d7c9SVivien Didelot 
1448b486d7c9SVivien Didelot 	return mv88e6xxx_g1_vtu_flush(chip);
1449b486d7c9SVivien Didelot }
1450b486d7c9SVivien Didelot 
1451f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,
1452f1394b78SVivien Didelot 				 struct mv88e6xxx_vtu_entry *entry)
1453f1394b78SVivien Didelot {
1454f1394b78SVivien Didelot 	if (!chip->info->ops->vtu_getnext)
1455f1394b78SVivien Didelot 		return -EOPNOTSUPP;
1456f1394b78SVivien Didelot 
1457f1394b78SVivien Didelot 	return chip->info->ops->vtu_getnext(chip, entry);
1458f1394b78SVivien Didelot }
1459f1394b78SVivien Didelot 
14600ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
14610ad5daf6SVivien Didelot 				   struct mv88e6xxx_vtu_entry *entry)
14620ad5daf6SVivien Didelot {
14630ad5daf6SVivien Didelot 	if (!chip->info->ops->vtu_loadpurge)
14640ad5daf6SVivien Didelot 		return -EOPNOTSUPP;
14650ad5daf6SVivien Didelot 
14660ad5daf6SVivien Didelot 	return chip->info->ops->vtu_loadpurge(chip, entry);
14670ad5daf6SVivien Didelot }
14680ad5daf6SVivien Didelot 
1469d7f435f9SVivien Didelot static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
1470fad09c73SVivien Didelot {
1471fad09c73SVivien Didelot 	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
14723afb4bdeSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan = {
14733afb4bdeSVivien Didelot 		.vid = chip->info->max_vid,
14743afb4bdeSVivien Didelot 	};
1475fad09c73SVivien Didelot 	int i, err;
1476fad09c73SVivien Didelot 
1477fad09c73SVivien Didelot 	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
1478fad09c73SVivien Didelot 
1479fad09c73SVivien Didelot 	/* Set every FID bit used by the (un)bridged ports */
1480370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1481b4e48c50SVivien Didelot 		err = mv88e6xxx_port_get_fid(chip, i, fid);
1482fad09c73SVivien Didelot 		if (err)
1483fad09c73SVivien Didelot 			return err;
1484fad09c73SVivien Didelot 
1485fad09c73SVivien Didelot 		set_bit(*fid, fid_bitmap);
1486fad09c73SVivien Didelot 	}
1487fad09c73SVivien Didelot 
1488fad09c73SVivien Didelot 	/* Set every FID bit used by the VLAN entries */
1489fad09c73SVivien Didelot 	do {
1490f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1491fad09c73SVivien Didelot 		if (err)
1492fad09c73SVivien Didelot 			return err;
1493fad09c73SVivien Didelot 
1494fad09c73SVivien Didelot 		if (!vlan.valid)
1495fad09c73SVivien Didelot 			break;
1496fad09c73SVivien Didelot 
1497fad09c73SVivien Didelot 		set_bit(vlan.fid, fid_bitmap);
14983cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
1499fad09c73SVivien Didelot 
1500fad09c73SVivien Didelot 	/* The reset value 0x000 is used to indicate that multiple address
1501fad09c73SVivien Didelot 	 * databases are not needed. Return the next positive available.
1502fad09c73SVivien Didelot 	 */
1503fad09c73SVivien Didelot 	*fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1);
1504fad09c73SVivien Didelot 	if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
1505fad09c73SVivien Didelot 		return -ENOSPC;
1506fad09c73SVivien Didelot 
1507fad09c73SVivien Didelot 	/* Clear the database */
1508daefc943SVivien Didelot 	return mv88e6xxx_g1_atu_flush(chip, *fid, true);
1509fad09c73SVivien Didelot }
1510fad09c73SVivien Didelot 
1511567aa59aSVivien Didelot static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
1512567aa59aSVivien Didelot 			     struct mv88e6xxx_vtu_entry *entry, bool new)
1513fad09c73SVivien Didelot {
1514fad09c73SVivien Didelot 	int err;
1515fad09c73SVivien Didelot 
1516fad09c73SVivien Didelot 	if (!vid)
1517fad09c73SVivien Didelot 		return -EINVAL;
1518fad09c73SVivien Didelot 
15193afb4bdeSVivien Didelot 	entry->vid = vid - 1;
15203afb4bdeSVivien Didelot 	entry->valid = false;
1521fad09c73SVivien Didelot 
1522f1394b78SVivien Didelot 	err = mv88e6xxx_vtu_getnext(chip, entry);
1523fad09c73SVivien Didelot 	if (err)
1524fad09c73SVivien Didelot 		return err;
1525fad09c73SVivien Didelot 
1526567aa59aSVivien Didelot 	if (entry->vid == vid && entry->valid)
1527567aa59aSVivien Didelot 		return 0;
1528fad09c73SVivien Didelot 
1529567aa59aSVivien Didelot 	if (new) {
1530567aa59aSVivien Didelot 		int i;
1531567aa59aSVivien Didelot 
1532567aa59aSVivien Didelot 		/* Initialize a fresh VLAN entry */
1533567aa59aSVivien Didelot 		memset(entry, 0, sizeof(*entry));
1534567aa59aSVivien Didelot 		entry->valid = true;
1535567aa59aSVivien Didelot 		entry->vid = vid;
1536567aa59aSVivien Didelot 
1537553a768dSVivien Didelot 		/* Exclude all ports */
1538567aa59aSVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
1539553a768dSVivien Didelot 			entry->member[i] =
15407ec60d6eSVivien Didelot 				MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1541567aa59aSVivien Didelot 
1542567aa59aSVivien Didelot 		return mv88e6xxx_atu_new(chip, &entry->fid);
1543fad09c73SVivien Didelot 	}
1544fad09c73SVivien Didelot 
1545567aa59aSVivien Didelot 	/* switchdev expects -EOPNOTSUPP to honor software VLANs */
1546567aa59aSVivien Didelot 	return -EOPNOTSUPP;
1547fad09c73SVivien Didelot }
1548fad09c73SVivien Didelot 
1549fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
1550fad09c73SVivien Didelot 					u16 vid_begin, u16 vid_end)
1551fad09c73SVivien Didelot {
155204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
15533afb4bdeSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan = {
15543afb4bdeSVivien Didelot 		.vid = vid_begin - 1,
15553afb4bdeSVivien Didelot 	};
1556fad09c73SVivien Didelot 	int i, err;
1557fad09c73SVivien Didelot 
1558db06ae41SAndrew Lunn 	/* DSA and CPU ports have to be members of multiple vlans */
1559db06ae41SAndrew Lunn 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
1560db06ae41SAndrew Lunn 		return 0;
1561db06ae41SAndrew Lunn 
1562fad09c73SVivien Didelot 	if (!vid_begin)
1563fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1564fad09c73SVivien Didelot 
1565fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1566fad09c73SVivien Didelot 
1567fad09c73SVivien Didelot 	do {
1568f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1569fad09c73SVivien Didelot 		if (err)
1570fad09c73SVivien Didelot 			goto unlock;
1571fad09c73SVivien Didelot 
1572fad09c73SVivien Didelot 		if (!vlan.valid)
1573fad09c73SVivien Didelot 			break;
1574fad09c73SVivien Didelot 
1575fad09c73SVivien Didelot 		if (vlan.vid > vid_end)
1576fad09c73SVivien Didelot 			break;
1577fad09c73SVivien Didelot 
1578370b4ffbSVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1579fad09c73SVivien Didelot 			if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
1580fad09c73SVivien Didelot 				continue;
1581fad09c73SVivien Didelot 
1582cd886469SAndrew Lunn 			if (!ds->ports[i].slave)
158366e2809dSAndrew Lunn 				continue;
158466e2809dSAndrew Lunn 
1585bd00e053SVivien Didelot 			if (vlan.member[i] ==
15867ec60d6eSVivien Didelot 			    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1587fad09c73SVivien Didelot 				continue;
1588fad09c73SVivien Didelot 
1589c8652c83SVivien Didelot 			if (dsa_to_port(ds, i)->bridge_dev ==
1590fae8a25eSVivien Didelot 			    ds->ports[port].bridge_dev)
1591fad09c73SVivien Didelot 				break; /* same bridge, check next VLAN */
1592fad09c73SVivien Didelot 
1593c8652c83SVivien Didelot 			if (!dsa_to_port(ds, i)->bridge_dev)
159466e2809dSAndrew Lunn 				continue;
159566e2809dSAndrew Lunn 
1596743fcc28SAndrew Lunn 			dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
1597743fcc28SAndrew Lunn 				port, vlan.vid, i,
1598c8652c83SVivien Didelot 				netdev_name(dsa_to_port(ds, i)->bridge_dev));
1599fad09c73SVivien Didelot 			err = -EOPNOTSUPP;
1600fad09c73SVivien Didelot 			goto unlock;
1601fad09c73SVivien Didelot 		}
1602fad09c73SVivien Didelot 	} while (vlan.vid < vid_end);
1603fad09c73SVivien Didelot 
1604fad09c73SVivien Didelot unlock:
1605fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1606fad09c73SVivien Didelot 
1607fad09c73SVivien Didelot 	return err;
1608fad09c73SVivien Didelot }
1609fad09c73SVivien Didelot 
1610fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
1611fad09c73SVivien Didelot 					 bool vlan_filtering)
1612fad09c73SVivien Didelot {
161304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
161481c6edb2SVivien Didelot 	u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
161581c6edb2SVivien Didelot 		MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
16160e7b9925SAndrew Lunn 	int err;
1617fad09c73SVivien Didelot 
16183cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1619fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1620fad09c73SVivien Didelot 
1621fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1622385a0995SVivien Didelot 	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
1623fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1624fad09c73SVivien Didelot 
16250e7b9925SAndrew Lunn 	return err;
1626fad09c73SVivien Didelot }
1627fad09c73SVivien Didelot 
1628fad09c73SVivien Didelot static int
1629fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
163080e02360SVivien Didelot 			    const struct switchdev_obj_port_vlan *vlan)
1631fad09c73SVivien Didelot {
163204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1633fad09c73SVivien Didelot 	int err;
1634fad09c73SVivien Didelot 
16353cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1636fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1637fad09c73SVivien Didelot 
1638fad09c73SVivien Didelot 	/* If the requested port doesn't belong to the same bridge as the VLAN
1639fad09c73SVivien Didelot 	 * members, do not support it (yet) and fallback to software VLAN.
1640fad09c73SVivien Didelot 	 */
1641fad09c73SVivien Didelot 	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
1642fad09c73SVivien Didelot 					   vlan->vid_end);
1643fad09c73SVivien Didelot 	if (err)
1644fad09c73SVivien Didelot 		return err;
1645fad09c73SVivien Didelot 
1646fad09c73SVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
1647fad09c73SVivien Didelot 	 * so skip the prepare phase.
1648fad09c73SVivien Didelot 	 */
1649fad09c73SVivien Didelot 	return 0;
1650fad09c73SVivien Didelot }
1651fad09c73SVivien Didelot 
1652a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
1653a4c93ae1SAndrew Lunn 					const unsigned char *addr, u16 vid,
1654a4c93ae1SAndrew Lunn 					u8 state)
1655a4c93ae1SAndrew Lunn {
1656a4c93ae1SAndrew Lunn 	struct mv88e6xxx_vtu_entry vlan;
1657a4c93ae1SAndrew Lunn 	struct mv88e6xxx_atu_entry entry;
1658a4c93ae1SAndrew Lunn 	int err;
1659a4c93ae1SAndrew Lunn 
1660a4c93ae1SAndrew Lunn 	/* Null VLAN ID corresponds to the port private database */
1661a4c93ae1SAndrew Lunn 	if (vid == 0)
1662a4c93ae1SAndrew Lunn 		err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
1663a4c93ae1SAndrew Lunn 	else
1664a4c93ae1SAndrew Lunn 		err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
1665a4c93ae1SAndrew Lunn 	if (err)
1666a4c93ae1SAndrew Lunn 		return err;
1667a4c93ae1SAndrew Lunn 
1668a4c93ae1SAndrew Lunn 	entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1669a4c93ae1SAndrew Lunn 	ether_addr_copy(entry.mac, addr);
1670a4c93ae1SAndrew Lunn 	eth_addr_dec(entry.mac);
1671a4c93ae1SAndrew Lunn 
1672a4c93ae1SAndrew Lunn 	err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry);
1673a4c93ae1SAndrew Lunn 	if (err)
1674a4c93ae1SAndrew Lunn 		return err;
1675a4c93ae1SAndrew Lunn 
1676a4c93ae1SAndrew Lunn 	/* Initialize a fresh ATU entry if it isn't found */
1677a4c93ae1SAndrew Lunn 	if (entry.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED ||
1678a4c93ae1SAndrew Lunn 	    !ether_addr_equal(entry.mac, addr)) {
1679a4c93ae1SAndrew Lunn 		memset(&entry, 0, sizeof(entry));
1680a4c93ae1SAndrew Lunn 		ether_addr_copy(entry.mac, addr);
1681a4c93ae1SAndrew Lunn 	}
1682a4c93ae1SAndrew Lunn 
1683a4c93ae1SAndrew Lunn 	/* Purge the ATU entry only if no port is using it anymore */
1684a4c93ae1SAndrew Lunn 	if (state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
1685a4c93ae1SAndrew Lunn 		entry.portvec &= ~BIT(port);
1686a4c93ae1SAndrew Lunn 		if (!entry.portvec)
1687a4c93ae1SAndrew Lunn 			entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1688a4c93ae1SAndrew Lunn 	} else {
1689a4c93ae1SAndrew Lunn 		entry.portvec |= BIT(port);
1690a4c93ae1SAndrew Lunn 		entry.state = state;
1691a4c93ae1SAndrew Lunn 	}
1692a4c93ae1SAndrew Lunn 
1693a4c93ae1SAndrew Lunn 	return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry);
1694a4c93ae1SAndrew Lunn }
1695a4c93ae1SAndrew Lunn 
169687fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
169787fa886eSAndrew Lunn 					u16 vid)
169887fa886eSAndrew Lunn {
169987fa886eSAndrew Lunn 	const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
170087fa886eSAndrew Lunn 	u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
170187fa886eSAndrew Lunn 
170287fa886eSAndrew Lunn 	return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
170387fa886eSAndrew Lunn }
170487fa886eSAndrew Lunn 
170587fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
170687fa886eSAndrew Lunn {
170787fa886eSAndrew Lunn 	int port;
170887fa886eSAndrew Lunn 	int err;
170987fa886eSAndrew Lunn 
171087fa886eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
171187fa886eSAndrew Lunn 		err = mv88e6xxx_port_add_broadcast(chip, port, vid);
171287fa886eSAndrew Lunn 		if (err)
171387fa886eSAndrew Lunn 			return err;
171487fa886eSAndrew Lunn 	}
171587fa886eSAndrew Lunn 
171687fa886eSAndrew Lunn 	return 0;
171787fa886eSAndrew Lunn }
171887fa886eSAndrew Lunn 
1719fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
1720c91498e1SVivien Didelot 				    u16 vid, u8 member)
1721fad09c73SVivien Didelot {
1722b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1723fad09c73SVivien Didelot 	int err;
1724fad09c73SVivien Didelot 
1725567aa59aSVivien Didelot 	err = mv88e6xxx_vtu_get(chip, vid, &vlan, true);
1726fad09c73SVivien Didelot 	if (err)
1727fad09c73SVivien Didelot 		return err;
1728fad09c73SVivien Didelot 
1729c91498e1SVivien Didelot 	vlan.member[port] = member;
1730fad09c73SVivien Didelot 
173187fa886eSAndrew Lunn 	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
173287fa886eSAndrew Lunn 	if (err)
173387fa886eSAndrew Lunn 		return err;
173487fa886eSAndrew Lunn 
173587fa886eSAndrew Lunn 	return mv88e6xxx_broadcast_setup(chip, vid);
1736fad09c73SVivien Didelot }
1737fad09c73SVivien Didelot 
1738fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
173980e02360SVivien Didelot 				    const struct switchdev_obj_port_vlan *vlan)
1740fad09c73SVivien Didelot {
174104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1742fad09c73SVivien Didelot 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1743fad09c73SVivien Didelot 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1744c91498e1SVivien Didelot 	u8 member;
1745fad09c73SVivien Didelot 	u16 vid;
1746fad09c73SVivien Didelot 
17473cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1748fad09c73SVivien Didelot 		return;
1749fad09c73SVivien Didelot 
1750c91498e1SVivien Didelot 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
17517ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED;
1752c91498e1SVivien Didelot 	else if (untagged)
17537ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED;
1754c91498e1SVivien Didelot 	else
17557ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
1756c91498e1SVivien Didelot 
1757fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1758fad09c73SVivien Didelot 
1759fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
1760c91498e1SVivien Didelot 		if (_mv88e6xxx_port_vlan_add(chip, port, vid, member))
1761774439e5SVivien Didelot 			dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
1762fad09c73SVivien Didelot 				vid, untagged ? 'u' : 't');
1763fad09c73SVivien Didelot 
176477064f37SVivien Didelot 	if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end))
1765774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to set PVID %d\n", port,
1766fad09c73SVivien Didelot 			vlan->vid_end);
1767fad09c73SVivien Didelot 
1768fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1769fad09c73SVivien Didelot }
1770fad09c73SVivien Didelot 
1771fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
1772fad09c73SVivien Didelot 				    int port, u16 vid)
1773fad09c73SVivien Didelot {
1774b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1775fad09c73SVivien Didelot 	int i, err;
1776fad09c73SVivien Didelot 
1777567aa59aSVivien Didelot 	err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
1778fad09c73SVivien Didelot 	if (err)
1779fad09c73SVivien Didelot 		return err;
1780fad09c73SVivien Didelot 
1781fad09c73SVivien Didelot 	/* Tell switchdev if this VLAN is handled in software */
17827ec60d6eSVivien Didelot 	if (vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1783fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1784fad09c73SVivien Didelot 
17857ec60d6eSVivien Didelot 	vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1786fad09c73SVivien Didelot 
1787fad09c73SVivien Didelot 	/* keep the VLAN unless all ports are excluded */
1788fad09c73SVivien Didelot 	vlan.valid = false;
1789370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
17907ec60d6eSVivien Didelot 		if (vlan.member[i] !=
17917ec60d6eSVivien Didelot 		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
1792fad09c73SVivien Didelot 			vlan.valid = true;
1793fad09c73SVivien Didelot 			break;
1794fad09c73SVivien Didelot 		}
1795fad09c73SVivien Didelot 	}
1796fad09c73SVivien Didelot 
17970ad5daf6SVivien Didelot 	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
1798fad09c73SVivien Didelot 	if (err)
1799fad09c73SVivien Didelot 		return err;
1800fad09c73SVivien Didelot 
1801e606ca36SVivien Didelot 	return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
1802fad09c73SVivien Didelot }
1803fad09c73SVivien Didelot 
1804fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
1805fad09c73SVivien Didelot 				   const struct switchdev_obj_port_vlan *vlan)
1806fad09c73SVivien Didelot {
180704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1808fad09c73SVivien Didelot 	u16 pvid, vid;
1809fad09c73SVivien Didelot 	int err = 0;
1810fad09c73SVivien Didelot 
18113cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1812fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1813fad09c73SVivien Didelot 
1814fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1815fad09c73SVivien Didelot 
181677064f37SVivien Didelot 	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
1817fad09c73SVivien Didelot 	if (err)
1818fad09c73SVivien Didelot 		goto unlock;
1819fad09c73SVivien Didelot 
1820fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1821fad09c73SVivien Didelot 		err = _mv88e6xxx_port_vlan_del(chip, port, vid);
1822fad09c73SVivien Didelot 		if (err)
1823fad09c73SVivien Didelot 			goto unlock;
1824fad09c73SVivien Didelot 
1825fad09c73SVivien Didelot 		if (vid == pvid) {
182677064f37SVivien Didelot 			err = mv88e6xxx_port_set_pvid(chip, port, 0);
1827fad09c73SVivien Didelot 			if (err)
1828fad09c73SVivien Didelot 				goto unlock;
1829fad09c73SVivien Didelot 		}
1830fad09c73SVivien Didelot 	}
1831fad09c73SVivien Didelot 
1832fad09c73SVivien Didelot unlock:
1833fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1834fad09c73SVivien Didelot 
1835fad09c73SVivien Didelot 	return err;
1836fad09c73SVivien Didelot }
1837fad09c73SVivien Didelot 
18381b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
18396c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
1840fad09c73SVivien Didelot {
184104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
18421b6dd556SArkadi Sharshevsky 	int err;
1843fad09c73SVivien Didelot 
1844fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
18451b6dd556SArkadi Sharshevsky 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
18461b6dd556SArkadi Sharshevsky 					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
1847fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
18481b6dd556SArkadi Sharshevsky 
18491b6dd556SArkadi Sharshevsky 	return err;
1850fad09c73SVivien Didelot }
1851fad09c73SVivien Didelot 
1852fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
18536c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
1854fad09c73SVivien Didelot {
185504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
185683dabd1fSVivien Didelot 	int err;
1857fad09c73SVivien Didelot 
1858fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
18596c2c1dcbSArkadi Sharshevsky 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
186027c0e600SVivien Didelot 					   MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
1861fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1862fad09c73SVivien Didelot 
186383dabd1fSVivien Didelot 	return err;
1864fad09c73SVivien Didelot }
1865fad09c73SVivien Didelot 
186683dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
1867fad09c73SVivien Didelot 				      u16 fid, u16 vid, int port,
18682bedde1aSArkadi Sharshevsky 				      dsa_fdb_dump_cb_t *cb, void *data)
1869fad09c73SVivien Didelot {
1870dabc1a96SVivien Didelot 	struct mv88e6xxx_atu_entry addr;
18712bedde1aSArkadi Sharshevsky 	bool is_static;
1872fad09c73SVivien Didelot 	int err;
1873fad09c73SVivien Didelot 
187427c0e600SVivien Didelot 	addr.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1875dabc1a96SVivien Didelot 	eth_broadcast_addr(addr.mac);
1876fad09c73SVivien Didelot 
1877fad09c73SVivien Didelot 	do {
1878a61e5406SAndrew Lunn 		mutex_lock(&chip->reg_lock);
1879dabc1a96SVivien Didelot 		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
1880a61e5406SAndrew Lunn 		mutex_unlock(&chip->reg_lock);
1881fad09c73SVivien Didelot 		if (err)
188283dabd1fSVivien Didelot 			return err;
1883fad09c73SVivien Didelot 
188427c0e600SVivien Didelot 		if (addr.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED)
1885fad09c73SVivien Didelot 			break;
1886fad09c73SVivien Didelot 
188701bd96c8SVivien Didelot 		if (addr.trunk || (addr.portvec & BIT(port)) == 0)
188883dabd1fSVivien Didelot 			continue;
1889fad09c73SVivien Didelot 
189083dabd1fSVivien Didelot 		if (!is_unicast_ether_addr(addr.mac))
189183dabd1fSVivien Didelot 			continue;
189283dabd1fSVivien Didelot 
18932bedde1aSArkadi Sharshevsky 		is_static = (addr.state ==
18942bedde1aSArkadi Sharshevsky 			     MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
18952bedde1aSArkadi Sharshevsky 		err = cb(addr.mac, vid, is_static, data);
189683dabd1fSVivien Didelot 		if (err)
189783dabd1fSVivien Didelot 			return err;
1898fad09c73SVivien Didelot 	} while (!is_broadcast_ether_addr(addr.mac));
1899fad09c73SVivien Didelot 
1900fad09c73SVivien Didelot 	return err;
1901fad09c73SVivien Didelot }
1902fad09c73SVivien Didelot 
190383dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
19042bedde1aSArkadi Sharshevsky 				  dsa_fdb_dump_cb_t *cb, void *data)
190583dabd1fSVivien Didelot {
1906b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan = {
19073cf3c846SVivien Didelot 		.vid = chip->info->max_vid,
190883dabd1fSVivien Didelot 	};
190983dabd1fSVivien Didelot 	u16 fid;
191083dabd1fSVivien Didelot 	int err;
191183dabd1fSVivien Didelot 
191283dabd1fSVivien Didelot 	/* Dump port's default Filtering Information Database (VLAN ID 0) */
1913a61e5406SAndrew Lunn 	mutex_lock(&chip->reg_lock);
1914b4e48c50SVivien Didelot 	err = mv88e6xxx_port_get_fid(chip, port, &fid);
1915a61e5406SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
1916a61e5406SAndrew Lunn 
191783dabd1fSVivien Didelot 	if (err)
191883dabd1fSVivien Didelot 		return err;
191983dabd1fSVivien Didelot 
19202bedde1aSArkadi Sharshevsky 	err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data);
192183dabd1fSVivien Didelot 	if (err)
192283dabd1fSVivien Didelot 		return err;
192383dabd1fSVivien Didelot 
192483dabd1fSVivien Didelot 	/* Dump VLANs' Filtering Information Databases */
192583dabd1fSVivien Didelot 	do {
1926a61e5406SAndrew Lunn 		mutex_lock(&chip->reg_lock);
1927f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1928a61e5406SAndrew Lunn 		mutex_unlock(&chip->reg_lock);
192983dabd1fSVivien Didelot 		if (err)
193083dabd1fSVivien Didelot 			return err;
193183dabd1fSVivien Didelot 
193283dabd1fSVivien Didelot 		if (!vlan.valid)
193383dabd1fSVivien Didelot 			break;
193483dabd1fSVivien Didelot 
193583dabd1fSVivien Didelot 		err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port,
19362bedde1aSArkadi Sharshevsky 						 cb, data);
193783dabd1fSVivien Didelot 		if (err)
193883dabd1fSVivien Didelot 			return err;
19393cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
194083dabd1fSVivien Didelot 
194183dabd1fSVivien Didelot 	return err;
194283dabd1fSVivien Didelot }
194383dabd1fSVivien Didelot 
1944fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
19452bedde1aSArkadi Sharshevsky 				   dsa_fdb_dump_cb_t *cb, void *data)
1946fad09c73SVivien Didelot {
194704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1948fad09c73SVivien Didelot 
1949a61e5406SAndrew Lunn 	return mv88e6xxx_port_db_dump(chip, port, cb, data);
1950fad09c73SVivien Didelot }
1951fad09c73SVivien Didelot 
1952240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
1953240ea3efSVivien Didelot 				struct net_device *br)
1954240ea3efSVivien Didelot {
1955e96a6e02SVivien Didelot 	struct dsa_switch *ds;
1956240ea3efSVivien Didelot 	int port;
1957e96a6e02SVivien Didelot 	int dev;
1958240ea3efSVivien Didelot 	int err;
1959240ea3efSVivien Didelot 
1960240ea3efSVivien Didelot 	/* Remap the Port VLAN of each local bridge group member */
1961240ea3efSVivien Didelot 	for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) {
1962240ea3efSVivien Didelot 		if (chip->ds->ports[port].bridge_dev == br) {
1963240ea3efSVivien Didelot 			err = mv88e6xxx_port_vlan_map(chip, port);
1964240ea3efSVivien Didelot 			if (err)
1965240ea3efSVivien Didelot 				return err;
1966240ea3efSVivien Didelot 		}
1967240ea3efSVivien Didelot 	}
1968240ea3efSVivien Didelot 
1969e96a6e02SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
1970e96a6e02SVivien Didelot 		return 0;
1971e96a6e02SVivien Didelot 
1972e96a6e02SVivien Didelot 	/* Remap the Port VLAN of each cross-chip bridge group member */
1973e96a6e02SVivien Didelot 	for (dev = 0; dev < DSA_MAX_SWITCHES; ++dev) {
1974e96a6e02SVivien Didelot 		ds = chip->ds->dst->ds[dev];
1975e96a6e02SVivien Didelot 		if (!ds)
1976e96a6e02SVivien Didelot 			break;
1977e96a6e02SVivien Didelot 
1978e96a6e02SVivien Didelot 		for (port = 0; port < ds->num_ports; ++port) {
1979e96a6e02SVivien Didelot 			if (ds->ports[port].bridge_dev == br) {
1980e96a6e02SVivien Didelot 				err = mv88e6xxx_pvt_map(chip, dev, port);
1981e96a6e02SVivien Didelot 				if (err)
1982e96a6e02SVivien Didelot 					return err;
1983e96a6e02SVivien Didelot 			}
1984e96a6e02SVivien Didelot 		}
1985e96a6e02SVivien Didelot 	}
1986e96a6e02SVivien Didelot 
1987240ea3efSVivien Didelot 	return 0;
1988240ea3efSVivien Didelot }
1989240ea3efSVivien Didelot 
1990fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
1991fae8a25eSVivien Didelot 				      struct net_device *br)
1992fad09c73SVivien Didelot {
199304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1994240ea3efSVivien Didelot 	int err;
1995fad09c73SVivien Didelot 
1996fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1997240ea3efSVivien Didelot 	err = mv88e6xxx_bridge_map(chip, br);
1998fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1999fad09c73SVivien Didelot 
2000fad09c73SVivien Didelot 	return err;
2001fad09c73SVivien Didelot }
2002fad09c73SVivien Didelot 
2003f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
2004f123f2fbSVivien Didelot 					struct net_device *br)
2005fad09c73SVivien Didelot {
200604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2007fad09c73SVivien Didelot 
2008fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
2009240ea3efSVivien Didelot 	if (mv88e6xxx_bridge_map(chip, br) ||
2010240ea3efSVivien Didelot 	    mv88e6xxx_port_vlan_map(chip, port))
2011240ea3efSVivien Didelot 		dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
2012fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2013fad09c73SVivien Didelot }
2014fad09c73SVivien Didelot 
2015aec5ac88SVivien Didelot static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev,
2016aec5ac88SVivien Didelot 					   int port, struct net_device *br)
2017aec5ac88SVivien Didelot {
2018aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2019aec5ac88SVivien Didelot 	int err;
2020aec5ac88SVivien Didelot 
2021aec5ac88SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
2022aec5ac88SVivien Didelot 		return 0;
2023aec5ac88SVivien Didelot 
2024aec5ac88SVivien Didelot 	mutex_lock(&chip->reg_lock);
2025aec5ac88SVivien Didelot 	err = mv88e6xxx_pvt_map(chip, dev, port);
2026aec5ac88SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2027aec5ac88SVivien Didelot 
2028aec5ac88SVivien Didelot 	return err;
2029aec5ac88SVivien Didelot }
2030aec5ac88SVivien Didelot 
2031aec5ac88SVivien Didelot static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev,
2032aec5ac88SVivien Didelot 					     int port, struct net_device *br)
2033aec5ac88SVivien Didelot {
2034aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2035aec5ac88SVivien Didelot 
2036aec5ac88SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
2037aec5ac88SVivien Didelot 		return;
2038aec5ac88SVivien Didelot 
2039aec5ac88SVivien Didelot 	mutex_lock(&chip->reg_lock);
2040aec5ac88SVivien Didelot 	if (mv88e6xxx_pvt_map(chip, dev, port))
2041aec5ac88SVivien Didelot 		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
2042aec5ac88SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2043aec5ac88SVivien Didelot }
2044aec5ac88SVivien Didelot 
204517e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
204617e708baSVivien Didelot {
204717e708baSVivien Didelot 	if (chip->info->ops->reset)
204817e708baSVivien Didelot 		return chip->info->ops->reset(chip);
204917e708baSVivien Didelot 
205017e708baSVivien Didelot 	return 0;
205117e708baSVivien Didelot }
205217e708baSVivien Didelot 
2053309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
2054309eca6dSVivien Didelot {
2055309eca6dSVivien Didelot 	struct gpio_desc *gpiod = chip->reset;
2056309eca6dSVivien Didelot 
2057309eca6dSVivien Didelot 	/* If there is a GPIO connected to the reset pin, toggle it */
2058309eca6dSVivien Didelot 	if (gpiod) {
2059309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 1);
2060309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2061309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 0);
2062309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2063309eca6dSVivien Didelot 	}
2064309eca6dSVivien Didelot }
2065309eca6dSVivien Didelot 
20664ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
20674ac4b5a6SVivien Didelot {
20684ac4b5a6SVivien Didelot 	int i, err;
20694ac4b5a6SVivien Didelot 
20704ac4b5a6SVivien Didelot 	/* Set all ports to the Disabled state */
20714ac4b5a6SVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2072f894c29cSVivien Didelot 		err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED);
20734ac4b5a6SVivien Didelot 		if (err)
20744ac4b5a6SVivien Didelot 			return err;
20754ac4b5a6SVivien Didelot 	}
20764ac4b5a6SVivien Didelot 
20774ac4b5a6SVivien Didelot 	/* Wait for transmit queues to drain,
20784ac4b5a6SVivien Didelot 	 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
20794ac4b5a6SVivien Didelot 	 */
20804ac4b5a6SVivien Didelot 	usleep_range(2000, 4000);
20814ac4b5a6SVivien Didelot 
20824ac4b5a6SVivien Didelot 	return 0;
20834ac4b5a6SVivien Didelot }
20844ac4b5a6SVivien Didelot 
2085fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
2086fad09c73SVivien Didelot {
2087a935c052SVivien Didelot 	int err;
2088fad09c73SVivien Didelot 
20894ac4b5a6SVivien Didelot 	err = mv88e6xxx_disable_ports(chip);
20900e7b9925SAndrew Lunn 	if (err)
20910e7b9925SAndrew Lunn 		return err;
2092fad09c73SVivien Didelot 
2093309eca6dSVivien Didelot 	mv88e6xxx_hardware_reset(chip);
2094fad09c73SVivien Didelot 
209517e708baSVivien Didelot 	return mv88e6xxx_software_reset(chip);
2096fad09c73SVivien Didelot }
2097fad09c73SVivien Didelot 
20984314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
209931bef4e9SVivien Didelot 				   enum mv88e6xxx_frame_mode frame,
210031bef4e9SVivien Didelot 				   enum mv88e6xxx_egress_mode egress, u16 etype)
210156995cbcSAndrew Lunn {
210256995cbcSAndrew Lunn 	int err;
210356995cbcSAndrew Lunn 
21044314557cSVivien Didelot 	if (!chip->info->ops->port_set_frame_mode)
21054314557cSVivien Didelot 		return -EOPNOTSUPP;
21064314557cSVivien Didelot 
21074314557cSVivien Didelot 	err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
210856995cbcSAndrew Lunn 	if (err)
210956995cbcSAndrew Lunn 		return err;
211056995cbcSAndrew Lunn 
21114314557cSVivien Didelot 	err = chip->info->ops->port_set_frame_mode(chip, port, frame);
21124314557cSVivien Didelot 	if (err)
21134314557cSVivien Didelot 		return err;
21144314557cSVivien Didelot 
21154314557cSVivien Didelot 	if (chip->info->ops->port_set_ether_type)
21164314557cSVivien Didelot 		return chip->info->ops->port_set_ether_type(chip, port, etype);
21174314557cSVivien Didelot 
21184314557cSVivien Didelot 	return 0;
21194314557cSVivien Didelot }
21204314557cSVivien Didelot 
21214314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
21224314557cSVivien Didelot {
21234314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
212431bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2125b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
21264314557cSVivien Didelot }
21274314557cSVivien Didelot 
21284314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
21294314557cSVivien Didelot {
21304314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
213131bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2132b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
21334314557cSVivien Didelot }
21344314557cSVivien Didelot 
21354314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
21364314557cSVivien Didelot {
21374314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port,
21384314557cSVivien Didelot 				       MV88E6XXX_FRAME_MODE_ETHERTYPE,
213931bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_ETHERTYPE,
214031bef4e9SVivien Didelot 				       ETH_P_EDSA);
21414314557cSVivien Didelot }
21424314557cSVivien Didelot 
21434314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port)
21444314557cSVivien Didelot {
21454314557cSVivien Didelot 	if (dsa_is_dsa_port(chip->ds, port))
21464314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
21474314557cSVivien Didelot 
21482b3e9891SVivien Didelot 	if (dsa_is_user_port(chip->ds, port))
21494314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_normal(chip, port);
21504314557cSVivien Didelot 
21514314557cSVivien Didelot 	/* Setup CPU port mode depending on its supported tag format */
21524314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA)
21534314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
21544314557cSVivien Didelot 
21554314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA)
21564314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_edsa(chip, port);
21574314557cSVivien Didelot 
21584314557cSVivien Didelot 	return -EINVAL;
21594314557cSVivien Didelot }
21604314557cSVivien Didelot 
2161ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
2162ea698f4fSVivien Didelot {
2163ea698f4fSVivien Didelot 	bool message = dsa_is_dsa_port(chip->ds, port);
2164ea698f4fSVivien Didelot 
2165ea698f4fSVivien Didelot 	return mv88e6xxx_port_set_message_port(chip, port, message);
2166ea698f4fSVivien Didelot }
2167ea698f4fSVivien Didelot 
2168601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
2169601aeed3SVivien Didelot {
21703ee50cbfSVivien Didelot 	struct dsa_switch *ds = chip->ds;
21713ee50cbfSVivien Didelot 	bool flood;
2172601aeed3SVivien Didelot 
2173601aeed3SVivien Didelot 	/* Upstream ports flood frames with unknown unicast or multicast DA */
21743ee50cbfSVivien Didelot 	flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port);
2175601aeed3SVivien Didelot 	if (chip->info->ops->port_set_egress_floods)
2176601aeed3SVivien Didelot 		return chip->info->ops->port_set_egress_floods(chip, port,
2177601aeed3SVivien Didelot 							       flood, flood);
2178601aeed3SVivien Didelot 
2179601aeed3SVivien Didelot 	return 0;
2180601aeed3SVivien Didelot }
2181601aeed3SVivien Didelot 
21826d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
21836d91782fSAndrew Lunn 				  bool on)
21846d91782fSAndrew Lunn {
2185523a8904SVivien Didelot 	if (chip->info->ops->serdes_power)
2186523a8904SVivien Didelot 		return chip->info->ops->serdes_power(chip, port, on);
21876d91782fSAndrew Lunn 
2188523a8904SVivien Didelot 	return 0;
21896d91782fSAndrew Lunn }
21906d91782fSAndrew Lunn 
2191fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
2192fa371c80SVivien Didelot {
2193fa371c80SVivien Didelot 	struct dsa_switch *ds = chip->ds;
2194fa371c80SVivien Didelot 	int upstream_port;
2195fa371c80SVivien Didelot 	int err;
2196fa371c80SVivien Didelot 
219707073c79SVivien Didelot 	upstream_port = dsa_upstream_port(ds, port);
2198fa371c80SVivien Didelot 	if (chip->info->ops->port_set_upstream_port) {
2199fa371c80SVivien Didelot 		err = chip->info->ops->port_set_upstream_port(chip, port,
2200fa371c80SVivien Didelot 							      upstream_port);
2201fa371c80SVivien Didelot 		if (err)
2202fa371c80SVivien Didelot 			return err;
2203fa371c80SVivien Didelot 	}
2204fa371c80SVivien Didelot 
22050ea54ddaSVivien Didelot 	if (port == upstream_port) {
22060ea54ddaSVivien Didelot 		if (chip->info->ops->set_cpu_port) {
22070ea54ddaSVivien Didelot 			err = chip->info->ops->set_cpu_port(chip,
22080ea54ddaSVivien Didelot 							    upstream_port);
22090ea54ddaSVivien Didelot 			if (err)
22100ea54ddaSVivien Didelot 				return err;
22110ea54ddaSVivien Didelot 		}
22120ea54ddaSVivien Didelot 
22130ea54ddaSVivien Didelot 		if (chip->info->ops->set_egress_port) {
22140ea54ddaSVivien Didelot 			err = chip->info->ops->set_egress_port(chip,
22150ea54ddaSVivien Didelot 							       upstream_port);
22160ea54ddaSVivien Didelot 			if (err)
22170ea54ddaSVivien Didelot 				return err;
22180ea54ddaSVivien Didelot 		}
22190ea54ddaSVivien Didelot 	}
22200ea54ddaSVivien Didelot 
2221fa371c80SVivien Didelot 	return 0;
2222fa371c80SVivien Didelot }
2223fa371c80SVivien Didelot 
2224fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
2225fad09c73SVivien Didelot {
2226fad09c73SVivien Didelot 	struct dsa_switch *ds = chip->ds;
22270e7b9925SAndrew Lunn 	int err;
2228fad09c73SVivien Didelot 	u16 reg;
2229fad09c73SVivien Didelot 
22307b898469SAndrew Lunn 	chip->ports[port].chip = chip;
22317b898469SAndrew Lunn 	chip->ports[port].port = port;
22327b898469SAndrew Lunn 
2233d78343d2SVivien Didelot 	/* MAC Forcing register: don't force link, speed, duplex or flow control
2234d78343d2SVivien Didelot 	 * state to any particular values on physical ports, but force the CPU
2235d78343d2SVivien Didelot 	 * port and all DSA ports to their maximum bandwidth and full duplex.
2236fad09c73SVivien Didelot 	 */
2237d78343d2SVivien Didelot 	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
2238d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
2239d78343d2SVivien Didelot 					       SPEED_MAX, DUPLEX_FULL,
224054186b91SAndrew Lunn 					       PAUSE_OFF,
2241d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
2242fad09c73SVivien Didelot 	else
2243d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
2244d78343d2SVivien Didelot 					       SPEED_UNFORCED, DUPLEX_UNFORCED,
224554186b91SAndrew Lunn 					       PAUSE_ON,
2246d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
22470e7b9925SAndrew Lunn 	if (err)
22480e7b9925SAndrew Lunn 		return err;
2249fad09c73SVivien Didelot 
2250fad09c73SVivien Didelot 	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
2251fad09c73SVivien Didelot 	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
2252fad09c73SVivien Didelot 	 * tunneling, determine priority by looking at 802.1p and IP
2253fad09c73SVivien Didelot 	 * priority fields (IP prio has precedence), and set STP state
2254fad09c73SVivien Didelot 	 * to Forwarding.
2255fad09c73SVivien Didelot 	 *
2256fad09c73SVivien Didelot 	 * If this is the CPU link, use DSA or EDSA tagging depending
2257fad09c73SVivien Didelot 	 * on which tagging mode was configured.
2258fad09c73SVivien Didelot 	 *
2259fad09c73SVivien Didelot 	 * If this is a link to another switch, use DSA tagging mode.
2260fad09c73SVivien Didelot 	 *
2261fad09c73SVivien Didelot 	 * If this is the upstream port for this switch, enable
2262fad09c73SVivien Didelot 	 * forwarding of unknown unicasts and multicasts.
2263fad09c73SVivien Didelot 	 */
2264a89b433bSVivien Didelot 	reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP |
2265a89b433bSVivien Didelot 		MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
2266a89b433bSVivien Didelot 		MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
2267a89b433bSVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
22680e7b9925SAndrew Lunn 	if (err)
22690e7b9925SAndrew Lunn 		return err;
227056995cbcSAndrew Lunn 
2271601aeed3SVivien Didelot 	err = mv88e6xxx_setup_port_mode(chip, port);
227256995cbcSAndrew Lunn 	if (err)
227356995cbcSAndrew Lunn 		return err;
2274fad09c73SVivien Didelot 
2275601aeed3SVivien Didelot 	err = mv88e6xxx_setup_egress_floods(chip, port);
22764314557cSVivien Didelot 	if (err)
22774314557cSVivien Didelot 		return err;
22784314557cSVivien Didelot 
227904aca993SAndrew Lunn 	/* Enable the SERDES interface for DSA and CPU ports. Normal
228004aca993SAndrew Lunn 	 * ports SERDES are enabled when the port is enabled, thus
228104aca993SAndrew Lunn 	 * saving a bit of power.
2282fad09c73SVivien Didelot 	 */
228304aca993SAndrew Lunn 	if ((dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) {
22846d91782fSAndrew Lunn 		err = mv88e6xxx_serdes_power(chip, port, true);
22850e7b9925SAndrew Lunn 		if (err)
22860e7b9925SAndrew Lunn 			return err;
228704aca993SAndrew Lunn 	}
2288fad09c73SVivien Didelot 
2289fad09c73SVivien Didelot 	/* Port Control 2: don't force a good FCS, set the maximum frame size to
2290fad09c73SVivien Didelot 	 * 10240 bytes, disable 802.1q tags checking, don't discard tagged or
2291fad09c73SVivien Didelot 	 * untagged frames on this port, do a destination address lookup on all
2292fad09c73SVivien Didelot 	 * received packets as usual, disable ARP mirroring and don't send a
2293fad09c73SVivien Didelot 	 * copy of all transmitted/received frames on this port to the CPU.
2294fad09c73SVivien Didelot 	 */
2295a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_map_da(chip, port);
2296a23b2961SAndrew Lunn 	if (err)
2297a23b2961SAndrew Lunn 		return err;
2298a23b2961SAndrew Lunn 
2299fa371c80SVivien Didelot 	err = mv88e6xxx_setup_upstream_port(chip, port);
23000e7b9925SAndrew Lunn 	if (err)
23010e7b9925SAndrew Lunn 		return err;
2302fad09c73SVivien Didelot 
2303a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_8021q_mode(chip, port,
230481c6edb2SVivien Didelot 				MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED);
2305a23b2961SAndrew Lunn 	if (err)
2306a23b2961SAndrew Lunn 		return err;
2307a23b2961SAndrew Lunn 
2308cd782656SVivien Didelot 	if (chip->info->ops->port_set_jumbo_size) {
2309cd782656SVivien Didelot 		err = chip->info->ops->port_set_jumbo_size(chip, port, 10240);
23105f436666SAndrew Lunn 		if (err)
23115f436666SAndrew Lunn 			return err;
23125f436666SAndrew Lunn 	}
23135f436666SAndrew Lunn 
2314fad09c73SVivien Didelot 	/* Port Association Vector: when learning source addresses
2315fad09c73SVivien Didelot 	 * of packets, add the address to the address database using
2316fad09c73SVivien Didelot 	 * a port bitmap that has only the bit for this port set and
2317fad09c73SVivien Didelot 	 * the other bits clear.
2318fad09c73SVivien Didelot 	 */
2319fad09c73SVivien Didelot 	reg = 1 << port;
2320fad09c73SVivien Didelot 	/* Disable learning for CPU port */
2321fad09c73SVivien Didelot 	if (dsa_is_cpu_port(ds, port))
2322fad09c73SVivien Didelot 		reg = 0;
2323fad09c73SVivien Didelot 
23242a4614e4SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
23252a4614e4SVivien Didelot 				   reg);
23260e7b9925SAndrew Lunn 	if (err)
23270e7b9925SAndrew Lunn 		return err;
2328fad09c73SVivien Didelot 
2329fad09c73SVivien Didelot 	/* Egress rate control 2: disable egress rate control. */
23302cb8cb14SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2,
23312cb8cb14SVivien Didelot 				   0x0000);
23320e7b9925SAndrew Lunn 	if (err)
23330e7b9925SAndrew Lunn 		return err;
2334fad09c73SVivien Didelot 
23350898432cSVivien Didelot 	if (chip->info->ops->port_pause_limit) {
23360898432cSVivien Didelot 		err = chip->info->ops->port_pause_limit(chip, port, 0, 0);
2337b35d322aSAndrew Lunn 		if (err)
2338b35d322aSAndrew Lunn 			return err;
2339b35d322aSAndrew Lunn 	}
2340b35d322aSAndrew Lunn 
2341c8c94891SVivien Didelot 	if (chip->info->ops->port_disable_learn_limit) {
2342c8c94891SVivien Didelot 		err = chip->info->ops->port_disable_learn_limit(chip, port);
2343c8c94891SVivien Didelot 		if (err)
2344c8c94891SVivien Didelot 			return err;
2345c8c94891SVivien Didelot 	}
2346c8c94891SVivien Didelot 
23479dbfb4e1SVivien Didelot 	if (chip->info->ops->port_disable_pri_override) {
23489dbfb4e1SVivien Didelot 		err = chip->info->ops->port_disable_pri_override(chip, port);
23490e7b9925SAndrew Lunn 		if (err)
23500e7b9925SAndrew Lunn 			return err;
2351ef0a7318SAndrew Lunn 	}
23522bbb33beSAndrew Lunn 
2353ef0a7318SAndrew Lunn 	if (chip->info->ops->port_tag_remap) {
2354ef0a7318SAndrew Lunn 		err = chip->info->ops->port_tag_remap(chip, port);
23550e7b9925SAndrew Lunn 		if (err)
23560e7b9925SAndrew Lunn 			return err;
2357fad09c73SVivien Didelot 	}
2358fad09c73SVivien Didelot 
2359ef70b111SAndrew Lunn 	if (chip->info->ops->port_egress_rate_limiting) {
2360ef70b111SAndrew Lunn 		err = chip->info->ops->port_egress_rate_limiting(chip, port);
23610e7b9925SAndrew Lunn 		if (err)
23620e7b9925SAndrew Lunn 			return err;
2363fad09c73SVivien Didelot 	}
2364fad09c73SVivien Didelot 
2365ea698f4fSVivien Didelot 	err = mv88e6xxx_setup_message_port(chip, port);
23660e7b9925SAndrew Lunn 	if (err)
23670e7b9925SAndrew Lunn 		return err;
2368fad09c73SVivien Didelot 
2369fad09c73SVivien Didelot 	/* Port based VLAN map: give each port the same default address
2370fad09c73SVivien Didelot 	 * database, and allow bidirectional communication between the
2371fad09c73SVivien Didelot 	 * CPU and DSA port(s), and the other ports.
2372fad09c73SVivien Didelot 	 */
2373b4e48c50SVivien Didelot 	err = mv88e6xxx_port_set_fid(chip, port, 0);
23740e7b9925SAndrew Lunn 	if (err)
23750e7b9925SAndrew Lunn 		return err;
2376fad09c73SVivien Didelot 
2377240ea3efSVivien Didelot 	err = mv88e6xxx_port_vlan_map(chip, port);
23780e7b9925SAndrew Lunn 	if (err)
23790e7b9925SAndrew Lunn 		return err;
2380fad09c73SVivien Didelot 
2381fad09c73SVivien Didelot 	/* Default VLAN ID and priority: don't set a default VLAN
2382fad09c73SVivien Didelot 	 * ID, and set the default packet priority to zero.
2383fad09c73SVivien Didelot 	 */
2384b7929fb3SVivien Didelot 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0);
2385fad09c73SVivien Didelot }
2386fad09c73SVivien Didelot 
238704aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
238804aca993SAndrew Lunn 				 struct phy_device *phydev)
238904aca993SAndrew Lunn {
239004aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
2391523a8904SVivien Didelot 	int err;
239204aca993SAndrew Lunn 
239304aca993SAndrew Lunn 	mutex_lock(&chip->reg_lock);
2394efd1ba6aSAndrew Lunn 
2395523a8904SVivien Didelot 	err = mv88e6xxx_serdes_power(chip, port, true);
2396efd1ba6aSAndrew Lunn 
2397efd1ba6aSAndrew Lunn 	if (!err && chip->info->ops->serdes_irq_setup)
2398efd1ba6aSAndrew Lunn 		err = chip->info->ops->serdes_irq_setup(chip, port);
2399efd1ba6aSAndrew Lunn 
240004aca993SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
240104aca993SAndrew Lunn 
240204aca993SAndrew Lunn 	return err;
240304aca993SAndrew Lunn }
240404aca993SAndrew Lunn 
240575104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
240604aca993SAndrew Lunn {
240704aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
240804aca993SAndrew Lunn 
240904aca993SAndrew Lunn 	mutex_lock(&chip->reg_lock);
2410efd1ba6aSAndrew Lunn 
2411efd1ba6aSAndrew Lunn 	if (chip->info->ops->serdes_irq_free)
2412efd1ba6aSAndrew Lunn 		chip->info->ops->serdes_irq_free(chip, port);
2413efd1ba6aSAndrew Lunn 
2414523a8904SVivien Didelot 	if (mv88e6xxx_serdes_power(chip, port, false))
2415523a8904SVivien Didelot 		dev_err(chip->dev, "failed to power off SERDES\n");
2416efd1ba6aSAndrew Lunn 
241704aca993SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
241804aca993SAndrew Lunn }
241904aca993SAndrew Lunn 
24202cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
24212cfcd964SVivien Didelot 				     unsigned int ageing_time)
24222cfcd964SVivien Didelot {
242304bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
24242cfcd964SVivien Didelot 	int err;
24252cfcd964SVivien Didelot 
24262cfcd964SVivien Didelot 	mutex_lock(&chip->reg_lock);
2427720c6343SVivien Didelot 	err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
24282cfcd964SVivien Didelot 	mutex_unlock(&chip->reg_lock);
24292cfcd964SVivien Didelot 
24302cfcd964SVivien Didelot 	return err;
24312cfcd964SVivien Didelot }
24322cfcd964SVivien Didelot 
2433447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
2434fad09c73SVivien Didelot {
2435fad09c73SVivien Didelot 	int err;
2436fad09c73SVivien Didelot 
2437de227387SAndrew Lunn 	/* Initialize the statistics unit */
2438447b1bb8SVivien Didelot 	if (chip->info->ops->stats_set_histogram) {
2439447b1bb8SVivien Didelot 		err = chip->info->ops->stats_set_histogram(chip);
2440de227387SAndrew Lunn 		if (err)
2441de227387SAndrew Lunn 			return err;
2442447b1bb8SVivien Didelot 	}
2443de227387SAndrew Lunn 
244440cff8fcSAndrew Lunn 	return mv88e6xxx_g1_stats_clear(chip);
24459729934cSVivien Didelot }
24469729934cSVivien Didelot 
2447ea89098eSAndrew Lunn /* The mv88e6390 has some hidden registers used for debug and
2448ea89098eSAndrew Lunn  * development. The errata also makes use of them.
2449ea89098eSAndrew Lunn  */
2450ea89098eSAndrew Lunn static int mv88e6390_hidden_write(struct mv88e6xxx_chip *chip, int port,
2451ea89098eSAndrew Lunn 				  int reg, u16 val)
2452ea89098eSAndrew Lunn {
2453ea89098eSAndrew Lunn 	u16 ctrl;
2454ea89098eSAndrew Lunn 	int err;
2455ea89098eSAndrew Lunn 
2456ea89098eSAndrew Lunn 	err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_DATA_PORT,
2457ea89098eSAndrew Lunn 				   PORT_RESERVED_1A, val);
2458ea89098eSAndrew Lunn 	if (err)
2459ea89098eSAndrew Lunn 		return err;
2460ea89098eSAndrew Lunn 
2461ea89098eSAndrew Lunn 	ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_WRITE |
2462ea89098eSAndrew Lunn 	       PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT |
2463ea89098eSAndrew Lunn 	       reg;
2464ea89098eSAndrew Lunn 
2465ea89098eSAndrew Lunn 	return mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT,
2466ea89098eSAndrew Lunn 				    PORT_RESERVED_1A, ctrl);
2467ea89098eSAndrew Lunn }
2468ea89098eSAndrew Lunn 
2469ea89098eSAndrew Lunn static int mv88e6390_hidden_wait(struct mv88e6xxx_chip *chip)
2470ea89098eSAndrew Lunn {
2471ea89098eSAndrew Lunn 	return mv88e6xxx_wait(chip, PORT_RESERVED_1A_CTRL_PORT,
2472ea89098eSAndrew Lunn 			      PORT_RESERVED_1A, PORT_RESERVED_1A_BUSY);
2473ea89098eSAndrew Lunn }
2474ea89098eSAndrew Lunn 
2475ea89098eSAndrew Lunn 
2476ea89098eSAndrew Lunn static int mv88e6390_hidden_read(struct mv88e6xxx_chip *chip, int port,
2477ea89098eSAndrew Lunn 				  int reg, u16 *val)
2478ea89098eSAndrew Lunn {
2479ea89098eSAndrew Lunn 	u16 ctrl;
2480ea89098eSAndrew Lunn 	int err;
2481ea89098eSAndrew Lunn 
2482ea89098eSAndrew Lunn 	ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_READ |
2483ea89098eSAndrew Lunn 	       PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT |
2484ea89098eSAndrew Lunn 	       reg;
2485ea89098eSAndrew Lunn 
2486ea89098eSAndrew Lunn 	err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT,
2487ea89098eSAndrew Lunn 				   PORT_RESERVED_1A, ctrl);
2488ea89098eSAndrew Lunn 	if (err)
2489ea89098eSAndrew Lunn 		return err;
2490ea89098eSAndrew Lunn 
2491ea89098eSAndrew Lunn 	err = mv88e6390_hidden_wait(chip);
2492ea89098eSAndrew Lunn 	if (err)
2493ea89098eSAndrew Lunn 		return err;
2494ea89098eSAndrew Lunn 
2495ea89098eSAndrew Lunn 	return 	mv88e6xxx_port_read(chip, PORT_RESERVED_1A_DATA_PORT,
2496ea89098eSAndrew Lunn 				    PORT_RESERVED_1A, val);
2497ea89098eSAndrew Lunn }
2498ea89098eSAndrew Lunn 
2499ea89098eSAndrew Lunn /* Check if the errata has already been applied. */
2500ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
2501ea89098eSAndrew Lunn {
2502ea89098eSAndrew Lunn 	int port;
2503ea89098eSAndrew Lunn 	int err;
2504ea89098eSAndrew Lunn 	u16 val;
2505ea89098eSAndrew Lunn 
2506ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
2507ea89098eSAndrew Lunn 		err = mv88e6390_hidden_read(chip, port, 0, &val);
2508ea89098eSAndrew Lunn 		if (err) {
2509ea89098eSAndrew Lunn 			dev_err(chip->dev,
2510ea89098eSAndrew Lunn 				"Error reading hidden register: %d\n", err);
2511ea89098eSAndrew Lunn 			return false;
2512ea89098eSAndrew Lunn 		}
2513ea89098eSAndrew Lunn 		if (val != 0x01c0)
2514ea89098eSAndrew Lunn 			return false;
2515ea89098eSAndrew Lunn 	}
2516ea89098eSAndrew Lunn 
2517ea89098eSAndrew Lunn 	return true;
2518ea89098eSAndrew Lunn }
2519ea89098eSAndrew Lunn 
2520ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic
2521ea89098eSAndrew Lunn  * values into undocumented hidden registers and then performing a
2522ea89098eSAndrew Lunn  * software reset.
2523ea89098eSAndrew Lunn  */
2524ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
2525ea89098eSAndrew Lunn {
2526ea89098eSAndrew Lunn 	int port;
2527ea89098eSAndrew Lunn 	int err;
2528ea89098eSAndrew Lunn 
2529ea89098eSAndrew Lunn 	if (mv88e6390_setup_errata_applied(chip))
2530ea89098eSAndrew Lunn 		return 0;
2531ea89098eSAndrew Lunn 
2532ea89098eSAndrew Lunn 	/* Set the ports into blocking mode */
2533ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
2534ea89098eSAndrew Lunn 		err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED);
2535ea89098eSAndrew Lunn 		if (err)
2536ea89098eSAndrew Lunn 			return err;
2537ea89098eSAndrew Lunn 	}
2538ea89098eSAndrew Lunn 
2539ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
2540ea89098eSAndrew Lunn 		err = mv88e6390_hidden_write(chip, port, 0, 0x01c0);
2541ea89098eSAndrew Lunn 		if (err)
2542ea89098eSAndrew Lunn 			return err;
2543ea89098eSAndrew Lunn 	}
2544ea89098eSAndrew Lunn 
2545ea89098eSAndrew Lunn 	return mv88e6xxx_software_reset(chip);
2546ea89098eSAndrew Lunn }
2547ea89098eSAndrew Lunn 
2548fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds)
2549fad09c73SVivien Didelot {
255004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
25512d2e1dd2SAndrew Lunn 	u8 cmode;
2552fad09c73SVivien Didelot 	int err;
2553fad09c73SVivien Didelot 	int i;
2554fad09c73SVivien Didelot 
2555fad09c73SVivien Didelot 	chip->ds = ds;
2556a3c53be5SAndrew Lunn 	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
2557fad09c73SVivien Didelot 
2558fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
2559fad09c73SVivien Didelot 
2560ea89098eSAndrew Lunn 	if (chip->info->ops->setup_errata) {
2561ea89098eSAndrew Lunn 		err = chip->info->ops->setup_errata(chip);
2562ea89098eSAndrew Lunn 		if (err)
2563ea89098eSAndrew Lunn 			goto unlock;
2564ea89098eSAndrew Lunn 	}
2565ea89098eSAndrew Lunn 
25662d2e1dd2SAndrew Lunn 	/* Cache the cmode of each port. */
25672d2e1dd2SAndrew Lunn 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
25682d2e1dd2SAndrew Lunn 		if (chip->info->ops->port_get_cmode) {
25692d2e1dd2SAndrew Lunn 			err = chip->info->ops->port_get_cmode(chip, i, &cmode);
25702d2e1dd2SAndrew Lunn 			if (err)
2571e29129fcSDan Carpenter 				goto unlock;
25722d2e1dd2SAndrew Lunn 
25732d2e1dd2SAndrew Lunn 			chip->ports[i].cmode = cmode;
25742d2e1dd2SAndrew Lunn 		}
25752d2e1dd2SAndrew Lunn 	}
25762d2e1dd2SAndrew Lunn 
25779729934cSVivien Didelot 	/* Setup Switch Port Registers */
2578370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
257991dee144SVivien Didelot 		if (dsa_is_unused_port(ds, i))
258091dee144SVivien Didelot 			continue;
258191dee144SVivien Didelot 
25829729934cSVivien Didelot 		err = mv88e6xxx_setup_port(chip, i);
25839729934cSVivien Didelot 		if (err)
25849729934cSVivien Didelot 			goto unlock;
25859729934cSVivien Didelot 	}
25869729934cSVivien Didelot 
2587cd8da8bbSVivien Didelot 	err = mv88e6xxx_irl_setup(chip);
2588cd8da8bbSVivien Didelot 	if (err)
2589cd8da8bbSVivien Didelot 		goto unlock;
2590cd8da8bbSVivien Didelot 
259104a69a17SVivien Didelot 	err = mv88e6xxx_mac_setup(chip);
259204a69a17SVivien Didelot 	if (err)
259304a69a17SVivien Didelot 		goto unlock;
259404a69a17SVivien Didelot 
25951b17aedfSVivien Didelot 	err = mv88e6xxx_phy_setup(chip);
25961b17aedfSVivien Didelot 	if (err)
25971b17aedfSVivien Didelot 		goto unlock;
25981b17aedfSVivien Didelot 
2599b486d7c9SVivien Didelot 	err = mv88e6xxx_vtu_setup(chip);
2600b486d7c9SVivien Didelot 	if (err)
2601b486d7c9SVivien Didelot 		goto unlock;
2602b486d7c9SVivien Didelot 
260381228996SVivien Didelot 	err = mv88e6xxx_pvt_setup(chip);
260481228996SVivien Didelot 	if (err)
260581228996SVivien Didelot 		goto unlock;
260681228996SVivien Didelot 
2607a2ac29d2SVivien Didelot 	err = mv88e6xxx_atu_setup(chip);
2608a2ac29d2SVivien Didelot 	if (err)
2609a2ac29d2SVivien Didelot 		goto unlock;
2610a2ac29d2SVivien Didelot 
261187fa886eSAndrew Lunn 	err = mv88e6xxx_broadcast_setup(chip, 0);
261287fa886eSAndrew Lunn 	if (err)
261387fa886eSAndrew Lunn 		goto unlock;
261487fa886eSAndrew Lunn 
26159e907d73SVivien Didelot 	err = mv88e6xxx_pot_setup(chip);
26169e907d73SVivien Didelot 	if (err)
26179e907d73SVivien Didelot 		goto unlock;
26189e907d73SVivien Didelot 
26199e5baf9bSVivien Didelot 	err = mv88e6xxx_rmu_setup(chip);
26209e5baf9bSVivien Didelot 	if (err)
26219e5baf9bSVivien Didelot 		goto unlock;
26229e5baf9bSVivien Didelot 
262351c901a7SVivien Didelot 	err = mv88e6xxx_rsvd2cpu_setup(chip);
26246e55f698SAndrew Lunn 	if (err)
26256e55f698SAndrew Lunn 		goto unlock;
26266e55f698SAndrew Lunn 
2627b28f872dSVivien Didelot 	err = mv88e6xxx_trunk_setup(chip);
2628b28f872dSVivien Didelot 	if (err)
2629b28f872dSVivien Didelot 		goto unlock;
2630b28f872dSVivien Didelot 
2631c7f047b6SVivien Didelot 	err = mv88e6xxx_devmap_setup(chip);
2632c7f047b6SVivien Didelot 	if (err)
2633c7f047b6SVivien Didelot 		goto unlock;
2634c7f047b6SVivien Didelot 
263593e18d61SVivien Didelot 	err = mv88e6xxx_pri_setup(chip);
263693e18d61SVivien Didelot 	if (err)
263793e18d61SVivien Didelot 		goto unlock;
263893e18d61SVivien Didelot 
2639c6fe0ad2SBrandon Streiff 	/* Setup PTP Hardware Clock and timestamping */
26402fa8d3afSBrandon Streiff 	if (chip->info->ptp_support) {
26412fa8d3afSBrandon Streiff 		err = mv88e6xxx_ptp_setup(chip);
26422fa8d3afSBrandon Streiff 		if (err)
26432fa8d3afSBrandon Streiff 			goto unlock;
2644c6fe0ad2SBrandon Streiff 
2645c6fe0ad2SBrandon Streiff 		err = mv88e6xxx_hwtstamp_setup(chip);
2646c6fe0ad2SBrandon Streiff 		if (err)
2647c6fe0ad2SBrandon Streiff 			goto unlock;
26482fa8d3afSBrandon Streiff 	}
26492fa8d3afSBrandon Streiff 
2650447b1bb8SVivien Didelot 	err = mv88e6xxx_stats_setup(chip);
2651447b1bb8SVivien Didelot 	if (err)
2652447b1bb8SVivien Didelot 		goto unlock;
2653447b1bb8SVivien Didelot 
2654fad09c73SVivien Didelot unlock:
2655fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2656fad09c73SVivien Didelot 
2657fad09c73SVivien Didelot 	return err;
2658fad09c73SVivien Didelot }
2659fad09c73SVivien Didelot 
2660e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
2661fad09c73SVivien Didelot {
26620dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
26630dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
2664e57e5e77SVivien Didelot 	u16 val;
2665e57e5e77SVivien Didelot 	int err;
2666fad09c73SVivien Didelot 
2667ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_read)
2668ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
2669ee26a228SAndrew Lunn 
2670fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
2671ee26a228SAndrew Lunn 	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
2672fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2673e57e5e77SVivien Didelot 
2674da9f3301SAndrew Lunn 	if (reg == MII_PHYSID2) {
2675ddc49acbSAndrew Lunn 		/* Some internal PHYs don't have a model number. */
2676ddc49acbSAndrew Lunn 		if (chip->info->family != MV88E6XXX_FAMILY_6165)
2677ddc49acbSAndrew Lunn 			/* Then there is the 6165 family. It gets is
2678ddc49acbSAndrew Lunn 			 * PHYs correct. But it can also have two
2679ddc49acbSAndrew Lunn 			 * SERDES interfaces in the PHY address
2680ddc49acbSAndrew Lunn 			 * space. And these don't have a model
2681ddc49acbSAndrew Lunn 			 * number. But they are not PHYs, so we don't
2682ddc49acbSAndrew Lunn 			 * want to give them something a PHY driver
2683ddc49acbSAndrew Lunn 			 * will recognise.
2684ddc49acbSAndrew Lunn 			 *
2685ddc49acbSAndrew Lunn 			 * Use the mv88e6390 family model number
2686ddc49acbSAndrew Lunn 			 * instead, for anything which really could be
2687ddc49acbSAndrew Lunn 			 * a PHY,
2688da9f3301SAndrew Lunn 			 */
2689da9f3301SAndrew Lunn 			if (!(val & 0x3f0))
2690107fcc10SVivien Didelot 				val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4;
2691da9f3301SAndrew Lunn 	}
2692da9f3301SAndrew Lunn 
2693e57e5e77SVivien Didelot 	return err ? err : val;
2694fad09c73SVivien Didelot }
2695fad09c73SVivien Didelot 
2696e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
2697fad09c73SVivien Didelot {
26980dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
26990dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
2700e57e5e77SVivien Didelot 	int err;
2701fad09c73SVivien Didelot 
2702ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_write)
2703ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
2704ee26a228SAndrew Lunn 
2705fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
2706ee26a228SAndrew Lunn 	err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
2707fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2708e57e5e77SVivien Didelot 
2709e57e5e77SVivien Didelot 	return err;
2710fad09c73SVivien Didelot }
2711fad09c73SVivien Didelot 
2712fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
2713a3c53be5SAndrew Lunn 				   struct device_node *np,
2714a3c53be5SAndrew Lunn 				   bool external)
2715fad09c73SVivien Didelot {
2716fad09c73SVivien Didelot 	static int index;
27170dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
2718fad09c73SVivien Didelot 	struct mii_bus *bus;
2719fad09c73SVivien Didelot 	int err;
2720fad09c73SVivien Didelot 
27212510babcSAndrew Lunn 	if (external) {
27222510babcSAndrew Lunn 		mutex_lock(&chip->reg_lock);
27232510babcSAndrew Lunn 		err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
27242510babcSAndrew Lunn 		mutex_unlock(&chip->reg_lock);
27252510babcSAndrew Lunn 
27262510babcSAndrew Lunn 		if (err)
27272510babcSAndrew Lunn 			return err;
27282510babcSAndrew Lunn 	}
27292510babcSAndrew Lunn 
27300dd12d54SAndrew Lunn 	bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
2731fad09c73SVivien Didelot 	if (!bus)
2732fad09c73SVivien Didelot 		return -ENOMEM;
2733fad09c73SVivien Didelot 
27340dd12d54SAndrew Lunn 	mdio_bus = bus->priv;
2735a3c53be5SAndrew Lunn 	mdio_bus->bus = bus;
27360dd12d54SAndrew Lunn 	mdio_bus->chip = chip;
2737a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&mdio_bus->list);
2738a3c53be5SAndrew Lunn 	mdio_bus->external = external;
27390dd12d54SAndrew Lunn 
2740fad09c73SVivien Didelot 	if (np) {
2741fad09c73SVivien Didelot 		bus->name = np->full_name;
2742f7ce9103SRob Herring 		snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np);
2743fad09c73SVivien Didelot 	} else {
2744fad09c73SVivien Didelot 		bus->name = "mv88e6xxx SMI";
2745fad09c73SVivien Didelot 		snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
2746fad09c73SVivien Didelot 	}
2747fad09c73SVivien Didelot 
2748fad09c73SVivien Didelot 	bus->read = mv88e6xxx_mdio_read;
2749fad09c73SVivien Didelot 	bus->write = mv88e6xxx_mdio_write;
2750fad09c73SVivien Didelot 	bus->parent = chip->dev;
2751fad09c73SVivien Didelot 
27526f88284fSAndrew Lunn 	if (!external) {
27536f88284fSAndrew Lunn 		err = mv88e6xxx_g2_irq_mdio_setup(chip, bus);
27546f88284fSAndrew Lunn 		if (err)
27556f88284fSAndrew Lunn 			return err;
27566f88284fSAndrew Lunn 	}
27576f88284fSAndrew Lunn 
2758a3c53be5SAndrew Lunn 	err = of_mdiobus_register(bus, np);
2759fad09c73SVivien Didelot 	if (err) {
2760fad09c73SVivien Didelot 		dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
27616f88284fSAndrew Lunn 		mv88e6xxx_g2_irq_mdio_free(chip, bus);
2762fad09c73SVivien Didelot 		return err;
2763fad09c73SVivien Didelot 	}
2764fad09c73SVivien Didelot 
2765a3c53be5SAndrew Lunn 	if (external)
2766a3c53be5SAndrew Lunn 		list_add_tail(&mdio_bus->list, &chip->mdios);
2767a3c53be5SAndrew Lunn 	else
2768a3c53be5SAndrew Lunn 		list_add(&mdio_bus->list, &chip->mdios);
2769a3c53be5SAndrew Lunn 
2770a3c53be5SAndrew Lunn 	return 0;
2771a3c53be5SAndrew Lunn }
2772a3c53be5SAndrew Lunn 
2773a3c53be5SAndrew Lunn static const struct of_device_id mv88e6xxx_mdio_external_match[] = {
2774a3c53be5SAndrew Lunn 	{ .compatible = "marvell,mv88e6xxx-mdio-external",
2775a3c53be5SAndrew Lunn 	  .data = (void *)true },
2776a3c53be5SAndrew Lunn 	{ },
2777a3c53be5SAndrew Lunn };
2778a3c53be5SAndrew Lunn 
27793126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
27803126aeecSAndrew Lunn 
27813126aeecSAndrew Lunn {
27823126aeecSAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
27833126aeecSAndrew Lunn 	struct mii_bus *bus;
27843126aeecSAndrew Lunn 
27853126aeecSAndrew Lunn 	list_for_each_entry(mdio_bus, &chip->mdios, list) {
27863126aeecSAndrew Lunn 		bus = mdio_bus->bus;
27873126aeecSAndrew Lunn 
27886f88284fSAndrew Lunn 		if (!mdio_bus->external)
27896f88284fSAndrew Lunn 			mv88e6xxx_g2_irq_mdio_free(chip, bus);
27906f88284fSAndrew Lunn 
27913126aeecSAndrew Lunn 		mdiobus_unregister(bus);
27923126aeecSAndrew Lunn 	}
27933126aeecSAndrew Lunn }
27943126aeecSAndrew Lunn 
2795a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
2796a3c53be5SAndrew Lunn 				    struct device_node *np)
2797a3c53be5SAndrew Lunn {
2798a3c53be5SAndrew Lunn 	const struct of_device_id *match;
2799a3c53be5SAndrew Lunn 	struct device_node *child;
2800a3c53be5SAndrew Lunn 	int err;
2801a3c53be5SAndrew Lunn 
2802a3c53be5SAndrew Lunn 	/* Always register one mdio bus for the internal/default mdio
2803a3c53be5SAndrew Lunn 	 * bus. This maybe represented in the device tree, but is
2804a3c53be5SAndrew Lunn 	 * optional.
2805a3c53be5SAndrew Lunn 	 */
2806a3c53be5SAndrew Lunn 	child = of_get_child_by_name(np, "mdio");
2807a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdio_register(chip, child, false);
2808a3c53be5SAndrew Lunn 	if (err)
2809a3c53be5SAndrew Lunn 		return err;
2810a3c53be5SAndrew Lunn 
2811a3c53be5SAndrew Lunn 	/* Walk the device tree, and see if there are any other nodes
2812a3c53be5SAndrew Lunn 	 * which say they are compatible with the external mdio
2813a3c53be5SAndrew Lunn 	 * bus.
2814a3c53be5SAndrew Lunn 	 */
2815a3c53be5SAndrew Lunn 	for_each_available_child_of_node(np, child) {
2816a3c53be5SAndrew Lunn 		match = of_match_node(mv88e6xxx_mdio_external_match, child);
2817a3c53be5SAndrew Lunn 		if (match) {
2818a3c53be5SAndrew Lunn 			err = mv88e6xxx_mdio_register(chip, child, true);
28193126aeecSAndrew Lunn 			if (err) {
28203126aeecSAndrew Lunn 				mv88e6xxx_mdios_unregister(chip);
2821a3c53be5SAndrew Lunn 				return err;
2822a3c53be5SAndrew Lunn 			}
2823a3c53be5SAndrew Lunn 		}
28243126aeecSAndrew Lunn 	}
2825a3c53be5SAndrew Lunn 
2826a3c53be5SAndrew Lunn 	return 0;
2827a3c53be5SAndrew Lunn }
2828a3c53be5SAndrew Lunn 
2829855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
2830855b1932SVivien Didelot {
283104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2832855b1932SVivien Didelot 
2833855b1932SVivien Didelot 	return chip->eeprom_len;
2834855b1932SVivien Didelot }
2835855b1932SVivien Didelot 
2836855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
2837855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
2838855b1932SVivien Didelot {
283904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2840855b1932SVivien Didelot 	int err;
2841855b1932SVivien Didelot 
2842ee4dc2e7SVivien Didelot 	if (!chip->info->ops->get_eeprom)
2843ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
2844ee4dc2e7SVivien Didelot 
2845855b1932SVivien Didelot 	mutex_lock(&chip->reg_lock);
2846ee4dc2e7SVivien Didelot 	err = chip->info->ops->get_eeprom(chip, eeprom, data);
2847855b1932SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2848855b1932SVivien Didelot 
2849855b1932SVivien Didelot 	if (err)
2850855b1932SVivien Didelot 		return err;
2851855b1932SVivien Didelot 
2852855b1932SVivien Didelot 	eeprom->magic = 0xc3ec4951;
2853855b1932SVivien Didelot 
2854855b1932SVivien Didelot 	return 0;
2855855b1932SVivien Didelot }
2856855b1932SVivien Didelot 
2857855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
2858855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
2859855b1932SVivien Didelot {
286004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2861855b1932SVivien Didelot 	int err;
2862855b1932SVivien Didelot 
2863ee4dc2e7SVivien Didelot 	if (!chip->info->ops->set_eeprom)
2864ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
2865ee4dc2e7SVivien Didelot 
2866855b1932SVivien Didelot 	if (eeprom->magic != 0xc3ec4951)
2867855b1932SVivien Didelot 		return -EINVAL;
2868855b1932SVivien Didelot 
2869855b1932SVivien Didelot 	mutex_lock(&chip->reg_lock);
2870ee4dc2e7SVivien Didelot 	err = chip->info->ops->set_eeprom(chip, eeprom, data);
2871855b1932SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2872855b1932SVivien Didelot 
2873855b1932SVivien Didelot 	return err;
2874855b1932SVivien Didelot }
2875855b1932SVivien Didelot 
2876b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = {
28774b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6097 */
287893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
287993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2880cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
2881b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
28827e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
28837e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
288408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
28857f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
288696a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
2887ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
288856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2889601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
289056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
2891ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
28920898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
2893c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
28949dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
28956c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
28962d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
2897a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
289840cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2899dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
2900dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
2901052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
2902fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
2903fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
2904fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
290551c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
29069e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
2907a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
2908a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
290917e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
29109e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
2911f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
29120ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
29136c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
2914b3469dd8SVivien Didelot };
2915b3469dd8SVivien Didelot 
2916b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = {
29174b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6095 */
291893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
291993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2920b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
29217e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
29227e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
292308ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
29247f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
292596a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
292656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
2927601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
2928a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
29296c422e34SRussell King 	.port_link_state = mv88e6185_port_link_state,
29302d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
2931a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
293240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2933dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
2934dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
2935052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
293651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
2937a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
2938a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
293917e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
2940f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
29410ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
29426c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
2943b3469dd8SVivien Didelot };
2944b3469dd8SVivien Didelot 
29457d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = {
294615da3cc8SStefan Eichenberger 	/* MV88E6XXX_FAMILY_6097 */
294793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
294893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2949cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
29507d381a02SStefan Eichenberger 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
29517d381a02SStefan Eichenberger 	.phy_read = mv88e6xxx_g2_smi_phy_read,
29527d381a02SStefan Eichenberger 	.phy_write = mv88e6xxx_g2_smi_phy_write,
29537d381a02SStefan Eichenberger 	.port_set_link = mv88e6xxx_port_set_link,
29547d381a02SStefan Eichenberger 	.port_set_duplex = mv88e6xxx_port_set_duplex,
29557d381a02SStefan Eichenberger 	.port_set_speed = mv88e6185_port_set_speed,
2956ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
295756995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2958601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
295956995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
2960cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2961ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
29620898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
2963c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
29649dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
29656c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
29662d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
29677d381a02SStefan Eichenberger 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
296840cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
29697d381a02SStefan Eichenberger 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
29707d381a02SStefan Eichenberger 	.stats_get_strings = mv88e6095_stats_get_strings,
29717d381a02SStefan Eichenberger 	.stats_get_stats = mv88e6095_stats_get_stats,
2972fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
2973fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
297491eaa475SVolodymyr Bendiuga 	.watchdog_ops = &mv88e6097_watchdog_ops,
297551c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
29769e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
297717e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
29789e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
2979f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
29800ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
29816c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
29827d381a02SStefan Eichenberger };
29837d381a02SStefan Eichenberger 
2984b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = {
29854b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
298693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
298793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2988cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
2989b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2990ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
2991ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
299208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
29937f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
299496a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
299556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
2996601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2997c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
29989dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
29996c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
30002d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
30010ac64c39SAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
300240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3003dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3004dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3005052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3006fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3007fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3008fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
300951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
30109e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
301117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3012f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
30130ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
30146c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3015b3469dd8SVivien Didelot };
3016b3469dd8SVivien Didelot 
3017b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = {
30184b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
301993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
302093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3021b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
30227e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
30237e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
302408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
30257f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
302696a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3027ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
302856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3029601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
303056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3031a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
3032cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3033ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
30340898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
303554186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
30366c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
30372d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3038a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
303940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3040dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3041dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3042052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3043fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3044fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3045fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
304651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3047a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
304802317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3049a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
305017e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3051f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
30520ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
30536c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3054b3469dd8SVivien Didelot };
3055b3469dd8SVivien Didelot 
3056990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = {
3057990e27b0SVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
305893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
305993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3060cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3061990e27b0SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
3062990e27b0SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3063990e27b0SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3064990e27b0SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3065990e27b0SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
3066990e27b0SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3067990e27b0SVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3068990e27b0SVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
306926422340SMarek Behún 	.port_set_speed = mv88e6341_port_set_speed,
3070990e27b0SVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
3071990e27b0SVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3072990e27b0SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3073990e27b0SVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3074cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3075990e27b0SVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
30760898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3077990e27b0SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3078990e27b0SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
30796c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
30802d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3081990e27b0SVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
308240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3083990e27b0SVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3084990e27b0SVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
3085990e27b0SVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
3086fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3087fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
3088990e27b0SVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
3089990e27b0SVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
30909e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
3091990e27b0SVivien Didelot 	.reset = mv88e6352_g1_reset,
3092f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
30930ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
30946751e7c6SAndrew Lunn 	.serdes_power = mv88e6341_serdes_power,
3095a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
3096e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
3097990e27b0SVivien Didelot };
3098990e27b0SVivien Didelot 
3099b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = {
31004b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
310193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
310293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3103cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3104b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3105ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3106ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
310708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
31087f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
310996a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3110ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
311156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3112601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
311356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3114cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3115ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
31160898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3117c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
31189dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
31196c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
31202d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3121a6da21bbSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
312240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3123dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3124dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3125052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3126fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3127fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3128fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
312951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
31309e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
313117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3132f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
31330ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3134a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3135dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
31366c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3137b3469dd8SVivien Didelot };
3138b3469dd8SVivien Didelot 
3139b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = {
31404b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
314193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
314293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3143cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3144b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3145efb3e74dSAndrew Lunn 	.phy_read = mv88e6165_phy_read,
3146efb3e74dSAndrew Lunn 	.phy_write = mv88e6165_phy_write,
314708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
31487f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
314996a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3150c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
31519dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
31526c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
31532d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3154a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
315540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3156dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3157dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3158052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3159fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3160fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3161fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
316251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
31639e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
316417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3165f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
31660ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3167a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3168dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
31696c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3170b3469dd8SVivien Didelot };
3171b3469dd8SVivien Didelot 
3172b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = {
31734b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
317493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
317593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3176cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3177b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3178b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3179b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
318008ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
31817f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
318294d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
318396a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3184ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
318556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3186601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
318756995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3188cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3189ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
31900898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3191c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
31929dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
31936c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
31942d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3195a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
319640cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3197dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3198dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3199052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3200fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3201fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3202fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
320351c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
32049e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
320517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3206f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
32070ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
32086c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3209b3469dd8SVivien Didelot };
3210b3469dd8SVivien Didelot 
3211b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = {
32124b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
321393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
321493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3215cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3216ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3217ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3218b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3219b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3220b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
322108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
32227f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3223a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
322496a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3225ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
322656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3227601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
322856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3229cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3230ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
32310898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3232c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
32339dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
32346c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
32352d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3236a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
323740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3238dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3239dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3240052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3241fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3242fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3243fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
324451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
32459e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
324617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
32479e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
3248f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
32490ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
32506d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
3251a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
32526c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3253b3469dd8SVivien Didelot };
3254b3469dd8SVivien Didelot 
3255b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = {
32564b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
325793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
325893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3259cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3260b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3261b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3262b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
326308ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
32647f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
326594d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
326696a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3267ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
326856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3269601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
327056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3271cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3272ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
32730898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3274c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
32759dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
32766c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
32772d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3278a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
327940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3280dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3281dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3282052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3283fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3284fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3285fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
328651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
32879e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
328817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3289f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
32900ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
32916c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3292b3469dd8SVivien Didelot };
3293b3469dd8SVivien Didelot 
3294b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = {
32954b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
329693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
329793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3298cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3299ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3300ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3301b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3302b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3303b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
330408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
33057f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3306a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
330796a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3308ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
330956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3310601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
331156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3312cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3313ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
33140898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3315c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
33169dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
33176c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
33182d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3319a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
332040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3321dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3322dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3323052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3324fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3325fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3326fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
332751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
33289e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
332917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
33309e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
3331f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
33320ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
33336d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
33344382172fSAndrew Lunn 	.serdes_irq_setup = mv88e6352_serdes_irq_setup,
33354382172fSAndrew Lunn 	.serdes_irq_free = mv88e6352_serdes_irq_free,
3336a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
33376c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3338b3469dd8SVivien Didelot };
3339b3469dd8SVivien Didelot 
3340b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = {
33414b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
334293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
334393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3344b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
33457e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
33467e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
334708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
33487f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
334996a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
335056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3351601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
3352ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
3353a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
335454186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
33556c422e34SRussell King 	.port_link_state = mv88e6185_port_link_state,
33562d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3357a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
335840cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3359dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3360dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3361052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3362fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3363fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3364fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
336551c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
336602317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3367a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3368a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
336917e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3370f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
33710ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
33726c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3373b3469dd8SVivien Didelot };
3374b3469dd8SVivien Didelot 
33751a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = {
33764b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3377ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3378cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
337998fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
338098fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
33811a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
33821a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
33831a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
33841a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
33851a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
33861a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
33871a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
3388ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
338956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3390601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
339156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
33920898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3393c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
33949dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
33956c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
33962d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3397fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
339879523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3399de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3400dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3401dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3402e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3403fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3404fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
340561303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
34066e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
34079e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
340817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
34099e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3410931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3411931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
34126335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
3413efd1ba6aSAndrew Lunn 	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
3414efd1ba6aSAndrew Lunn 	.serdes_irq_free = mv88e6390_serdes_irq_free,
3415a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
34166c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
34171a3b39ecSAndrew Lunn };
34181a3b39ecSAndrew Lunn 
34191a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = {
34204b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3421ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3422cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
342398fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
342498fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
34251a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
34261a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
34271a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
34281a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
34291a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
34301a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
34311a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390x_port_set_speed,
3432ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
343356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3434601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
343556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
34360898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3437c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
34389dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34396c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
34402d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3441fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
344279523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3443de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3444dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3445dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3446e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3447fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3448fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
344961303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
34506e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
34519e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
345217e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
34539e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3454931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3455931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
345607ffbd74SAndrew Lunn 	.serdes_power = mv88e6390x_serdes_power,
34572defda1fSAndrew Lunn 	.serdes_irq_setup = mv88e6390x_serdes_irq_setup,
34582defda1fSAndrew Lunn 	.serdes_irq_free = mv88e6390x_serdes_irq_free,
3459a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
34606c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
34611a3b39ecSAndrew Lunn };
34621a3b39ecSAndrew Lunn 
34631a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = {
34644b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3465ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3466cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
346798fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
346898fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
34691a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
34701a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
34711a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
34721a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
34731a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
34741a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
34751a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
3476ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
347756995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3478601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
347956995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
34800898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3481c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
34829dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34836c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
34842d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3485fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
348679523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3487de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3488dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3489dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3490e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3491fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3492fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
349361303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
34946e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
34959e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
349617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
34979e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3498931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3499931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
35006335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
3501efd1ba6aSAndrew Lunn 	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
3502efd1ba6aSAndrew Lunn 	.serdes_irq_free = mv88e6390_serdes_irq_free,
35036d2ac8eeSAndrew Lunn 	.avb_ops = &mv88e6390_avb_ops,
35046d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
35056c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
35061a3b39ecSAndrew Lunn };
35071a3b39ecSAndrew Lunn 
3508b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = {
35094b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
351093e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
351193e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3512cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3513ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3514ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3515b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3516b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3517b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
351808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
35197f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3520a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
352196a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3522ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
352356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3524601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
352556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3526cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3527ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
35280898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3529c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
35309dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35316c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
35322d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3533a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
353440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3535dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3536dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3537052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3538fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3539fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3540fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
354151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
35429e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
354317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
35449e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
3545f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
35460ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
35476d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
35484382172fSAndrew Lunn 	.serdes_irq_setup = mv88e6352_serdes_irq_setup,
35494382172fSAndrew Lunn 	.serdes_irq_free = mv88e6352_serdes_irq_free,
3550a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
35510d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
35526d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
35536c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3554b3469dd8SVivien Didelot };
3555b3469dd8SVivien Didelot 
35561a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = {
35574b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3558ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3559cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
356098fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
356198fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
35621a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
35631a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
35641a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
35651a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
35661a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
35671a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
35681a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
3569ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
357056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3571601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
357256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
35730898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3574c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
35759dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35766c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
35772d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3578fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
357979523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3580de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3581dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3582dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3583e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3584fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3585fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
358661303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
35876e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
35889e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
358917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
35909e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3591931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3592931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
35936335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
3594efd1ba6aSAndrew Lunn 	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
3595efd1ba6aSAndrew Lunn 	.serdes_irq_free = mv88e6390_serdes_irq_free,
3596a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
35970d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
35986d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
35996c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
36001a3b39ecSAndrew Lunn };
36011a3b39ecSAndrew Lunn 
3602b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = {
36034b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6320 */
360493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
360593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3606cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3607ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3608ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3609b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3610b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3611b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
361208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
36137f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
361496a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3615ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
361656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3617601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
361856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3619cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3620ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36210898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3622c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36239dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36246c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
36252d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3626a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
362740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3628dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3629dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3630052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
3631fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3632fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
36339c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
363451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
36359e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
363617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3637f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
36380ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
3639a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
36400d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
36416d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
36426c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3643b3469dd8SVivien Didelot };
3644b3469dd8SVivien Didelot 
3645b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = {
3646bd807204SVivien Didelot 	/* MV88E6XXX_FAMILY_6320 */
364793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
364893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3649cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3650ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3651ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3652b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3653b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3654b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
365508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
36567f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
365796a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3658ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
365956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3660601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
366156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3662cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3663ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36640898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3665c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36669dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36676c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
36682d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3669a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
367040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3671dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3672dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3673052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
3674fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3675fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
36769c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
367717e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3678f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
36790ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
3680a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
36810d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
36826d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
36836c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3684b3469dd8SVivien Didelot };
3685b3469dd8SVivien Didelot 
368616e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = {
368716e329aeSVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
368893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
368993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3690cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
369116e329aeSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
369216e329aeSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
369316e329aeSVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
369416e329aeSVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
369516e329aeSVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
369616e329aeSVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
369716e329aeSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
369816e329aeSVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
369926422340SMarek Behún 	.port_set_speed = mv88e6341_port_set_speed,
370016e329aeSVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
370116e329aeSVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
370216e329aeSVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
370316e329aeSVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3704cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
370516e329aeSVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37060898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
370716e329aeSVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
370816e329aeSVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37096c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
37102d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
371116e329aeSVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
371240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
371316e329aeSVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
371416e329aeSVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
371516e329aeSVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
3716fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3717fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
371816e329aeSVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
371916e329aeSVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
37209e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
372116e329aeSVivien Didelot 	.reset = mv88e6352_g1_reset,
3722f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37230ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37246751e7c6SAndrew Lunn 	.serdes_power = mv88e6341_serdes_power,
3725a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
37260d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
37276d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
3728e3af71a3SMarek Behún 	.phylink_validate = mv88e6341_phylink_validate,
372916e329aeSVivien Didelot };
373016e329aeSVivien Didelot 
3731b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = {
37324b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
373393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
373493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3735cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3736b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3737b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3738b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
373908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
37407f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
374194d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
374296a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3743ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
374456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3745601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
374656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3747cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3748ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37490898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3750c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
37519dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37526c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
37532d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3754a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
375540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3756dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3757dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3758052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3759fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3760fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3761fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
376251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
37639e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
376417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3765f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37660ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37676c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3768b3469dd8SVivien Didelot };
3769b3469dd8SVivien Didelot 
3770b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = {
37714b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
377293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
377393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3774cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3775b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3776b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3777b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
377808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
37797f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
378094d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
378196a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3782ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
378356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3784601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
378556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3786cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3787ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37880898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3789c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
37909dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37916c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
37922d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3793a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
379440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3795dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3796dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3797052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3798fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3799fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3800fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
380151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
38029e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
380317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3804f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
38050ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
38060d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
38076d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
38086c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3809b3469dd8SVivien Didelot };
3810b3469dd8SVivien Didelot 
3811b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = {
38124b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
381393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
381493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3815cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3816ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3817ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3818b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3819b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3820b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
382108ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
38227f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3823a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
382496a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3825ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
382656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3827601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
382856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3829cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3830ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
38310898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3832c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38339dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38346c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
38352d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3836a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
383740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3838dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3839dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3840052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3841fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3842fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3843fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
384451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
38459e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
384617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
38479e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
3848f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
38490ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
38506d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
38514382172fSAndrew Lunn 	.serdes_irq_setup = mv88e6352_serdes_irq_setup,
38524382172fSAndrew Lunn 	.serdes_irq_free = mv88e6352_serdes_irq_free,
3853a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
38540d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
38556d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
3856cda9f4aaSAndrew Lunn 	.serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
3857cda9f4aaSAndrew Lunn 	.serdes_get_strings = mv88e6352_serdes_get_strings,
3858cda9f4aaSAndrew Lunn 	.serdes_get_stats = mv88e6352_serdes_get_stats,
38596c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3860b3469dd8SVivien Didelot };
3861b3469dd8SVivien Didelot 
38621a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = {
38634b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3864ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3865cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
386698fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
386798fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
38681a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
38691a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
38701a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
38711a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
38721a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
38731a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
38741a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
3875ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
387656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3877601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
387856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3879cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3880ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
38810898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3882c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38839dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38846c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
38852d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3886fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
388779523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3888de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3889dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3890dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3891e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3892fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3893fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
389461303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
38956e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
38969e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
389717e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
38989e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3899931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3900931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
39016335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
3902efd1ba6aSAndrew Lunn 	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
3903efd1ba6aSAndrew Lunn 	.serdes_irq_free = mv88e6390_serdes_irq_free,
3904a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
39050d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
39066d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
39076c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
39081a3b39ecSAndrew Lunn };
39091a3b39ecSAndrew Lunn 
39101a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = {
39114b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3912ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3913cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
391498fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
391598fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
39161a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
39171a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
39181a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
39191a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
39201a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
39211a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
39221a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390x_port_set_speed,
3923ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
392456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3925601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
392656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3927cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3928ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
39290898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3930c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
39319dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
39326c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
39332d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3934b3dce4daSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
393579523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3936de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3937dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3938dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3939e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3940fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3941fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
394261303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
39436e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
39449e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
394517e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
39469e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3947931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3948931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
394907ffbd74SAndrew Lunn 	.serdes_power = mv88e6390x_serdes_power,
39502defda1fSAndrew Lunn 	.serdes_irq_setup = mv88e6390x_serdes_irq_setup,
39512defda1fSAndrew Lunn 	.serdes_irq_free = mv88e6390x_serdes_irq_free,
3952a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
39530d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
39546d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
39556c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
39561a3b39ecSAndrew Lunn };
39571a3b39ecSAndrew Lunn 
3958fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3959fad09c73SVivien Didelot 	[MV88E6085] = {
3960107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
3961fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6097,
3962fad09c73SVivien Didelot 		.name = "Marvell 88E6085",
3963fad09c73SVivien Didelot 		.num_databases = 4096,
3964fad09c73SVivien Didelot 		.num_ports = 10,
3965bc393155SAndrew Lunn 		.num_internal_phys = 5,
39663cf3c846SVivien Didelot 		.max_vid = 4095,
3967fad09c73SVivien Didelot 		.port_base_addr = 0x10,
39689255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
3969a935c052SVivien Didelot 		.global1_addr = 0x1b,
39709069c13aSVivien Didelot 		.global2_addr = 0x1c,
3971acddbd21SVivien Didelot 		.age_time_coeff = 15000,
3972dc30c35bSAndrew Lunn 		.g1_irqs = 8,
3973d6c5e6afSVivien Didelot 		.g2_irqs = 10,
3974e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
3975f3645652SVivien Didelot 		.pvt = true,
3976b3e05aa1SVivien Didelot 		.multi_chip = true,
3977443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
3978b3469dd8SVivien Didelot 		.ops = &mv88e6085_ops,
3979fad09c73SVivien Didelot 	},
3980fad09c73SVivien Didelot 
3981fad09c73SVivien Didelot 	[MV88E6095] = {
3982107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095,
3983fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6095,
3984fad09c73SVivien Didelot 		.name = "Marvell 88E6095/88E6095F",
3985fad09c73SVivien Didelot 		.num_databases = 256,
3986fad09c73SVivien Didelot 		.num_ports = 11,
3987bc393155SAndrew Lunn 		.num_internal_phys = 0,
39883cf3c846SVivien Didelot 		.max_vid = 4095,
3989fad09c73SVivien Didelot 		.port_base_addr = 0x10,
39909255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
3991a935c052SVivien Didelot 		.global1_addr = 0x1b,
39929069c13aSVivien Didelot 		.global2_addr = 0x1c,
3993acddbd21SVivien Didelot 		.age_time_coeff = 15000,
3994dc30c35bSAndrew Lunn 		.g1_irqs = 8,
3995e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
3996b3e05aa1SVivien Didelot 		.multi_chip = true,
3997443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
3998b3469dd8SVivien Didelot 		.ops = &mv88e6095_ops,
3999fad09c73SVivien Didelot 	},
4000fad09c73SVivien Didelot 
40017d381a02SStefan Eichenberger 	[MV88E6097] = {
4002107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097,
40037d381a02SStefan Eichenberger 		.family = MV88E6XXX_FAMILY_6097,
40047d381a02SStefan Eichenberger 		.name = "Marvell 88E6097/88E6097F",
40057d381a02SStefan Eichenberger 		.num_databases = 4096,
40067d381a02SStefan Eichenberger 		.num_ports = 11,
4007bc393155SAndrew Lunn 		.num_internal_phys = 8,
40083cf3c846SVivien Didelot 		.max_vid = 4095,
40097d381a02SStefan Eichenberger 		.port_base_addr = 0x10,
40109255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
40117d381a02SStefan Eichenberger 		.global1_addr = 0x1b,
40129069c13aSVivien Didelot 		.global2_addr = 0x1c,
40137d381a02SStefan Eichenberger 		.age_time_coeff = 15000,
4014c534178bSStefan Eichenberger 		.g1_irqs = 8,
4015d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4016e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4017f3645652SVivien Didelot 		.pvt = true,
4018b3e05aa1SVivien Didelot 		.multi_chip = true,
40192bfcfcd3SStefan Eichenberger 		.tag_protocol = DSA_TAG_PROTO_EDSA,
40207d381a02SStefan Eichenberger 		.ops = &mv88e6097_ops,
40217d381a02SStefan Eichenberger 	},
40227d381a02SStefan Eichenberger 
4023fad09c73SVivien Didelot 	[MV88E6123] = {
4024107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123,
4025fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4026fad09c73SVivien Didelot 		.name = "Marvell 88E6123",
4027fad09c73SVivien Didelot 		.num_databases = 4096,
4028fad09c73SVivien Didelot 		.num_ports = 3,
4029bc393155SAndrew Lunn 		.num_internal_phys = 5,
40303cf3c846SVivien Didelot 		.max_vid = 4095,
4031fad09c73SVivien Didelot 		.port_base_addr = 0x10,
40329255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4033a935c052SVivien Didelot 		.global1_addr = 0x1b,
40349069c13aSVivien Didelot 		.global2_addr = 0x1c,
4035acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4036dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4037d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4038e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4039f3645652SVivien Didelot 		.pvt = true,
4040b3e05aa1SVivien Didelot 		.multi_chip = true,
40415ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4042b3469dd8SVivien Didelot 		.ops = &mv88e6123_ops,
4043fad09c73SVivien Didelot 	},
4044fad09c73SVivien Didelot 
4045fad09c73SVivien Didelot 	[MV88E6131] = {
4046107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131,
4047fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
4048fad09c73SVivien Didelot 		.name = "Marvell 88E6131",
4049fad09c73SVivien Didelot 		.num_databases = 256,
4050fad09c73SVivien Didelot 		.num_ports = 8,
4051bc393155SAndrew Lunn 		.num_internal_phys = 0,
40523cf3c846SVivien Didelot 		.max_vid = 4095,
4053fad09c73SVivien Didelot 		.port_base_addr = 0x10,
40549255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4055a935c052SVivien Didelot 		.global1_addr = 0x1b,
40569069c13aSVivien Didelot 		.global2_addr = 0x1c,
4057acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4058dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4059e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4060b3e05aa1SVivien Didelot 		.multi_chip = true,
4061443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4062b3469dd8SVivien Didelot 		.ops = &mv88e6131_ops,
4063fad09c73SVivien Didelot 	},
4064fad09c73SVivien Didelot 
4065990e27b0SVivien Didelot 	[MV88E6141] = {
4066107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141,
4067990e27b0SVivien Didelot 		.family = MV88E6XXX_FAMILY_6341,
406879a68b26SUwe Kleine-König 		.name = "Marvell 88E6141",
4069990e27b0SVivien Didelot 		.num_databases = 4096,
4070990e27b0SVivien Didelot 		.num_ports = 6,
4071bc393155SAndrew Lunn 		.num_internal_phys = 5,
4072a73ccd61SBrandon Streiff 		.num_gpio = 11,
40733cf3c846SVivien Didelot 		.max_vid = 4095,
4074990e27b0SVivien Didelot 		.port_base_addr = 0x10,
40759255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
4076990e27b0SVivien Didelot 		.global1_addr = 0x1b,
40779069c13aSVivien Didelot 		.global2_addr = 0x1c,
4078990e27b0SVivien Didelot 		.age_time_coeff = 3750,
4079990e27b0SVivien Didelot 		.atu_move_port_mask = 0x1f,
4080adfccf11SAndrew Lunn 		.g1_irqs = 9,
4081d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4082f3645652SVivien Didelot 		.pvt = true,
4083b3e05aa1SVivien Didelot 		.multi_chip = true,
4084990e27b0SVivien Didelot 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4085990e27b0SVivien Didelot 		.ops = &mv88e6141_ops,
4086990e27b0SVivien Didelot 	},
4087990e27b0SVivien Didelot 
4088fad09c73SVivien Didelot 	[MV88E6161] = {
4089107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161,
4090fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4091fad09c73SVivien Didelot 		.name = "Marvell 88E6161",
4092fad09c73SVivien Didelot 		.num_databases = 4096,
4093fad09c73SVivien Didelot 		.num_ports = 6,
4094bc393155SAndrew Lunn 		.num_internal_phys = 5,
40953cf3c846SVivien Didelot 		.max_vid = 4095,
4096fad09c73SVivien Didelot 		.port_base_addr = 0x10,
40979255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4098a935c052SVivien Didelot 		.global1_addr = 0x1b,
40999069c13aSVivien Didelot 		.global2_addr = 0x1c,
4100acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4101dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4102d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4103e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4104f3645652SVivien Didelot 		.pvt = true,
4105b3e05aa1SVivien Didelot 		.multi_chip = true,
41065ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4107dfa54348SAndrew Lunn 		.ptp_support = true,
4108b3469dd8SVivien Didelot 		.ops = &mv88e6161_ops,
4109fad09c73SVivien Didelot 	},
4110fad09c73SVivien Didelot 
4111fad09c73SVivien Didelot 	[MV88E6165] = {
4112107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165,
4113fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4114fad09c73SVivien Didelot 		.name = "Marvell 88E6165",
4115fad09c73SVivien Didelot 		.num_databases = 4096,
4116fad09c73SVivien Didelot 		.num_ports = 6,
4117bc393155SAndrew Lunn 		.num_internal_phys = 0,
41183cf3c846SVivien Didelot 		.max_vid = 4095,
4119fad09c73SVivien Didelot 		.port_base_addr = 0x10,
41209255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4121a935c052SVivien Didelot 		.global1_addr = 0x1b,
41229069c13aSVivien Didelot 		.global2_addr = 0x1c,
4123acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4124dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4125d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4126e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4127f3645652SVivien Didelot 		.pvt = true,
4128b3e05aa1SVivien Didelot 		.multi_chip = true,
4129443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4130dfa54348SAndrew Lunn 		.ptp_support = true,
4131b3469dd8SVivien Didelot 		.ops = &mv88e6165_ops,
4132fad09c73SVivien Didelot 	},
4133fad09c73SVivien Didelot 
4134fad09c73SVivien Didelot 	[MV88E6171] = {
4135107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171,
4136fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4137fad09c73SVivien Didelot 		.name = "Marvell 88E6171",
4138fad09c73SVivien Didelot 		.num_databases = 4096,
4139fad09c73SVivien Didelot 		.num_ports = 7,
4140bc393155SAndrew Lunn 		.num_internal_phys = 5,
41413cf3c846SVivien Didelot 		.max_vid = 4095,
4142fad09c73SVivien Didelot 		.port_base_addr = 0x10,
41439255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4144a935c052SVivien Didelot 		.global1_addr = 0x1b,
41459069c13aSVivien Didelot 		.global2_addr = 0x1c,
4146acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4147dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4148d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4149e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4150f3645652SVivien Didelot 		.pvt = true,
4151b3e05aa1SVivien Didelot 		.multi_chip = true,
4152443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4153b3469dd8SVivien Didelot 		.ops = &mv88e6171_ops,
4154fad09c73SVivien Didelot 	},
4155fad09c73SVivien Didelot 
4156fad09c73SVivien Didelot 	[MV88E6172] = {
4157107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172,
4158fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4159fad09c73SVivien Didelot 		.name = "Marvell 88E6172",
4160fad09c73SVivien Didelot 		.num_databases = 4096,
4161fad09c73SVivien Didelot 		.num_ports = 7,
4162bc393155SAndrew Lunn 		.num_internal_phys = 5,
4163a73ccd61SBrandon Streiff 		.num_gpio = 15,
41643cf3c846SVivien Didelot 		.max_vid = 4095,
4165fad09c73SVivien Didelot 		.port_base_addr = 0x10,
41669255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4167a935c052SVivien Didelot 		.global1_addr = 0x1b,
41689069c13aSVivien Didelot 		.global2_addr = 0x1c,
4169acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4170dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4171d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4172e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4173f3645652SVivien Didelot 		.pvt = true,
4174b3e05aa1SVivien Didelot 		.multi_chip = true,
4175443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4176b3469dd8SVivien Didelot 		.ops = &mv88e6172_ops,
4177fad09c73SVivien Didelot 	},
4178fad09c73SVivien Didelot 
4179fad09c73SVivien Didelot 	[MV88E6175] = {
4180107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175,
4181fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4182fad09c73SVivien Didelot 		.name = "Marvell 88E6175",
4183fad09c73SVivien Didelot 		.num_databases = 4096,
4184fad09c73SVivien Didelot 		.num_ports = 7,
4185bc393155SAndrew Lunn 		.num_internal_phys = 5,
41863cf3c846SVivien Didelot 		.max_vid = 4095,
4187fad09c73SVivien Didelot 		.port_base_addr = 0x10,
41889255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4189a935c052SVivien Didelot 		.global1_addr = 0x1b,
41909069c13aSVivien Didelot 		.global2_addr = 0x1c,
4191acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4192dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4193d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4194e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4195f3645652SVivien Didelot 		.pvt = true,
4196b3e05aa1SVivien Didelot 		.multi_chip = true,
4197443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4198b3469dd8SVivien Didelot 		.ops = &mv88e6175_ops,
4199fad09c73SVivien Didelot 	},
4200fad09c73SVivien Didelot 
4201fad09c73SVivien Didelot 	[MV88E6176] = {
4202107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176,
4203fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4204fad09c73SVivien Didelot 		.name = "Marvell 88E6176",
4205fad09c73SVivien Didelot 		.num_databases = 4096,
4206fad09c73SVivien Didelot 		.num_ports = 7,
4207bc393155SAndrew Lunn 		.num_internal_phys = 5,
4208a73ccd61SBrandon Streiff 		.num_gpio = 15,
42093cf3c846SVivien Didelot 		.max_vid = 4095,
4210fad09c73SVivien Didelot 		.port_base_addr = 0x10,
42119255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4212a935c052SVivien Didelot 		.global1_addr = 0x1b,
42139069c13aSVivien Didelot 		.global2_addr = 0x1c,
4214acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4215dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4216d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4217e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4218f3645652SVivien Didelot 		.pvt = true,
4219b3e05aa1SVivien Didelot 		.multi_chip = true,
4220443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4221b3469dd8SVivien Didelot 		.ops = &mv88e6176_ops,
4222fad09c73SVivien Didelot 	},
4223fad09c73SVivien Didelot 
4224fad09c73SVivien Didelot 	[MV88E6185] = {
4225107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185,
4226fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
4227fad09c73SVivien Didelot 		.name = "Marvell 88E6185",
4228fad09c73SVivien Didelot 		.num_databases = 256,
4229fad09c73SVivien Didelot 		.num_ports = 10,
4230bc393155SAndrew Lunn 		.num_internal_phys = 0,
42313cf3c846SVivien Didelot 		.max_vid = 4095,
4232fad09c73SVivien Didelot 		.port_base_addr = 0x10,
42339255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4234a935c052SVivien Didelot 		.global1_addr = 0x1b,
42359069c13aSVivien Didelot 		.global2_addr = 0x1c,
4236acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4237dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4238e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4239b3e05aa1SVivien Didelot 		.multi_chip = true,
4240443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4241b3469dd8SVivien Didelot 		.ops = &mv88e6185_ops,
4242fad09c73SVivien Didelot 	},
4243fad09c73SVivien Didelot 
42441a3b39ecSAndrew Lunn 	[MV88E6190] = {
4245107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190,
42461a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
42471a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190",
42481a3b39ecSAndrew Lunn 		.num_databases = 4096,
42491a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
4250bc393155SAndrew Lunn 		.num_internal_phys = 11,
4251a73ccd61SBrandon Streiff 		.num_gpio = 16,
4252931d1822SVivien Didelot 		.max_vid = 8191,
42531a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
42549255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
42551a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
42569069c13aSVivien Didelot 		.global2_addr = 0x1c,
4257443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4258b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
42591a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4260d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4261f3645652SVivien Didelot 		.pvt = true,
4262b3e05aa1SVivien Didelot 		.multi_chip = true,
4263e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
42641a3b39ecSAndrew Lunn 		.ops = &mv88e6190_ops,
42651a3b39ecSAndrew Lunn 	},
42661a3b39ecSAndrew Lunn 
42671a3b39ecSAndrew Lunn 	[MV88E6190X] = {
4268107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X,
42691a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
42701a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190X",
42711a3b39ecSAndrew Lunn 		.num_databases = 4096,
42721a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
4273bc393155SAndrew Lunn 		.num_internal_phys = 11,
4274a73ccd61SBrandon Streiff 		.num_gpio = 16,
4275931d1822SVivien Didelot 		.max_vid = 8191,
42761a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
42779255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
42781a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
42799069c13aSVivien Didelot 		.global2_addr = 0x1c,
4280b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
42811a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4282d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4283e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4284f3645652SVivien Didelot 		.pvt = true,
4285b3e05aa1SVivien Didelot 		.multi_chip = true,
4286443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
42871a3b39ecSAndrew Lunn 		.ops = &mv88e6190x_ops,
42881a3b39ecSAndrew Lunn 	},
42891a3b39ecSAndrew Lunn 
42901a3b39ecSAndrew Lunn 	[MV88E6191] = {
4291107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191,
42921a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
42931a3b39ecSAndrew Lunn 		.name = "Marvell 88E6191",
42941a3b39ecSAndrew Lunn 		.num_databases = 4096,
42951a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
4296bc393155SAndrew Lunn 		.num_internal_phys = 11,
4297931d1822SVivien Didelot 		.max_vid = 8191,
42981a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
42999255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
43001a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
43019069c13aSVivien Didelot 		.global2_addr = 0x1c,
4302b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
4303443d5a1bSAndrew Lunn 		.g1_irqs = 9,
4304d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4305e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4306f3645652SVivien Didelot 		.pvt = true,
4307b3e05aa1SVivien Didelot 		.multi_chip = true,
4308443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
43092fa8d3afSBrandon Streiff 		.ptp_support = true,
43102cf4cefbSVivien Didelot 		.ops = &mv88e6191_ops,
43111a3b39ecSAndrew Lunn 	},
43121a3b39ecSAndrew Lunn 
4313fad09c73SVivien Didelot 	[MV88E6240] = {
4314107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240,
4315fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4316fad09c73SVivien Didelot 		.name = "Marvell 88E6240",
4317fad09c73SVivien Didelot 		.num_databases = 4096,
4318fad09c73SVivien Didelot 		.num_ports = 7,
4319bc393155SAndrew Lunn 		.num_internal_phys = 5,
4320a73ccd61SBrandon Streiff 		.num_gpio = 15,
43213cf3c846SVivien Didelot 		.max_vid = 4095,
4322fad09c73SVivien Didelot 		.port_base_addr = 0x10,
43239255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4324a935c052SVivien Didelot 		.global1_addr = 0x1b,
43259069c13aSVivien Didelot 		.global2_addr = 0x1c,
4326acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4327dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4328d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4329e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4330f3645652SVivien Didelot 		.pvt = true,
4331b3e05aa1SVivien Didelot 		.multi_chip = true,
4332443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
43332fa8d3afSBrandon Streiff 		.ptp_support = true,
4334b3469dd8SVivien Didelot 		.ops = &mv88e6240_ops,
4335fad09c73SVivien Didelot 	},
4336fad09c73SVivien Didelot 
43371a3b39ecSAndrew Lunn 	[MV88E6290] = {
4338107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
43391a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
43401a3b39ecSAndrew Lunn 		.name = "Marvell 88E6290",
43411a3b39ecSAndrew Lunn 		.num_databases = 4096,
43421a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
4343bc393155SAndrew Lunn 		.num_internal_phys = 11,
4344a73ccd61SBrandon Streiff 		.num_gpio = 16,
4345931d1822SVivien Didelot 		.max_vid = 8191,
43461a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
43479255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
43481a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
43499069c13aSVivien Didelot 		.global2_addr = 0x1c,
4350b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
43511a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4352d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4353e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4354f3645652SVivien Didelot 		.pvt = true,
4355b3e05aa1SVivien Didelot 		.multi_chip = true,
4356443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
43572fa8d3afSBrandon Streiff 		.ptp_support = true,
43581a3b39ecSAndrew Lunn 		.ops = &mv88e6290_ops,
43591a3b39ecSAndrew Lunn 	},
43601a3b39ecSAndrew Lunn 
4361fad09c73SVivien Didelot 	[MV88E6320] = {
4362107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320,
4363fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
4364fad09c73SVivien Didelot 		.name = "Marvell 88E6320",
4365fad09c73SVivien Didelot 		.num_databases = 4096,
4366fad09c73SVivien Didelot 		.num_ports = 7,
4367bc393155SAndrew Lunn 		.num_internal_phys = 5,
4368a73ccd61SBrandon Streiff 		.num_gpio = 15,
43693cf3c846SVivien Didelot 		.max_vid = 4095,
4370fad09c73SVivien Didelot 		.port_base_addr = 0x10,
43719255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4372a935c052SVivien Didelot 		.global1_addr = 0x1b,
43739069c13aSVivien Didelot 		.global2_addr = 0x1c,
4374acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4375dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4376bc393155SAndrew Lunn 		.g2_irqs = 10,
4377e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4378f3645652SVivien Didelot 		.pvt = true,
4379b3e05aa1SVivien Didelot 		.multi_chip = true,
4380443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
43812fa8d3afSBrandon Streiff 		.ptp_support = true,
4382b3469dd8SVivien Didelot 		.ops = &mv88e6320_ops,
4383fad09c73SVivien Didelot 	},
4384fad09c73SVivien Didelot 
4385fad09c73SVivien Didelot 	[MV88E6321] = {
4386107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321,
4387fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
4388fad09c73SVivien Didelot 		.name = "Marvell 88E6321",
4389fad09c73SVivien Didelot 		.num_databases = 4096,
4390fad09c73SVivien Didelot 		.num_ports = 7,
4391bc393155SAndrew Lunn 		.num_internal_phys = 5,
4392a73ccd61SBrandon Streiff 		.num_gpio = 15,
43933cf3c846SVivien Didelot 		.max_vid = 4095,
4394fad09c73SVivien Didelot 		.port_base_addr = 0x10,
43959255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4396a935c052SVivien Didelot 		.global1_addr = 0x1b,
43979069c13aSVivien Didelot 		.global2_addr = 0x1c,
4398acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4399dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4400bc393155SAndrew Lunn 		.g2_irqs = 10,
4401e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4402b3e05aa1SVivien Didelot 		.multi_chip = true,
4403443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
44042fa8d3afSBrandon Streiff 		.ptp_support = true,
4405b3469dd8SVivien Didelot 		.ops = &mv88e6321_ops,
4406fad09c73SVivien Didelot 	},
4407fad09c73SVivien Didelot 
4408a75961d0SGregory CLEMENT 	[MV88E6341] = {
4409107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
4410a75961d0SGregory CLEMENT 		.family = MV88E6XXX_FAMILY_6341,
4411a75961d0SGregory CLEMENT 		.name = "Marvell 88E6341",
4412a75961d0SGregory CLEMENT 		.num_databases = 4096,
4413bc393155SAndrew Lunn 		.num_internal_phys = 5,
4414a75961d0SGregory CLEMENT 		.num_ports = 6,
4415a73ccd61SBrandon Streiff 		.num_gpio = 11,
44163cf3c846SVivien Didelot 		.max_vid = 4095,
4417a75961d0SGregory CLEMENT 		.port_base_addr = 0x10,
44189255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
4419a75961d0SGregory CLEMENT 		.global1_addr = 0x1b,
44209069c13aSVivien Didelot 		.global2_addr = 0x1c,
4421a75961d0SGregory CLEMENT 		.age_time_coeff = 3750,
4422e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4423adfccf11SAndrew Lunn 		.g1_irqs = 9,
4424d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4425f3645652SVivien Didelot 		.pvt = true,
4426b3e05aa1SVivien Didelot 		.multi_chip = true,
4427a75961d0SGregory CLEMENT 		.tag_protocol = DSA_TAG_PROTO_EDSA,
44282fa8d3afSBrandon Streiff 		.ptp_support = true,
4429a75961d0SGregory CLEMENT 		.ops = &mv88e6341_ops,
4430a75961d0SGregory CLEMENT 	},
4431a75961d0SGregory CLEMENT 
4432fad09c73SVivien Didelot 	[MV88E6350] = {
4433107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350,
4434fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4435fad09c73SVivien Didelot 		.name = "Marvell 88E6350",
4436fad09c73SVivien Didelot 		.num_databases = 4096,
4437fad09c73SVivien Didelot 		.num_ports = 7,
4438bc393155SAndrew Lunn 		.num_internal_phys = 5,
44393cf3c846SVivien Didelot 		.max_vid = 4095,
4440fad09c73SVivien Didelot 		.port_base_addr = 0x10,
44419255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4442a935c052SVivien Didelot 		.global1_addr = 0x1b,
44439069c13aSVivien Didelot 		.global2_addr = 0x1c,
4444acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4445dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4446d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4447e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4448f3645652SVivien Didelot 		.pvt = true,
4449b3e05aa1SVivien Didelot 		.multi_chip = true,
4450443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4451b3469dd8SVivien Didelot 		.ops = &mv88e6350_ops,
4452fad09c73SVivien Didelot 	},
4453fad09c73SVivien Didelot 
4454fad09c73SVivien Didelot 	[MV88E6351] = {
4455107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351,
4456fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4457fad09c73SVivien Didelot 		.name = "Marvell 88E6351",
4458fad09c73SVivien Didelot 		.num_databases = 4096,
4459fad09c73SVivien Didelot 		.num_ports = 7,
4460bc393155SAndrew Lunn 		.num_internal_phys = 5,
44613cf3c846SVivien Didelot 		.max_vid = 4095,
4462fad09c73SVivien Didelot 		.port_base_addr = 0x10,
44639255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4464a935c052SVivien Didelot 		.global1_addr = 0x1b,
44659069c13aSVivien Didelot 		.global2_addr = 0x1c,
4466acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4467dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4468d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4469e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4470f3645652SVivien Didelot 		.pvt = true,
4471b3e05aa1SVivien Didelot 		.multi_chip = true,
4472443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4473b3469dd8SVivien Didelot 		.ops = &mv88e6351_ops,
4474fad09c73SVivien Didelot 	},
4475fad09c73SVivien Didelot 
4476fad09c73SVivien Didelot 	[MV88E6352] = {
4477107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352,
4478fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4479fad09c73SVivien Didelot 		.name = "Marvell 88E6352",
4480fad09c73SVivien Didelot 		.num_databases = 4096,
4481fad09c73SVivien Didelot 		.num_ports = 7,
4482bc393155SAndrew Lunn 		.num_internal_phys = 5,
4483a73ccd61SBrandon Streiff 		.num_gpio = 15,
44843cf3c846SVivien Didelot 		.max_vid = 4095,
4485fad09c73SVivien Didelot 		.port_base_addr = 0x10,
44869255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4487a935c052SVivien Didelot 		.global1_addr = 0x1b,
44889069c13aSVivien Didelot 		.global2_addr = 0x1c,
4489acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4490dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4491d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4492e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4493f3645652SVivien Didelot 		.pvt = true,
4494b3e05aa1SVivien Didelot 		.multi_chip = true,
4495443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
44962fa8d3afSBrandon Streiff 		.ptp_support = true,
4497b3469dd8SVivien Didelot 		.ops = &mv88e6352_ops,
4498fad09c73SVivien Didelot 	},
44991a3b39ecSAndrew Lunn 	[MV88E6390] = {
4500107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
45011a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
45021a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390",
45031a3b39ecSAndrew Lunn 		.num_databases = 4096,
45041a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
4505bc393155SAndrew Lunn 		.num_internal_phys = 11,
4506a73ccd61SBrandon Streiff 		.num_gpio = 16,
4507931d1822SVivien Didelot 		.max_vid = 8191,
45081a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
45099255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
45101a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
45119069c13aSVivien Didelot 		.global2_addr = 0x1c,
4512b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
45131a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4514d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4515e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4516f3645652SVivien Didelot 		.pvt = true,
4517b3e05aa1SVivien Didelot 		.multi_chip = true,
4518443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
45192fa8d3afSBrandon Streiff 		.ptp_support = true,
45201a3b39ecSAndrew Lunn 		.ops = &mv88e6390_ops,
45211a3b39ecSAndrew Lunn 	},
45221a3b39ecSAndrew Lunn 	[MV88E6390X] = {
4523107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X,
45241a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
45251a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390X",
45261a3b39ecSAndrew Lunn 		.num_databases = 4096,
45271a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
4528bc393155SAndrew Lunn 		.num_internal_phys = 11,
4529a73ccd61SBrandon Streiff 		.num_gpio = 16,
4530931d1822SVivien Didelot 		.max_vid = 8191,
45311a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
45329255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
45331a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
45349069c13aSVivien Didelot 		.global2_addr = 0x1c,
4535b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
45361a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4537d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4538e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4539f3645652SVivien Didelot 		.pvt = true,
4540b3e05aa1SVivien Didelot 		.multi_chip = true,
4541443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
45422fa8d3afSBrandon Streiff 		.ptp_support = true,
45431a3b39ecSAndrew Lunn 		.ops = &mv88e6390x_ops,
45441a3b39ecSAndrew Lunn 	},
4545fad09c73SVivien Didelot };
4546fad09c73SVivien Didelot 
4547fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
4548fad09c73SVivien Didelot {
4549fad09c73SVivien Didelot 	int i;
4550fad09c73SVivien Didelot 
4551fad09c73SVivien Didelot 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
4552fad09c73SVivien Didelot 		if (mv88e6xxx_table[i].prod_num == prod_num)
4553fad09c73SVivien Didelot 			return &mv88e6xxx_table[i];
4554fad09c73SVivien Didelot 
4555fad09c73SVivien Didelot 	return NULL;
4556fad09c73SVivien Didelot }
4557fad09c73SVivien Didelot 
4558fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
4559fad09c73SVivien Didelot {
4560fad09c73SVivien Didelot 	const struct mv88e6xxx_info *info;
45618f6345b2SVivien Didelot 	unsigned int prod_num, rev;
45628f6345b2SVivien Didelot 	u16 id;
45638f6345b2SVivien Didelot 	int err;
4564fad09c73SVivien Didelot 
45658f6345b2SVivien Didelot 	mutex_lock(&chip->reg_lock);
4566107fcc10SVivien Didelot 	err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
45678f6345b2SVivien Didelot 	mutex_unlock(&chip->reg_lock);
45688f6345b2SVivien Didelot 	if (err)
45698f6345b2SVivien Didelot 		return err;
4570fad09c73SVivien Didelot 
4571107fcc10SVivien Didelot 	prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK;
4572107fcc10SVivien Didelot 	rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK;
4573fad09c73SVivien Didelot 
4574fad09c73SVivien Didelot 	info = mv88e6xxx_lookup_info(prod_num);
4575fad09c73SVivien Didelot 	if (!info)
4576fad09c73SVivien Didelot 		return -ENODEV;
4577fad09c73SVivien Didelot 
4578fad09c73SVivien Didelot 	/* Update the compatible info with the probed one */
4579fad09c73SVivien Didelot 	chip->info = info;
4580fad09c73SVivien Didelot 
4581ca070c10SVivien Didelot 	err = mv88e6xxx_g2_require(chip);
4582ca070c10SVivien Didelot 	if (err)
4583ca070c10SVivien Didelot 		return err;
4584ca070c10SVivien Didelot 
4585fad09c73SVivien Didelot 	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
4586fad09c73SVivien Didelot 		 chip->info->prod_num, chip->info->name, rev);
4587fad09c73SVivien Didelot 
4588fad09c73SVivien Didelot 	return 0;
4589fad09c73SVivien Didelot }
4590fad09c73SVivien Didelot 
4591fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
4592fad09c73SVivien Didelot {
4593fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
4594fad09c73SVivien Didelot 
4595fad09c73SVivien Didelot 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
4596fad09c73SVivien Didelot 	if (!chip)
4597fad09c73SVivien Didelot 		return NULL;
4598fad09c73SVivien Didelot 
4599fad09c73SVivien Didelot 	chip->dev = dev;
4600fad09c73SVivien Didelot 
4601fad09c73SVivien Didelot 	mutex_init(&chip->reg_lock);
4602a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&chip->mdios);
4603fad09c73SVivien Didelot 
4604fad09c73SVivien Didelot 	return chip;
4605fad09c73SVivien Didelot }
4606fad09c73SVivien Didelot 
4607fad09c73SVivien Didelot static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
4608fad09c73SVivien Didelot 			      struct mii_bus *bus, int sw_addr)
4609fad09c73SVivien Didelot {
4610fad09c73SVivien Didelot 	if (sw_addr == 0)
4611fad09c73SVivien Didelot 		chip->smi_ops = &mv88e6xxx_smi_single_chip_ops;
4612b3e05aa1SVivien Didelot 	else if (chip->info->multi_chip)
4613fad09c73SVivien Didelot 		chip->smi_ops = &mv88e6xxx_smi_multi_chip_ops;
4614fad09c73SVivien Didelot 	else
4615fad09c73SVivien Didelot 		return -EINVAL;
4616fad09c73SVivien Didelot 
4617fad09c73SVivien Didelot 	chip->bus = bus;
4618fad09c73SVivien Didelot 	chip->sw_addr = sw_addr;
4619fad09c73SVivien Didelot 
4620fad09c73SVivien Didelot 	return 0;
4621fad09c73SVivien Didelot }
4622fad09c73SVivien Didelot 
4623ed8fe202SHeiner Kallweit static void mv88e6xxx_ports_cmode_init(struct mv88e6xxx_chip *chip)
4624ed8fe202SHeiner Kallweit {
4625ed8fe202SHeiner Kallweit 	int i;
4626ed8fe202SHeiner Kallweit 
4627ed8fe202SHeiner Kallweit 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
4628ed8fe202SHeiner Kallweit 		chip->ports[i].cmode = MV88E6XXX_PORT_STS_CMODE_INVALID;
4629ed8fe202SHeiner Kallweit }
4630ed8fe202SHeiner Kallweit 
46315ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
46325ed4e3ebSFlorian Fainelli 							int port)
46337b314362SAndrew Lunn {
463404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
46352bbb33beSAndrew Lunn 
4636443d5a1bSAndrew Lunn 	return chip->info->tag_protocol;
46377b314362SAndrew Lunn }
46387b314362SAndrew Lunn 
46392a93c1a3SFlorian Fainelli #if IS_ENABLED(CONFIG_NET_DSA_LEGACY)
4640fad09c73SVivien Didelot static const char *mv88e6xxx_drv_probe(struct device *dsa_dev,
4641fad09c73SVivien Didelot 				       struct device *host_dev, int sw_addr,
4642fad09c73SVivien Didelot 				       void **priv)
4643fad09c73SVivien Didelot {
4644fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
4645fad09c73SVivien Didelot 	struct mii_bus *bus;
4646fad09c73SVivien Didelot 	int err;
4647fad09c73SVivien Didelot 
4648fad09c73SVivien Didelot 	bus = dsa_host_dev_to_mii_bus(host_dev);
4649fad09c73SVivien Didelot 	if (!bus)
4650fad09c73SVivien Didelot 		return NULL;
4651fad09c73SVivien Didelot 
4652fad09c73SVivien Didelot 	chip = mv88e6xxx_alloc_chip(dsa_dev);
4653fad09c73SVivien Didelot 	if (!chip)
4654fad09c73SVivien Didelot 		return NULL;
4655fad09c73SVivien Didelot 
4656fad09c73SVivien Didelot 	/* Legacy SMI probing will only support chips similar to 88E6085 */
4657fad09c73SVivien Didelot 	chip->info = &mv88e6xxx_table[MV88E6085];
4658fad09c73SVivien Didelot 
4659fad09c73SVivien Didelot 	err = mv88e6xxx_smi_init(chip, bus, sw_addr);
4660fad09c73SVivien Didelot 	if (err)
4661fad09c73SVivien Didelot 		goto free;
4662fad09c73SVivien Didelot 
4663fad09c73SVivien Didelot 	err = mv88e6xxx_detect(chip);
4664fad09c73SVivien Didelot 	if (err)
4665fad09c73SVivien Didelot 		goto free;
4666fad09c73SVivien Didelot 
4667ed8fe202SHeiner Kallweit 	mv88e6xxx_ports_cmode_init(chip);
4668ed8fe202SHeiner Kallweit 
4669dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
4670dc30c35bSAndrew Lunn 	err = mv88e6xxx_switch_reset(chip);
4671dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
4672dc30c35bSAndrew Lunn 	if (err)
4673dc30c35bSAndrew Lunn 		goto free;
4674dc30c35bSAndrew Lunn 
4675e57e5e77SVivien Didelot 	mv88e6xxx_phy_init(chip);
4676e57e5e77SVivien Didelot 
4677a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdios_register(chip, NULL);
4678fad09c73SVivien Didelot 	if (err)
4679fad09c73SVivien Didelot 		goto free;
4680fad09c73SVivien Didelot 
4681fad09c73SVivien Didelot 	*priv = chip;
4682fad09c73SVivien Didelot 
4683fad09c73SVivien Didelot 	return chip->info->name;
4684fad09c73SVivien Didelot free:
4685fad09c73SVivien Didelot 	devm_kfree(dsa_dev, chip);
4686fad09c73SVivien Didelot 
4687fad09c73SVivien Didelot 	return NULL;
4688fad09c73SVivien Didelot }
46892a93c1a3SFlorian Fainelli #endif
4690fad09c73SVivien Didelot 
46917df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port,
46923709aadcSVivien Didelot 				      const struct switchdev_obj_port_mdb *mdb)
46937df8fbddSVivien Didelot {
46947df8fbddSVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
46957df8fbddSVivien Didelot 	 * so skip the prepare phase.
46967df8fbddSVivien Didelot 	 */
46977df8fbddSVivien Didelot 
46987df8fbddSVivien Didelot 	return 0;
46997df8fbddSVivien Didelot }
47007df8fbddSVivien Didelot 
47017df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
47023709aadcSVivien Didelot 				   const struct switchdev_obj_port_mdb *mdb)
47037df8fbddSVivien Didelot {
470404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
47057df8fbddSVivien Didelot 
47067df8fbddSVivien Didelot 	mutex_lock(&chip->reg_lock);
47077df8fbddSVivien Didelot 	if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
470827c0e600SVivien Didelot 					 MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC))
4709774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to load multicast MAC address\n",
4710774439e5SVivien Didelot 			port);
47117df8fbddSVivien Didelot 	mutex_unlock(&chip->reg_lock);
47127df8fbddSVivien Didelot }
47137df8fbddSVivien Didelot 
47147df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
47157df8fbddSVivien Didelot 				  const struct switchdev_obj_port_mdb *mdb)
47167df8fbddSVivien Didelot {
471704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
47187df8fbddSVivien Didelot 	int err;
47197df8fbddSVivien Didelot 
47207df8fbddSVivien Didelot 	mutex_lock(&chip->reg_lock);
47217df8fbddSVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
472227c0e600SVivien Didelot 					   MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
47237df8fbddSVivien Didelot 	mutex_unlock(&chip->reg_lock);
47247df8fbddSVivien Didelot 
47257df8fbddSVivien Didelot 	return err;
47267df8fbddSVivien Didelot }
47277df8fbddSVivien Didelot 
47284f85901fSRussell King static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
47294f85901fSRussell King 					 bool unicast, bool multicast)
47304f85901fSRussell King {
47314f85901fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
47324f85901fSRussell King 	int err = -EOPNOTSUPP;
47334f85901fSRussell King 
47344f85901fSRussell King 	mutex_lock(&chip->reg_lock);
47354f85901fSRussell King 	if (chip->info->ops->port_set_egress_floods)
47364f85901fSRussell King 		err = chip->info->ops->port_set_egress_floods(chip, port,
47374f85901fSRussell King 							      unicast,
47384f85901fSRussell King 							      multicast);
47394f85901fSRussell King 	mutex_unlock(&chip->reg_lock);
47404f85901fSRussell King 
47414f85901fSRussell King 	return err;
47424f85901fSRussell King }
47434f85901fSRussell King 
4744a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
47452a93c1a3SFlorian Fainelli #if IS_ENABLED(CONFIG_NET_DSA_LEGACY)
4746fad09c73SVivien Didelot 	.probe			= mv88e6xxx_drv_probe,
47472a93c1a3SFlorian Fainelli #endif
47487b314362SAndrew Lunn 	.get_tag_protocol	= mv88e6xxx_get_tag_protocol,
4749fad09c73SVivien Didelot 	.setup			= mv88e6xxx_setup,
4750fad09c73SVivien Didelot 	.adjust_link		= mv88e6xxx_adjust_link,
4751c9a2356fSRussell King 	.phylink_validate	= mv88e6xxx_validate,
4752c9a2356fSRussell King 	.phylink_mac_link_state	= mv88e6xxx_link_state,
4753c9a2356fSRussell King 	.phylink_mac_config	= mv88e6xxx_mac_config,
4754c9a2356fSRussell King 	.phylink_mac_link_down	= mv88e6xxx_mac_link_down,
4755c9a2356fSRussell King 	.phylink_mac_link_up	= mv88e6xxx_mac_link_up,
4756fad09c73SVivien Didelot 	.get_strings		= mv88e6xxx_get_strings,
4757fad09c73SVivien Didelot 	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
4758fad09c73SVivien Didelot 	.get_sset_count		= mv88e6xxx_get_sset_count,
475904aca993SAndrew Lunn 	.port_enable		= mv88e6xxx_port_enable,
476004aca993SAndrew Lunn 	.port_disable		= mv88e6xxx_port_disable,
476108f50061SVivien Didelot 	.get_mac_eee		= mv88e6xxx_get_mac_eee,
476208f50061SVivien Didelot 	.set_mac_eee		= mv88e6xxx_set_mac_eee,
4763fad09c73SVivien Didelot 	.get_eeprom_len		= mv88e6xxx_get_eeprom_len,
4764fad09c73SVivien Didelot 	.get_eeprom		= mv88e6xxx_get_eeprom,
4765fad09c73SVivien Didelot 	.set_eeprom		= mv88e6xxx_set_eeprom,
4766fad09c73SVivien Didelot 	.get_regs_len		= mv88e6xxx_get_regs_len,
4767fad09c73SVivien Didelot 	.get_regs		= mv88e6xxx_get_regs,
47682cfcd964SVivien Didelot 	.set_ageing_time	= mv88e6xxx_set_ageing_time,
4769fad09c73SVivien Didelot 	.port_bridge_join	= mv88e6xxx_port_bridge_join,
4770fad09c73SVivien Didelot 	.port_bridge_leave	= mv88e6xxx_port_bridge_leave,
47714f85901fSRussell King 	.port_egress_floods	= mv88e6xxx_port_egress_floods,
4772fad09c73SVivien Didelot 	.port_stp_state_set	= mv88e6xxx_port_stp_state_set,
4773749efcb8SVivien Didelot 	.port_fast_age		= mv88e6xxx_port_fast_age,
4774fad09c73SVivien Didelot 	.port_vlan_filtering	= mv88e6xxx_port_vlan_filtering,
4775fad09c73SVivien Didelot 	.port_vlan_prepare	= mv88e6xxx_port_vlan_prepare,
4776fad09c73SVivien Didelot 	.port_vlan_add		= mv88e6xxx_port_vlan_add,
4777fad09c73SVivien Didelot 	.port_vlan_del		= mv88e6xxx_port_vlan_del,
4778fad09c73SVivien Didelot 	.port_fdb_add           = mv88e6xxx_port_fdb_add,
4779fad09c73SVivien Didelot 	.port_fdb_del           = mv88e6xxx_port_fdb_del,
4780fad09c73SVivien Didelot 	.port_fdb_dump          = mv88e6xxx_port_fdb_dump,
47817df8fbddSVivien Didelot 	.port_mdb_prepare       = mv88e6xxx_port_mdb_prepare,
47827df8fbddSVivien Didelot 	.port_mdb_add           = mv88e6xxx_port_mdb_add,
47837df8fbddSVivien Didelot 	.port_mdb_del           = mv88e6xxx_port_mdb_del,
4784aec5ac88SVivien Didelot 	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
4785aec5ac88SVivien Didelot 	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
4786c6fe0ad2SBrandon Streiff 	.port_hwtstamp_set	= mv88e6xxx_port_hwtstamp_set,
4787c6fe0ad2SBrandon Streiff 	.port_hwtstamp_get	= mv88e6xxx_port_hwtstamp_get,
4788c6fe0ad2SBrandon Streiff 	.port_txtstamp		= mv88e6xxx_port_txtstamp,
4789c6fe0ad2SBrandon Streiff 	.port_rxtstamp		= mv88e6xxx_port_rxtstamp,
4790c6fe0ad2SBrandon Streiff 	.get_ts_info		= mv88e6xxx_get_ts_info,
4791fad09c73SVivien Didelot };
4792fad09c73SVivien Didelot 
4793ab3d408dSFlorian Fainelli static struct dsa_switch_driver mv88e6xxx_switch_drv = {
4794ab3d408dSFlorian Fainelli 	.ops			= &mv88e6xxx_switch_ops,
4795ab3d408dSFlorian Fainelli };
4796ab3d408dSFlorian Fainelli 
479755ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
4798fad09c73SVivien Didelot {
4799fad09c73SVivien Didelot 	struct device *dev = chip->dev;
4800fad09c73SVivien Didelot 	struct dsa_switch *ds;
4801fad09c73SVivien Didelot 
480273b1204dSVivien Didelot 	ds = dsa_switch_alloc(dev, mv88e6xxx_num_ports(chip));
4803fad09c73SVivien Didelot 	if (!ds)
4804fad09c73SVivien Didelot 		return -ENOMEM;
4805fad09c73SVivien Didelot 
4806fad09c73SVivien Didelot 	ds->priv = chip;
4807877b7cb0SAndrew Lunn 	ds->dev = dev;
48089d490b4eSVivien Didelot 	ds->ops = &mv88e6xxx_switch_ops;
48099ff74f24SVivien Didelot 	ds->ageing_time_min = chip->info->age_time_coeff;
48109ff74f24SVivien Didelot 	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
4811fad09c73SVivien Didelot 
4812fad09c73SVivien Didelot 	dev_set_drvdata(dev, ds);
4813fad09c73SVivien Didelot 
481423c9ee49SVivien Didelot 	return dsa_register_switch(ds);
4815fad09c73SVivien Didelot }
4816fad09c73SVivien Didelot 
4817fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
4818fad09c73SVivien Didelot {
4819fad09c73SVivien Didelot 	dsa_unregister_switch(chip->ds);
4820fad09c73SVivien Didelot }
4821fad09c73SVivien Didelot 
4822877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev)
4823877b7cb0SAndrew Lunn {
4824877b7cb0SAndrew Lunn 	const struct of_device_id *matches = dev->driver->of_match_table;
4825877b7cb0SAndrew Lunn 	const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data;
4826877b7cb0SAndrew Lunn 
4827877b7cb0SAndrew Lunn 	for (; matches->name[0] || matches->type[0] || matches->compatible[0];
4828877b7cb0SAndrew Lunn 	     matches++) {
4829877b7cb0SAndrew Lunn 		if (!strcmp(pdata->compatible, matches->compatible))
4830877b7cb0SAndrew Lunn 			return matches->data;
4831877b7cb0SAndrew Lunn 	}
4832877b7cb0SAndrew Lunn 	return NULL;
4833877b7cb0SAndrew Lunn }
4834877b7cb0SAndrew Lunn 
4835bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration
4836bcd3d9d9SMiquel Raynal  * would be lost after a power cycle so prevent it to be suspended.
4837bcd3d9d9SMiquel Raynal  */
4838bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev)
4839bcd3d9d9SMiquel Raynal {
4840bcd3d9d9SMiquel Raynal 	return -EOPNOTSUPP;
4841bcd3d9d9SMiquel Raynal }
4842bcd3d9d9SMiquel Raynal 
4843bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev)
4844bcd3d9d9SMiquel Raynal {
4845bcd3d9d9SMiquel Raynal 	return 0;
4846bcd3d9d9SMiquel Raynal }
4847bcd3d9d9SMiquel Raynal 
4848bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume);
4849bcd3d9d9SMiquel Raynal 
4850fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev)
4851fad09c73SVivien Didelot {
4852877b7cb0SAndrew Lunn 	struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data;
48537ddae24fSDavid S. Miller 	const struct mv88e6xxx_info *compat_info = NULL;
4854fad09c73SVivien Didelot 	struct device *dev = &mdiodev->dev;
4855fad09c73SVivien Didelot 	struct device_node *np = dev->of_node;
4856fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
4857877b7cb0SAndrew Lunn 	int port;
4858fad09c73SVivien Didelot 	int err;
4859fad09c73SVivien Didelot 
48607bb8c996SAndrew Lunn 	if (!np && !pdata)
48617bb8c996SAndrew Lunn 		return -EINVAL;
48627bb8c996SAndrew Lunn 
4863877b7cb0SAndrew Lunn 	if (np)
4864fad09c73SVivien Didelot 		compat_info = of_device_get_match_data(dev);
4865877b7cb0SAndrew Lunn 
4866877b7cb0SAndrew Lunn 	if (pdata) {
4867877b7cb0SAndrew Lunn 		compat_info = pdata_device_get_match_data(dev);
4868877b7cb0SAndrew Lunn 
4869877b7cb0SAndrew Lunn 		if (!pdata->netdev)
4870877b7cb0SAndrew Lunn 			return -EINVAL;
4871877b7cb0SAndrew Lunn 
4872877b7cb0SAndrew Lunn 		for (port = 0; port < DSA_MAX_PORTS; port++) {
4873877b7cb0SAndrew Lunn 			if (!(pdata->enabled_ports & (1 << port)))
4874877b7cb0SAndrew Lunn 				continue;
4875877b7cb0SAndrew Lunn 			if (strcmp(pdata->cd.port_names[port], "cpu"))
4876877b7cb0SAndrew Lunn 				continue;
4877877b7cb0SAndrew Lunn 			pdata->cd.netdev[port] = &pdata->netdev->dev;
4878877b7cb0SAndrew Lunn 			break;
4879877b7cb0SAndrew Lunn 		}
4880877b7cb0SAndrew Lunn 	}
4881877b7cb0SAndrew Lunn 
4882fad09c73SVivien Didelot 	if (!compat_info)
4883fad09c73SVivien Didelot 		return -EINVAL;
4884fad09c73SVivien Didelot 
4885fad09c73SVivien Didelot 	chip = mv88e6xxx_alloc_chip(dev);
4886877b7cb0SAndrew Lunn 	if (!chip) {
4887877b7cb0SAndrew Lunn 		err = -ENOMEM;
4888877b7cb0SAndrew Lunn 		goto out;
4889877b7cb0SAndrew Lunn 	}
4890fad09c73SVivien Didelot 
4891fad09c73SVivien Didelot 	chip->info = compat_info;
4892fad09c73SVivien Didelot 
4893fad09c73SVivien Didelot 	err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
4894fad09c73SVivien Didelot 	if (err)
4895877b7cb0SAndrew Lunn 		goto out;
4896fad09c73SVivien Didelot 
4897b4308f04SAndrew Lunn 	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
4898877b7cb0SAndrew Lunn 	if (IS_ERR(chip->reset)) {
4899877b7cb0SAndrew Lunn 		err = PTR_ERR(chip->reset);
4900877b7cb0SAndrew Lunn 		goto out;
4901877b7cb0SAndrew Lunn 	}
4902b4308f04SAndrew Lunn 
4903fad09c73SVivien Didelot 	err = mv88e6xxx_detect(chip);
4904fad09c73SVivien Didelot 	if (err)
4905877b7cb0SAndrew Lunn 		goto out;
4906fad09c73SVivien Didelot 
4907e57e5e77SVivien Didelot 	mv88e6xxx_phy_init(chip);
4908e57e5e77SVivien Didelot 
490900baabe5SAndrew Lunn 	if (chip->info->ops->get_eeprom) {
491000baabe5SAndrew Lunn 		if (np)
491100baabe5SAndrew Lunn 			of_property_read_u32(np, "eeprom-length",
491200baabe5SAndrew Lunn 					     &chip->eeprom_len);
491300baabe5SAndrew Lunn 		else
491400baabe5SAndrew Lunn 			chip->eeprom_len = pdata->eeprom_len;
491500baabe5SAndrew Lunn 	}
4916fad09c73SVivien Didelot 
4917dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
4918dc30c35bSAndrew Lunn 	err = mv88e6xxx_switch_reset(chip);
4919dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
4920fad09c73SVivien Didelot 	if (err)
4921dc30c35bSAndrew Lunn 		goto out;
4922fad09c73SVivien Didelot 
4923dc30c35bSAndrew Lunn 	chip->irq = of_irq_get(np, 0);
4924dc30c35bSAndrew Lunn 	if (chip->irq == -EPROBE_DEFER) {
4925dc30c35bSAndrew Lunn 		err = chip->irq;
4926dc30c35bSAndrew Lunn 		goto out;
4927fad09c73SVivien Didelot 	}
4928fad09c73SVivien Didelot 
4929294d711eSAndrew Lunn 	/* Has to be performed before the MDIO bus is created, because
4930a708767eSUwe Kleine-König 	 * the PHYs will link their interrupts to these interrupt
4931294d711eSAndrew Lunn 	 * controllers
4932dc30c35bSAndrew Lunn 	 */
4933dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
4934294d711eSAndrew Lunn 	if (chip->irq > 0)
4935dc30c35bSAndrew Lunn 		err = mv88e6xxx_g1_irq_setup(chip);
4936294d711eSAndrew Lunn 	else
4937294d711eSAndrew Lunn 		err = mv88e6xxx_irq_poll_setup(chip);
4938dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
4939dc30c35bSAndrew Lunn 
4940dc30c35bSAndrew Lunn 	if (err)
4941dc30c35bSAndrew Lunn 		goto out;
4942dc30c35bSAndrew Lunn 
4943d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0) {
4944dc30c35bSAndrew Lunn 		err = mv88e6xxx_g2_irq_setup(chip);
4945dc30c35bSAndrew Lunn 		if (err)
4946dc30c35bSAndrew Lunn 			goto out_g1_irq;
4947dc30c35bSAndrew Lunn 	}
49480977644cSAndrew Lunn 
49490977644cSAndrew Lunn 	err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
49500977644cSAndrew Lunn 	if (err)
49510977644cSAndrew Lunn 		goto out_g2_irq;
495262eb1162SAndrew Lunn 
495362eb1162SAndrew Lunn 	err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
495462eb1162SAndrew Lunn 	if (err)
495562eb1162SAndrew Lunn 		goto out_g1_atu_prob_irq;
4956dc30c35bSAndrew Lunn 
4957a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdios_register(chip, np);
4958dc30c35bSAndrew Lunn 	if (err)
495962eb1162SAndrew Lunn 		goto out_g1_vtu_prob_irq;
4960dc30c35bSAndrew Lunn 
496155ed0ce0SFlorian Fainelli 	err = mv88e6xxx_register_switch(chip);
4962dc30c35bSAndrew Lunn 	if (err)
4963dc30c35bSAndrew Lunn 		goto out_mdio;
4964dc30c35bSAndrew Lunn 
4965fad09c73SVivien Didelot 	return 0;
4966dc30c35bSAndrew Lunn 
4967dc30c35bSAndrew Lunn out_mdio:
4968a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
496962eb1162SAndrew Lunn out_g1_vtu_prob_irq:
497062eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
49710977644cSAndrew Lunn out_g1_atu_prob_irq:
49720977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
4973dc30c35bSAndrew Lunn out_g2_irq:
4974294d711eSAndrew Lunn 	if (chip->info->g2_irqs > 0)
4975dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
4976dc30c35bSAndrew Lunn out_g1_irq:
4977294d711eSAndrew Lunn 	if (chip->irq > 0)
4978dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
4979294d711eSAndrew Lunn 	else
4980294d711eSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
4981dc30c35bSAndrew Lunn out:
4982877b7cb0SAndrew Lunn 	if (pdata)
4983877b7cb0SAndrew Lunn 		dev_put(pdata->netdev);
4984877b7cb0SAndrew Lunn 
4985dc30c35bSAndrew Lunn 	return err;
4986fad09c73SVivien Didelot }
4987fad09c73SVivien Didelot 
4988fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev)
4989fad09c73SVivien Didelot {
4990fad09c73SVivien Didelot 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
499104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
4992fad09c73SVivien Didelot 
4993c6fe0ad2SBrandon Streiff 	if (chip->info->ptp_support) {
4994c6fe0ad2SBrandon Streiff 		mv88e6xxx_hwtstamp_free(chip);
49952fa8d3afSBrandon Streiff 		mv88e6xxx_ptp_free(chip);
4996c6fe0ad2SBrandon Streiff 	}
49972fa8d3afSBrandon Streiff 
4998930188ceSAndrew Lunn 	mv88e6xxx_phy_destroy(chip);
4999fad09c73SVivien Didelot 	mv88e6xxx_unregister_switch(chip);
5000a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
5001dc30c35bSAndrew Lunn 
500262eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
50030977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
500476f38f1fSAndrew Lunn 
5005d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0)
5006dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
500776f38f1fSAndrew Lunn 
500876f38f1fSAndrew Lunn 	if (chip->irq > 0)
5009dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
501076f38f1fSAndrew Lunn 	else
501176f38f1fSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
5012fad09c73SVivien Didelot }
5013fad09c73SVivien Didelot 
5014fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = {
5015fad09c73SVivien Didelot 	{
5016fad09c73SVivien Didelot 		.compatible = "marvell,mv88e6085",
5017fad09c73SVivien Didelot 		.data = &mv88e6xxx_table[MV88E6085],
5018fad09c73SVivien Didelot 	},
50191a3b39ecSAndrew Lunn 	{
50201a3b39ecSAndrew Lunn 		.compatible = "marvell,mv88e6190",
50211a3b39ecSAndrew Lunn 		.data = &mv88e6xxx_table[MV88E6190],
50221a3b39ecSAndrew Lunn 	},
5023fad09c73SVivien Didelot 	{ /* sentinel */ },
5024fad09c73SVivien Didelot };
5025fad09c73SVivien Didelot 
5026fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);
5027fad09c73SVivien Didelot 
5028fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = {
5029fad09c73SVivien Didelot 	.probe	= mv88e6xxx_probe,
5030fad09c73SVivien Didelot 	.remove = mv88e6xxx_remove,
5031fad09c73SVivien Didelot 	.mdiodrv.driver = {
5032fad09c73SVivien Didelot 		.name = "mv88e6085",
5033fad09c73SVivien Didelot 		.of_match_table = mv88e6xxx_of_match,
5034bcd3d9d9SMiquel Raynal 		.pm = &mv88e6xxx_pm_ops,
5035fad09c73SVivien Didelot 	},
5036fad09c73SVivien Didelot };
5037fad09c73SVivien Didelot 
5038fad09c73SVivien Didelot static int __init mv88e6xxx_init(void)
5039fad09c73SVivien Didelot {
5040ab3d408dSFlorian Fainelli 	register_switch_driver(&mv88e6xxx_switch_drv);
5041fad09c73SVivien Didelot 	return mdio_driver_register(&mv88e6xxx_driver);
5042fad09c73SVivien Didelot }
5043fad09c73SVivien Didelot module_init(mv88e6xxx_init);
5044fad09c73SVivien Didelot 
5045fad09c73SVivien Didelot static void __exit mv88e6xxx_cleanup(void)
5046fad09c73SVivien Didelot {
5047fad09c73SVivien Didelot 	mdio_driver_unregister(&mv88e6xxx_driver);
5048ab3d408dSFlorian Fainelli 	unregister_switch_driver(&mv88e6xxx_switch_drv);
5049fad09c73SVivien Didelot }
5050fad09c73SVivien Didelot module_exit(mv88e6xxx_cleanup);
5051fad09c73SVivien Didelot 
5052fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
5053fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
5054fad09c73SVivien Didelot MODULE_LICENSE("GPL");
5055