xref: /openbmc/linux/drivers/net/dsa/mv88e6xxx/chip.c (revision f6d9758b)
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 
459294d711eSAndrew Lunn 	err = request_threaded_irq(chip->irq, NULL,
460294d711eSAndrew Lunn 				   mv88e6xxx_g1_irq_thread_fn,
4610340376eSMarek Behún 				   IRQF_ONESHOT | IRQF_SHARED,
462294d711eSAndrew Lunn 				   dev_name(chip->dev), chip);
463294d711eSAndrew Lunn 	if (err)
464294d711eSAndrew Lunn 		mv88e6xxx_g1_irq_free_common(chip);
465294d711eSAndrew Lunn 
466294d711eSAndrew Lunn 	return err;
467294d711eSAndrew Lunn }
468294d711eSAndrew Lunn 
469294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work)
470294d711eSAndrew Lunn {
471294d711eSAndrew Lunn 	struct mv88e6xxx_chip *chip = container_of(work,
472294d711eSAndrew Lunn 						   struct mv88e6xxx_chip,
473294d711eSAndrew Lunn 						   irq_poll_work.work);
474294d711eSAndrew Lunn 	mv88e6xxx_g1_irq_thread_work(chip);
475294d711eSAndrew Lunn 
476294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
477294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
478294d711eSAndrew Lunn }
479294d711eSAndrew Lunn 
480294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip)
481294d711eSAndrew Lunn {
482294d711eSAndrew Lunn 	int err;
483294d711eSAndrew Lunn 
484294d711eSAndrew Lunn 	err = mv88e6xxx_g1_irq_setup_common(chip);
485294d711eSAndrew Lunn 	if (err)
486294d711eSAndrew Lunn 		return err;
487294d711eSAndrew Lunn 
488294d711eSAndrew Lunn 	kthread_init_delayed_work(&chip->irq_poll_work,
489294d711eSAndrew Lunn 				  mv88e6xxx_irq_poll);
490294d711eSAndrew Lunn 
4913f8b8696SFlorian Fainelli 	chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev));
492294d711eSAndrew Lunn 	if (IS_ERR(chip->kworker))
493294d711eSAndrew Lunn 		return PTR_ERR(chip->kworker);
494294d711eSAndrew Lunn 
495294d711eSAndrew Lunn 	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
496294d711eSAndrew Lunn 				   msecs_to_jiffies(100));
497294d711eSAndrew Lunn 
498294d711eSAndrew Lunn 	return 0;
499294d711eSAndrew Lunn }
500294d711eSAndrew Lunn 
501294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip)
502294d711eSAndrew Lunn {
503294d711eSAndrew Lunn 	kthread_cancel_delayed_work_sync(&chip->irq_poll_work);
504294d711eSAndrew Lunn 	kthread_destroy_worker(chip->kworker);
5053d82475aSUwe Kleine-König 
5063d82475aSUwe Kleine-König 	mutex_lock(&chip->reg_lock);
5073d82475aSUwe Kleine-König 	mv88e6xxx_g1_irq_free_common(chip);
5083d82475aSUwe Kleine-König 	mutex_unlock(&chip->reg_lock);
509294d711eSAndrew Lunn }
510294d711eSAndrew Lunn 
511ec561276SVivien Didelot int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask)
5122d79af6eSVivien Didelot {
5136441e669SAndrew Lunn 	int i;
5142d79af6eSVivien Didelot 
5156441e669SAndrew Lunn 	for (i = 0; i < 16; i++) {
5162d79af6eSVivien Didelot 		u16 val;
5172d79af6eSVivien Didelot 		int err;
5182d79af6eSVivien Didelot 
5192d79af6eSVivien Didelot 		err = mv88e6xxx_read(chip, addr, reg, &val);
5202d79af6eSVivien Didelot 		if (err)
5212d79af6eSVivien Didelot 			return err;
5222d79af6eSVivien Didelot 
5232d79af6eSVivien Didelot 		if (!(val & mask))
5242d79af6eSVivien Didelot 			return 0;
5252d79af6eSVivien Didelot 
5262d79af6eSVivien Didelot 		usleep_range(1000, 2000);
5272d79af6eSVivien Didelot 	}
5282d79af6eSVivien Didelot 
52930853553SAndrew Lunn 	dev_err(chip->dev, "Timeout while waiting for switch\n");
5302d79af6eSVivien Didelot 	return -ETIMEDOUT;
5312d79af6eSVivien Didelot }
5322d79af6eSVivien Didelot 
533f22ab641SVivien Didelot /* Indirect write to single pointer-data register with an Update bit */
534ec561276SVivien Didelot int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update)
535f22ab641SVivien Didelot {
536f22ab641SVivien Didelot 	u16 val;
5370f02b4f7SAndrew Lunn 	int err;
538f22ab641SVivien Didelot 
539f22ab641SVivien Didelot 	/* Wait until the previous operation is completed */
5400f02b4f7SAndrew Lunn 	err = mv88e6xxx_wait(chip, addr, reg, BIT(15));
541f22ab641SVivien Didelot 	if (err)
542f22ab641SVivien Didelot 		return err;
543f22ab641SVivien Didelot 
544f22ab641SVivien Didelot 	/* Set the Update bit to trigger a write operation */
545f22ab641SVivien Didelot 	val = BIT(15) | update;
546f22ab641SVivien Didelot 
547f22ab641SVivien Didelot 	return mv88e6xxx_write(chip, addr, reg, val);
548f22ab641SVivien Didelot }
549f22ab641SVivien Didelot 
550d78343d2SVivien Didelot static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
55154186b91SAndrew Lunn 				    int link, int speed, int duplex, int pause,
552d78343d2SVivien Didelot 				    phy_interface_t mode)
553d78343d2SVivien Didelot {
554d78343d2SVivien Didelot 	int err;
555d78343d2SVivien Didelot 
556d78343d2SVivien Didelot 	if (!chip->info->ops->port_set_link)
557d78343d2SVivien Didelot 		return 0;
558d78343d2SVivien Didelot 
559d78343d2SVivien Didelot 	/* Port's MAC control must not be changed unless the link is down */
560d78343d2SVivien Didelot 	err = chip->info->ops->port_set_link(chip, port, 0);
561d78343d2SVivien Didelot 	if (err)
562d78343d2SVivien Didelot 		return err;
563d78343d2SVivien Didelot 
564d78343d2SVivien Didelot 	if (chip->info->ops->port_set_speed) {
565d78343d2SVivien Didelot 		err = chip->info->ops->port_set_speed(chip, port, speed);
566d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
567d78343d2SVivien Didelot 			goto restore_link;
568d78343d2SVivien Didelot 	}
569d78343d2SVivien Didelot 
57054186b91SAndrew Lunn 	if (chip->info->ops->port_set_pause) {
57154186b91SAndrew Lunn 		err = chip->info->ops->port_set_pause(chip, port, pause);
57254186b91SAndrew Lunn 		if (err)
57354186b91SAndrew Lunn 			goto restore_link;
57454186b91SAndrew Lunn 	}
57554186b91SAndrew Lunn 
576d78343d2SVivien Didelot 	if (chip->info->ops->port_set_duplex) {
577d78343d2SVivien Didelot 		err = chip->info->ops->port_set_duplex(chip, port, duplex);
578d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
579d78343d2SVivien Didelot 			goto restore_link;
580d78343d2SVivien Didelot 	}
581d78343d2SVivien Didelot 
582d78343d2SVivien Didelot 	if (chip->info->ops->port_set_rgmii_delay) {
583d78343d2SVivien Didelot 		err = chip->info->ops->port_set_rgmii_delay(chip, port, mode);
584d78343d2SVivien Didelot 		if (err && err != -EOPNOTSUPP)
585d78343d2SVivien Didelot 			goto restore_link;
586d78343d2SVivien Didelot 	}
587d78343d2SVivien Didelot 
588f39908d3SAndrew Lunn 	if (chip->info->ops->port_set_cmode) {
589f39908d3SAndrew Lunn 		err = chip->info->ops->port_set_cmode(chip, port, mode);
590f39908d3SAndrew Lunn 		if (err && err != -EOPNOTSUPP)
591f39908d3SAndrew Lunn 			goto restore_link;
592f39908d3SAndrew Lunn 	}
593f39908d3SAndrew Lunn 
594d78343d2SVivien Didelot 	err = 0;
595d78343d2SVivien Didelot restore_link:
596d78343d2SVivien Didelot 	if (chip->info->ops->port_set_link(chip, port, link))
597774439e5SVivien Didelot 		dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
598d78343d2SVivien Didelot 
599d78343d2SVivien Didelot 	return err;
600d78343d2SVivien Didelot }
601d78343d2SVivien Didelot 
602d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
603d700ec41SMarek Vasut {
604d700ec41SMarek Vasut 	struct mv88e6xxx_chip *chip = ds->priv;
605d700ec41SMarek Vasut 
606d700ec41SMarek Vasut 	return port < chip->info->num_internal_phys;
607d700ec41SMarek Vasut }
608d700ec41SMarek Vasut 
609fad09c73SVivien Didelot /* We expect the switch to perform auto negotiation if there is a real
610fad09c73SVivien Didelot  * phy. However, in the case of a fixed link phy, we force the port
611fad09c73SVivien Didelot  * settings from the fixed link settings.
612fad09c73SVivien Didelot  */
613fad09c73SVivien Didelot static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
614fad09c73SVivien Didelot 				  struct phy_device *phydev)
615fad09c73SVivien Didelot {
61604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
6170e7b9925SAndrew Lunn 	int err;
618fad09c73SVivien Didelot 
619d700ec41SMarek Vasut 	if (!phy_is_pseudo_fixed_link(phydev) &&
620d700ec41SMarek Vasut 	    mv88e6xxx_phy_is_internal(ds, port))
621fad09c73SVivien Didelot 		return;
622fad09c73SVivien Didelot 
623fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
624d78343d2SVivien Didelot 	err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
62554186b91SAndrew Lunn 				       phydev->duplex, phydev->pause,
62654186b91SAndrew Lunn 				       phydev->interface);
627fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
628d78343d2SVivien Didelot 
629d78343d2SVivien Didelot 	if (err && err != -EOPNOTSUPP)
630774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
631fad09c73SVivien Didelot }
632fad09c73SVivien Didelot 
6336c422e34SRussell King static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6346c422e34SRussell King 				       unsigned long *mask,
6356c422e34SRussell King 				       struct phylink_link_state *state)
6366c422e34SRussell King {
6376c422e34SRussell King 	if (!phy_interface_mode_is_8023z(state->interface)) {
6386c422e34SRussell King 		/* 10M and 100M are only supported in non-802.3z mode */
6396c422e34SRussell King 		phylink_set(mask, 10baseT_Half);
6406c422e34SRussell King 		phylink_set(mask, 10baseT_Full);
6416c422e34SRussell King 		phylink_set(mask, 100baseT_Half);
6426c422e34SRussell King 		phylink_set(mask, 100baseT_Full);
6436c422e34SRussell King 	}
6446c422e34SRussell King }
6456c422e34SRussell King 
6466c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6476c422e34SRussell King 				       unsigned long *mask,
6486c422e34SRussell King 				       struct phylink_link_state *state)
6496c422e34SRussell King {
6506c422e34SRussell King 	/* FIXME: if the port is in 1000Base-X mode, then it only supports
6516c422e34SRussell King 	 * 1000M FD speeds.  In this case, CMODE will indicate 5.
6526c422e34SRussell King 	 */
6536c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
6546c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
6556c422e34SRussell King 
6566c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
6576c422e34SRussell King }
6586c422e34SRussell King 
6596c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6606c422e34SRussell King 				       unsigned long *mask,
6616c422e34SRussell King 				       struct phylink_link_state *state)
6626c422e34SRussell King {
6636c422e34SRussell King 	/* No ethtool bits for 200Mbps */
6646c422e34SRussell King 	phylink_set(mask, 1000baseT_Full);
6656c422e34SRussell King 	phylink_set(mask, 1000baseX_Full);
6666c422e34SRussell King 
6676c422e34SRussell King 	mv88e6065_phylink_validate(chip, port, mask, state);
6686c422e34SRussell King }
6696c422e34SRussell King 
6706c422e34SRussell King static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6716c422e34SRussell King 				       unsigned long *mask,
6726c422e34SRussell King 				       struct phylink_link_state *state)
6736c422e34SRussell King {
674ec26016bSAndrew Lunn 	if (port >= 9) {
6756c422e34SRussell King 		phylink_set(mask, 2500baseX_Full);
676ec26016bSAndrew Lunn 		phylink_set(mask, 2500baseT_Full);
677ec26016bSAndrew Lunn 	}
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 mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
6876c422e34SRussell King 					unsigned long *mask,
6886c422e34SRussell King 					struct phylink_link_state *state)
6896c422e34SRussell King {
6906c422e34SRussell King 	if (port >= 9) {
6916c422e34SRussell King 		phylink_set(mask, 10000baseT_Full);
6926c422e34SRussell King 		phylink_set(mask, 10000baseKR_Full);
6936c422e34SRussell King 	}
6946c422e34SRussell King 
6956c422e34SRussell King 	mv88e6390_phylink_validate(chip, port, mask, state);
6966c422e34SRussell King }
6976c422e34SRussell King 
698c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
699c9a2356fSRussell King 			       unsigned long *supported,
700c9a2356fSRussell King 			       struct phylink_link_state *state)
701c9a2356fSRussell King {
7026c422e34SRussell King 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
7036c422e34SRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
7046c422e34SRussell King 
7056c422e34SRussell King 	/* Allow all the expected bits */
7066c422e34SRussell King 	phylink_set(mask, Autoneg);
7076c422e34SRussell King 	phylink_set(mask, Pause);
7086c422e34SRussell King 	phylink_set_port_modes(mask);
7096c422e34SRussell King 
7106c422e34SRussell King 	if (chip->info->ops->phylink_validate)
7116c422e34SRussell King 		chip->info->ops->phylink_validate(chip, port, mask, state);
7126c422e34SRussell King 
7136c422e34SRussell King 	bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
7146c422e34SRussell King 	bitmap_and(state->advertising, state->advertising, mask,
7156c422e34SRussell King 		   __ETHTOOL_LINK_MODE_MASK_NBITS);
7166c422e34SRussell King 
7176c422e34SRussell King 	/* We can only operate at 2500BaseX or 1000BaseX.  If requested
7186c422e34SRussell King 	 * to advertise both, only report advertising at 2500BaseX.
7196c422e34SRussell King 	 */
7206c422e34SRussell King 	phylink_helper_basex_speed(state);
721c9a2356fSRussell King }
722c9a2356fSRussell King 
723c9a2356fSRussell King static int mv88e6xxx_link_state(struct dsa_switch *ds, int port,
724c9a2356fSRussell King 				struct phylink_link_state *state)
725c9a2356fSRussell King {
726c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
727c9a2356fSRussell King 	int err;
728c9a2356fSRussell King 
729c9a2356fSRussell King 	mutex_lock(&chip->reg_lock);
7306c422e34SRussell King 	if (chip->info->ops->port_link_state)
7316c422e34SRussell King 		err = chip->info->ops->port_link_state(chip, port, state);
7326c422e34SRussell King 	else
7336c422e34SRussell King 		err = -EOPNOTSUPP;
734c9a2356fSRussell King 	mutex_unlock(&chip->reg_lock);
735c9a2356fSRussell King 
736c9a2356fSRussell King 	return err;
737c9a2356fSRussell King }
738c9a2356fSRussell King 
739c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
740c9a2356fSRussell King 				 unsigned int mode,
741c9a2356fSRussell King 				 const struct phylink_link_state *state)
742c9a2356fSRussell King {
743c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
74454186b91SAndrew Lunn 	int speed, duplex, link, pause, err;
745c9a2356fSRussell King 
746d700ec41SMarek Vasut 	if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port))
747c9a2356fSRussell King 		return;
748c9a2356fSRussell King 
749c9a2356fSRussell King 	if (mode == MLO_AN_FIXED) {
750c9a2356fSRussell King 		link = LINK_FORCED_UP;
751c9a2356fSRussell King 		speed = state->speed;
752c9a2356fSRussell King 		duplex = state->duplex;
753d700ec41SMarek Vasut 	} else if (!mv88e6xxx_phy_is_internal(ds, port)) {
754d700ec41SMarek Vasut 		link = state->link;
755d700ec41SMarek Vasut 		speed = state->speed;
756d700ec41SMarek Vasut 		duplex = state->duplex;
757c9a2356fSRussell King 	} else {
758c9a2356fSRussell King 		speed = SPEED_UNFORCED;
759c9a2356fSRussell King 		duplex = DUPLEX_UNFORCED;
760c9a2356fSRussell King 		link = LINK_UNFORCED;
761c9a2356fSRussell King 	}
76254186b91SAndrew Lunn 	pause = !!phylink_test(state->advertising, Pause);
763c9a2356fSRussell King 
764c9a2356fSRussell King 	mutex_lock(&chip->reg_lock);
76554186b91SAndrew Lunn 	err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, pause,
766c9a2356fSRussell King 				       state->interface);
767c9a2356fSRussell King 	mutex_unlock(&chip->reg_lock);
768c9a2356fSRussell King 
769c9a2356fSRussell King 	if (err && err != -EOPNOTSUPP)
770c9a2356fSRussell King 		dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
771c9a2356fSRussell King }
772c9a2356fSRussell King 
773c9a2356fSRussell King static void mv88e6xxx_mac_link_force(struct dsa_switch *ds, int port, int link)
774c9a2356fSRussell King {
775c9a2356fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
776c9a2356fSRussell King 	int err;
777c9a2356fSRussell King 
778c9a2356fSRussell King 	mutex_lock(&chip->reg_lock);
779c9a2356fSRussell King 	err = chip->info->ops->port_set_link(chip, port, link);
780c9a2356fSRussell King 	mutex_unlock(&chip->reg_lock);
781c9a2356fSRussell King 
782c9a2356fSRussell King 	if (err)
783c9a2356fSRussell King 		dev_err(chip->dev, "p%d: failed to force MAC link\n", port);
784c9a2356fSRussell King }
785c9a2356fSRussell King 
786c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
787c9a2356fSRussell King 				    unsigned int mode,
788c9a2356fSRussell King 				    phy_interface_t interface)
789c9a2356fSRussell King {
790c9a2356fSRussell King 	if (mode == MLO_AN_FIXED)
791c9a2356fSRussell King 		mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_DOWN);
792c9a2356fSRussell King }
793c9a2356fSRussell King 
794c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
795c9a2356fSRussell King 				  unsigned int mode, phy_interface_t interface,
796c9a2356fSRussell King 				  struct phy_device *phydev)
797c9a2356fSRussell King {
798c9a2356fSRussell King 	if (mode == MLO_AN_FIXED)
799c9a2356fSRussell King 		mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_UP);
800c9a2356fSRussell King }
801c9a2356fSRussell King 
802a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
803fad09c73SVivien Didelot {
804a605a0feSAndrew Lunn 	if (!chip->info->ops->stats_snapshot)
805a605a0feSAndrew Lunn 		return -EOPNOTSUPP;
806fad09c73SVivien Didelot 
807a605a0feSAndrew Lunn 	return chip->info->ops->stats_snapshot(chip, port);
808fad09c73SVivien Didelot }
809fad09c73SVivien Didelot 
810fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
811dfafe449SAndrew Lunn 	{ "in_good_octets",		8, 0x00, STATS_TYPE_BANK0, },
812dfafe449SAndrew Lunn 	{ "in_bad_octets",		4, 0x02, STATS_TYPE_BANK0, },
813dfafe449SAndrew Lunn 	{ "in_unicast",			4, 0x04, STATS_TYPE_BANK0, },
814dfafe449SAndrew Lunn 	{ "in_broadcasts",		4, 0x06, STATS_TYPE_BANK0, },
815dfafe449SAndrew Lunn 	{ "in_multicasts",		4, 0x07, STATS_TYPE_BANK0, },
816dfafe449SAndrew Lunn 	{ "in_pause",			4, 0x16, STATS_TYPE_BANK0, },
817dfafe449SAndrew Lunn 	{ "in_undersize",		4, 0x18, STATS_TYPE_BANK0, },
818dfafe449SAndrew Lunn 	{ "in_fragments",		4, 0x19, STATS_TYPE_BANK0, },
819dfafe449SAndrew Lunn 	{ "in_oversize",		4, 0x1a, STATS_TYPE_BANK0, },
820dfafe449SAndrew Lunn 	{ "in_jabber",			4, 0x1b, STATS_TYPE_BANK0, },
821dfafe449SAndrew Lunn 	{ "in_rx_error",		4, 0x1c, STATS_TYPE_BANK0, },
822dfafe449SAndrew Lunn 	{ "in_fcs_error",		4, 0x1d, STATS_TYPE_BANK0, },
823dfafe449SAndrew Lunn 	{ "out_octets",			8, 0x0e, STATS_TYPE_BANK0, },
824dfafe449SAndrew Lunn 	{ "out_unicast",		4, 0x10, STATS_TYPE_BANK0, },
825dfafe449SAndrew Lunn 	{ "out_broadcasts",		4, 0x13, STATS_TYPE_BANK0, },
826dfafe449SAndrew Lunn 	{ "out_multicasts",		4, 0x12, STATS_TYPE_BANK0, },
827dfafe449SAndrew Lunn 	{ "out_pause",			4, 0x15, STATS_TYPE_BANK0, },
828dfafe449SAndrew Lunn 	{ "excessive",			4, 0x11, STATS_TYPE_BANK0, },
829dfafe449SAndrew Lunn 	{ "collisions",			4, 0x1e, STATS_TYPE_BANK0, },
830dfafe449SAndrew Lunn 	{ "deferred",			4, 0x05, STATS_TYPE_BANK0, },
831dfafe449SAndrew Lunn 	{ "single",			4, 0x14, STATS_TYPE_BANK0, },
832dfafe449SAndrew Lunn 	{ "multiple",			4, 0x17, STATS_TYPE_BANK0, },
833dfafe449SAndrew Lunn 	{ "out_fcs_error",		4, 0x03, STATS_TYPE_BANK0, },
834dfafe449SAndrew Lunn 	{ "late",			4, 0x1f, STATS_TYPE_BANK0, },
835dfafe449SAndrew Lunn 	{ "hist_64bytes",		4, 0x08, STATS_TYPE_BANK0, },
836dfafe449SAndrew Lunn 	{ "hist_65_127bytes",		4, 0x09, STATS_TYPE_BANK0, },
837dfafe449SAndrew Lunn 	{ "hist_128_255bytes",		4, 0x0a, STATS_TYPE_BANK0, },
838dfafe449SAndrew Lunn 	{ "hist_256_511bytes",		4, 0x0b, STATS_TYPE_BANK0, },
839dfafe449SAndrew Lunn 	{ "hist_512_1023bytes",		4, 0x0c, STATS_TYPE_BANK0, },
840dfafe449SAndrew Lunn 	{ "hist_1024_max_bytes",	4, 0x0d, STATS_TYPE_BANK0, },
841dfafe449SAndrew Lunn 	{ "sw_in_discards",		4, 0x10, STATS_TYPE_PORT, },
842dfafe449SAndrew Lunn 	{ "sw_in_filtered",		2, 0x12, STATS_TYPE_PORT, },
843dfafe449SAndrew Lunn 	{ "sw_out_filtered",		2, 0x13, STATS_TYPE_PORT, },
844dfafe449SAndrew Lunn 	{ "in_discards",		4, 0x00, STATS_TYPE_BANK1, },
845dfafe449SAndrew Lunn 	{ "in_filtered",		4, 0x01, STATS_TYPE_BANK1, },
846dfafe449SAndrew Lunn 	{ "in_accepted",		4, 0x02, STATS_TYPE_BANK1, },
847dfafe449SAndrew Lunn 	{ "in_bad_accepted",		4, 0x03, STATS_TYPE_BANK1, },
848dfafe449SAndrew Lunn 	{ "in_good_avb_class_a",	4, 0x04, STATS_TYPE_BANK1, },
849dfafe449SAndrew Lunn 	{ "in_good_avb_class_b",	4, 0x05, STATS_TYPE_BANK1, },
850dfafe449SAndrew Lunn 	{ "in_bad_avb_class_a",		4, 0x06, STATS_TYPE_BANK1, },
851dfafe449SAndrew Lunn 	{ "in_bad_avb_class_b",		4, 0x07, STATS_TYPE_BANK1, },
852dfafe449SAndrew Lunn 	{ "tcam_counter_0",		4, 0x08, STATS_TYPE_BANK1, },
853dfafe449SAndrew Lunn 	{ "tcam_counter_1",		4, 0x09, STATS_TYPE_BANK1, },
854dfafe449SAndrew Lunn 	{ "tcam_counter_2",		4, 0x0a, STATS_TYPE_BANK1, },
855dfafe449SAndrew Lunn 	{ "tcam_counter_3",		4, 0x0b, STATS_TYPE_BANK1, },
856dfafe449SAndrew Lunn 	{ "in_da_unknown",		4, 0x0e, STATS_TYPE_BANK1, },
857dfafe449SAndrew Lunn 	{ "in_management",		4, 0x0f, STATS_TYPE_BANK1, },
858dfafe449SAndrew Lunn 	{ "out_queue_0",		4, 0x10, STATS_TYPE_BANK1, },
859dfafe449SAndrew Lunn 	{ "out_queue_1",		4, 0x11, STATS_TYPE_BANK1, },
860dfafe449SAndrew Lunn 	{ "out_queue_2",		4, 0x12, STATS_TYPE_BANK1, },
861dfafe449SAndrew Lunn 	{ "out_queue_3",		4, 0x13, STATS_TYPE_BANK1, },
862dfafe449SAndrew Lunn 	{ "out_queue_4",		4, 0x14, STATS_TYPE_BANK1, },
863dfafe449SAndrew Lunn 	{ "out_queue_5",		4, 0x15, STATS_TYPE_BANK1, },
864dfafe449SAndrew Lunn 	{ "out_queue_6",		4, 0x16, STATS_TYPE_BANK1, },
865dfafe449SAndrew Lunn 	{ "out_queue_7",		4, 0x17, STATS_TYPE_BANK1, },
866dfafe449SAndrew Lunn 	{ "out_cut_through",		4, 0x18, STATS_TYPE_BANK1, },
867dfafe449SAndrew Lunn 	{ "out_octets_a",		4, 0x1a, STATS_TYPE_BANK1, },
868dfafe449SAndrew Lunn 	{ "out_octets_b",		4, 0x1b, STATS_TYPE_BANK1, },
869dfafe449SAndrew Lunn 	{ "out_management",		4, 0x1f, STATS_TYPE_BANK1, },
870fad09c73SVivien Didelot };
871fad09c73SVivien Didelot 
872fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
873fad09c73SVivien Didelot 					    struct mv88e6xxx_hw_stat *s,
874e0d8b615SAndrew Lunn 					    int port, u16 bank1_select,
875e0d8b615SAndrew Lunn 					    u16 histogram)
876fad09c73SVivien Didelot {
877fad09c73SVivien Didelot 	u32 low;
878fad09c73SVivien Didelot 	u32 high = 0;
879dfafe449SAndrew Lunn 	u16 reg = 0;
8800e7b9925SAndrew Lunn 	int err;
881fad09c73SVivien Didelot 	u64 value;
882fad09c73SVivien Didelot 
883fad09c73SVivien Didelot 	switch (s->type) {
884dfafe449SAndrew Lunn 	case STATS_TYPE_PORT:
8850e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
8860e7b9925SAndrew Lunn 		if (err)
8876c3442f5SJisheng Zhang 			return U64_MAX;
888fad09c73SVivien Didelot 
8890e7b9925SAndrew Lunn 		low = reg;
890cda9f4aaSAndrew Lunn 		if (s->size == 4) {
8910e7b9925SAndrew Lunn 			err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
8920e7b9925SAndrew Lunn 			if (err)
8936c3442f5SJisheng Zhang 				return U64_MAX;
8940e7b9925SAndrew Lunn 			high = reg;
895fad09c73SVivien Didelot 		}
896fad09c73SVivien Didelot 		break;
897dfafe449SAndrew Lunn 	case STATS_TYPE_BANK1:
898e0d8b615SAndrew Lunn 		reg = bank1_select;
899dfafe449SAndrew Lunn 		/* fall through */
900dfafe449SAndrew Lunn 	case STATS_TYPE_BANK0:
901e0d8b615SAndrew Lunn 		reg |= s->reg | histogram;
9027f9ef3afSAndrew Lunn 		mv88e6xxx_g1_stats_read(chip, reg, &low);
903cda9f4aaSAndrew Lunn 		if (s->size == 8)
9047f9ef3afSAndrew Lunn 			mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
9059fc3e4dcSGustavo A. R. Silva 		break;
9069fc3e4dcSGustavo A. R. Silva 	default:
9076c3442f5SJisheng Zhang 		return U64_MAX;
908fad09c73SVivien Didelot 	}
909fad09c73SVivien Didelot 	value = (((u64)high) << 16) | low;
910fad09c73SVivien Didelot 	return value;
911fad09c73SVivien Didelot }
912fad09c73SVivien Didelot 
913436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
914dfafe449SAndrew Lunn 				       uint8_t *data, int types)
915fad09c73SVivien Didelot {
916fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
917fad09c73SVivien Didelot 	int i, j;
918fad09c73SVivien Didelot 
919fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
920fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
921dfafe449SAndrew Lunn 		if (stat->type & types) {
922fad09c73SVivien Didelot 			memcpy(data + j * ETH_GSTRING_LEN, stat->string,
923fad09c73SVivien Didelot 			       ETH_GSTRING_LEN);
924fad09c73SVivien Didelot 			j++;
925fad09c73SVivien Didelot 		}
926fad09c73SVivien Didelot 	}
927436fe17dSAndrew Lunn 
928436fe17dSAndrew Lunn 	return j;
929fad09c73SVivien Didelot }
930fad09c73SVivien Didelot 
931436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
932dfafe449SAndrew Lunn 				       uint8_t *data)
933dfafe449SAndrew Lunn {
934436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
935dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_PORT);
936dfafe449SAndrew Lunn }
937dfafe449SAndrew Lunn 
938436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
939dfafe449SAndrew Lunn 				       uint8_t *data)
940dfafe449SAndrew Lunn {
941436fe17dSAndrew Lunn 	return mv88e6xxx_stats_get_strings(chip, data,
942dfafe449SAndrew Lunn 					   STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
943dfafe449SAndrew Lunn }
944dfafe449SAndrew Lunn 
94565f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = {
94665f60e45SAndrew Lunn 	"atu_member_violation",
94765f60e45SAndrew Lunn 	"atu_miss_violation",
94865f60e45SAndrew Lunn 	"atu_full_violation",
94965f60e45SAndrew Lunn 	"vtu_member_violation",
95065f60e45SAndrew Lunn 	"vtu_miss_violation",
95165f60e45SAndrew Lunn };
95265f60e45SAndrew Lunn 
95365f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data)
95465f60e45SAndrew Lunn {
95565f60e45SAndrew Lunn 	unsigned int i;
95665f60e45SAndrew Lunn 
95765f60e45SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++)
95865f60e45SAndrew Lunn 		strlcpy(data + i * ETH_GSTRING_LEN,
95965f60e45SAndrew Lunn 			mv88e6xxx_atu_vtu_stats_strings[i],
96065f60e45SAndrew Lunn 			ETH_GSTRING_LEN);
96165f60e45SAndrew Lunn }
96265f60e45SAndrew Lunn 
963dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
96489f09048SFlorian Fainelli 				  u32 stringset, uint8_t *data)
965fad09c73SVivien Didelot {
96604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
967436fe17dSAndrew Lunn 	int count = 0;
968dfafe449SAndrew Lunn 
96989f09048SFlorian Fainelli 	if (stringset != ETH_SS_STATS)
97089f09048SFlorian Fainelli 		return;
97189f09048SFlorian Fainelli 
972c6c8cd5eSAndrew Lunn 	mutex_lock(&chip->reg_lock);
973c6c8cd5eSAndrew Lunn 
974dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_strings)
975436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_strings(chip, data);
976436fe17dSAndrew Lunn 
977436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_strings) {
978436fe17dSAndrew Lunn 		data += count * ETH_GSTRING_LEN;
97965f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_strings(chip, port, data);
980436fe17dSAndrew Lunn 	}
981c6c8cd5eSAndrew Lunn 
98265f60e45SAndrew Lunn 	data += count * ETH_GSTRING_LEN;
98365f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_strings(data);
98465f60e45SAndrew Lunn 
985c6c8cd5eSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
986dfafe449SAndrew Lunn }
987dfafe449SAndrew Lunn 
988dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
989dfafe449SAndrew Lunn 					  int types)
990dfafe449SAndrew Lunn {
991fad09c73SVivien Didelot 	struct mv88e6xxx_hw_stat *stat;
992fad09c73SVivien Didelot 	int i, j;
993fad09c73SVivien Didelot 
994fad09c73SVivien Didelot 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
995fad09c73SVivien Didelot 		stat = &mv88e6xxx_hw_stats[i];
996dfafe449SAndrew Lunn 		if (stat->type & types)
997fad09c73SVivien Didelot 			j++;
998fad09c73SVivien Didelot 	}
999fad09c73SVivien Didelot 	return j;
1000fad09c73SVivien Didelot }
1001fad09c73SVivien Didelot 
1002dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
1003dfafe449SAndrew Lunn {
1004dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
1005dfafe449SAndrew Lunn 					      STATS_TYPE_PORT);
1006dfafe449SAndrew Lunn }
1007dfafe449SAndrew Lunn 
1008dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
1009dfafe449SAndrew Lunn {
1010dfafe449SAndrew Lunn 	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
1011dfafe449SAndrew Lunn 					      STATS_TYPE_BANK1);
1012dfafe449SAndrew Lunn }
1013dfafe449SAndrew Lunn 
101489f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
1015dfafe449SAndrew Lunn {
1016dfafe449SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
1017436fe17dSAndrew Lunn 	int serdes_count = 0;
1018436fe17dSAndrew Lunn 	int count = 0;
1019dfafe449SAndrew Lunn 
102089f09048SFlorian Fainelli 	if (sset != ETH_SS_STATS)
102189f09048SFlorian Fainelli 		return 0;
102289f09048SFlorian Fainelli 
1023c6c8cd5eSAndrew Lunn 	mutex_lock(&chip->reg_lock);
1024dfafe449SAndrew Lunn 	if (chip->info->ops->stats_get_sset_count)
1025436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_sset_count(chip);
1026436fe17dSAndrew Lunn 	if (count < 0)
1027436fe17dSAndrew Lunn 		goto out;
1028436fe17dSAndrew Lunn 
1029436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_sset_count)
1030436fe17dSAndrew Lunn 		serdes_count = chip->info->ops->serdes_get_sset_count(chip,
1031436fe17dSAndrew Lunn 								      port);
103265f60e45SAndrew Lunn 	if (serdes_count < 0) {
1033436fe17dSAndrew Lunn 		count = serdes_count;
103465f60e45SAndrew Lunn 		goto out;
103565f60e45SAndrew Lunn 	}
1036436fe17dSAndrew Lunn 	count += serdes_count;
103765f60e45SAndrew Lunn 	count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings);
103865f60e45SAndrew Lunn 
1039436fe17dSAndrew Lunn out:
1040c6c8cd5eSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
1041dfafe449SAndrew Lunn 
1042436fe17dSAndrew Lunn 	return count;
1043dfafe449SAndrew Lunn }
1044dfafe449SAndrew Lunn 
1045436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1046e0d8b615SAndrew Lunn 				     uint64_t *data, int types,
1047e0d8b615SAndrew Lunn 				     u16 bank1_select, u16 histogram)
1048052f947fSAndrew Lunn {
1049052f947fSAndrew Lunn 	struct mv88e6xxx_hw_stat *stat;
1050052f947fSAndrew Lunn 	int i, j;
1051052f947fSAndrew Lunn 
1052052f947fSAndrew Lunn 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
1053052f947fSAndrew Lunn 		stat = &mv88e6xxx_hw_stats[i];
1054052f947fSAndrew Lunn 		if (stat->type & types) {
1055377cda13SAndrew Lunn 			mutex_lock(&chip->reg_lock);
1056e0d8b615SAndrew Lunn 			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
1057e0d8b615SAndrew Lunn 							      bank1_select,
1058e0d8b615SAndrew Lunn 							      histogram);
1059377cda13SAndrew Lunn 			mutex_unlock(&chip->reg_lock);
1060377cda13SAndrew Lunn 
1061052f947fSAndrew Lunn 			j++;
1062052f947fSAndrew Lunn 		}
1063052f947fSAndrew Lunn 	}
1064436fe17dSAndrew Lunn 	return j;
1065052f947fSAndrew Lunn }
1066052f947fSAndrew Lunn 
1067436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1068052f947fSAndrew Lunn 				     uint64_t *data)
1069052f947fSAndrew Lunn {
1070052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1071e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
107257d1ef38SVivien Didelot 					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1073052f947fSAndrew Lunn }
1074052f947fSAndrew Lunn 
1075436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1076052f947fSAndrew Lunn 				     uint64_t *data)
1077052f947fSAndrew Lunn {
1078052f947fSAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1079e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
108057d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
108157d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1082e0d8b615SAndrew Lunn }
1083e0d8b615SAndrew Lunn 
1084436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
1085e0d8b615SAndrew Lunn 				     uint64_t *data)
1086e0d8b615SAndrew Lunn {
1087e0d8b615SAndrew Lunn 	return mv88e6xxx_stats_get_stats(chip, port, data,
1088e0d8b615SAndrew Lunn 					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
108957d1ef38SVivien Didelot 					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
109057d1ef38SVivien Didelot 					 0);
1091052f947fSAndrew Lunn }
1092052f947fSAndrew Lunn 
109365f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
109465f60e45SAndrew Lunn 					uint64_t *data)
109565f60e45SAndrew Lunn {
109665f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_member_violation;
109765f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_miss_violation;
109865f60e45SAndrew Lunn 	*data++ = chip->ports[port].atu_full_violation;
109965f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_member_violation;
110065f60e45SAndrew Lunn 	*data++ = chip->ports[port].vtu_miss_violation;
110165f60e45SAndrew Lunn }
110265f60e45SAndrew Lunn 
1103052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
1104052f947fSAndrew Lunn 				uint64_t *data)
1105052f947fSAndrew Lunn {
1106436fe17dSAndrew Lunn 	int count = 0;
1107436fe17dSAndrew Lunn 
1108052f947fSAndrew Lunn 	if (chip->info->ops->stats_get_stats)
1109436fe17dSAndrew Lunn 		count = chip->info->ops->stats_get_stats(chip, port, data);
1110436fe17dSAndrew Lunn 
111165f60e45SAndrew Lunn 	mutex_lock(&chip->reg_lock);
1112436fe17dSAndrew Lunn 	if (chip->info->ops->serdes_get_stats) {
1113436fe17dSAndrew Lunn 		data += count;
111465f60e45SAndrew Lunn 		count = chip->info->ops->serdes_get_stats(chip, port, data);
1115436fe17dSAndrew Lunn 	}
111665f60e45SAndrew Lunn 	data += count;
111765f60e45SAndrew Lunn 	mv88e6xxx_atu_vtu_get_stats(chip, port, data);
111865f60e45SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
1119052f947fSAndrew Lunn }
1120052f947fSAndrew Lunn 
1121fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
1122fad09c73SVivien Didelot 					uint64_t *data)
1123fad09c73SVivien Didelot {
112404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1125fad09c73SVivien Didelot 	int ret;
1126fad09c73SVivien Didelot 
1127fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1128fad09c73SVivien Didelot 
1129a605a0feSAndrew Lunn 	ret = mv88e6xxx_stats_snapshot(chip, port);
1130fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1131377cda13SAndrew Lunn 
1132377cda13SAndrew Lunn 	if (ret < 0)
1133fad09c73SVivien Didelot 		return;
1134052f947fSAndrew Lunn 
1135052f947fSAndrew Lunn 	mv88e6xxx_get_stats(chip, port, data);
1136fad09c73SVivien Didelot 
1137fad09c73SVivien Didelot }
1138fad09c73SVivien Didelot 
1139fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
1140fad09c73SVivien Didelot {
1141fad09c73SVivien Didelot 	return 32 * sizeof(u16);
1142fad09c73SVivien Didelot }
1143fad09c73SVivien Didelot 
1144fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
1145fad09c73SVivien Didelot 			       struct ethtool_regs *regs, void *_p)
1146fad09c73SVivien Didelot {
114704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
11480e7b9925SAndrew Lunn 	int err;
11490e7b9925SAndrew Lunn 	u16 reg;
1150fad09c73SVivien Didelot 	u16 *p = _p;
1151fad09c73SVivien Didelot 	int i;
1152fad09c73SVivien Didelot 
1153a5f39326SVivien Didelot 	regs->version = chip->info->prod_num;
1154fad09c73SVivien Didelot 
1155fad09c73SVivien Didelot 	memset(p, 0xff, 32 * sizeof(u16));
1156fad09c73SVivien Didelot 
1157fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1158fad09c73SVivien Didelot 
1159fad09c73SVivien Didelot 	for (i = 0; i < 32; i++) {
1160fad09c73SVivien Didelot 
11610e7b9925SAndrew Lunn 		err = mv88e6xxx_port_read(chip, port, i, &reg);
11620e7b9925SAndrew Lunn 		if (!err)
11630e7b9925SAndrew Lunn 			p[i] = reg;
1164fad09c73SVivien Didelot 	}
1165fad09c73SVivien Didelot 
1166fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1167fad09c73SVivien Didelot }
1168fad09c73SVivien Didelot 
116908f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
1170fad09c73SVivien Didelot 				 struct ethtool_eee *e)
1171fad09c73SVivien Didelot {
11725480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
11735480db69SVivien Didelot 	return 0;
1174fad09c73SVivien Didelot }
1175fad09c73SVivien Didelot 
117608f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port,
117746587e4aSVivien Didelot 				 struct ethtool_eee *e)
1178fad09c73SVivien Didelot {
11795480db69SVivien Didelot 	/* Nothing to do on the port's MAC */
11805480db69SVivien Didelot 	return 0;
1181fad09c73SVivien Didelot }
1182fad09c73SVivien Didelot 
1183e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
1184fad09c73SVivien Didelot {
1185e5887a2aSVivien Didelot 	struct dsa_switch *ds = NULL;
1186e5887a2aSVivien Didelot 	struct net_device *br;
1187e5887a2aSVivien Didelot 	u16 pvlan;
1188fad09c73SVivien Didelot 	int i;
1189fad09c73SVivien Didelot 
1190e5887a2aSVivien Didelot 	if (dev < DSA_MAX_SWITCHES)
1191e5887a2aSVivien Didelot 		ds = chip->ds->dst->ds[dev];
1192fad09c73SVivien Didelot 
1193e5887a2aSVivien Didelot 	/* Prevent frames from unknown switch or port */
1194e5887a2aSVivien Didelot 	if (!ds || port >= ds->num_ports)
1195e5887a2aSVivien Didelot 		return 0;
1196e5887a2aSVivien Didelot 
1197e5887a2aSVivien Didelot 	/* Frames from DSA links and CPU ports can egress any local port */
1198e5887a2aSVivien Didelot 	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
1199e5887a2aSVivien Didelot 		return mv88e6xxx_port_mask(chip);
1200e5887a2aSVivien Didelot 
1201e5887a2aSVivien Didelot 	br = ds->ports[port].bridge_dev;
1202e5887a2aSVivien Didelot 	pvlan = 0;
1203e5887a2aSVivien Didelot 
1204e5887a2aSVivien Didelot 	/* Frames from user ports can egress any local DSA links and CPU ports,
1205e5887a2aSVivien Didelot 	 * as well as any local member of their bridge group.
1206e5887a2aSVivien Didelot 	 */
1207e5887a2aSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
1208e5887a2aSVivien Didelot 		if (dsa_is_cpu_port(chip->ds, i) ||
1209e5887a2aSVivien Didelot 		    dsa_is_dsa_port(chip->ds, i) ||
1210c8652c83SVivien Didelot 		    (br && dsa_to_port(chip->ds, i)->bridge_dev == br))
1211e5887a2aSVivien Didelot 			pvlan |= BIT(i);
1212e5887a2aSVivien Didelot 
1213e5887a2aSVivien Didelot 	return pvlan;
1214fad09c73SVivien Didelot }
1215e5887a2aSVivien Didelot 
1216240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port)
1217e5887a2aSVivien Didelot {
1218e5887a2aSVivien Didelot 	u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port);
1219fad09c73SVivien Didelot 
1220fad09c73SVivien Didelot 	/* prevent frames from going back out of the port they came in on */
1221fad09c73SVivien Didelot 	output_ports &= ~BIT(port);
1222fad09c73SVivien Didelot 
12235a7921f4SVivien Didelot 	return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
1224fad09c73SVivien Didelot }
1225fad09c73SVivien Didelot 
1226fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
1227fad09c73SVivien Didelot 					 u8 state)
1228fad09c73SVivien Didelot {
122904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1230fad09c73SVivien Didelot 	int err;
1231fad09c73SVivien Didelot 
1232fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1233f894c29cSVivien Didelot 	err = mv88e6xxx_port_set_state(chip, port, state);
1234fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1235fad09c73SVivien Didelot 
1236fad09c73SVivien Didelot 	if (err)
1237774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to update state\n", port);
1238fad09c73SVivien Didelot }
1239fad09c73SVivien Didelot 
124093e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip)
124193e18d61SVivien Didelot {
124293e18d61SVivien Didelot 	int err;
124393e18d61SVivien Didelot 
124493e18d61SVivien Didelot 	if (chip->info->ops->ieee_pri_map) {
124593e18d61SVivien Didelot 		err = chip->info->ops->ieee_pri_map(chip);
124693e18d61SVivien Didelot 		if (err)
124793e18d61SVivien Didelot 			return err;
124893e18d61SVivien Didelot 	}
124993e18d61SVivien Didelot 
125093e18d61SVivien Didelot 	if (chip->info->ops->ip_pri_map) {
125193e18d61SVivien Didelot 		err = chip->info->ops->ip_pri_map(chip);
125293e18d61SVivien Didelot 		if (err)
125393e18d61SVivien Didelot 			return err;
125493e18d61SVivien Didelot 	}
125593e18d61SVivien Didelot 
125693e18d61SVivien Didelot 	return 0;
125793e18d61SVivien Didelot }
125893e18d61SVivien Didelot 
1259c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
1260c7f047b6SVivien Didelot {
1261c7f047b6SVivien Didelot 	int target, port;
1262c7f047b6SVivien Didelot 	int err;
1263c7f047b6SVivien Didelot 
1264c7f047b6SVivien Didelot 	if (!chip->info->global2_addr)
1265c7f047b6SVivien Didelot 		return 0;
1266c7f047b6SVivien Didelot 
1267c7f047b6SVivien Didelot 	/* Initialize the routing port to the 32 possible target devices */
1268c7f047b6SVivien Didelot 	for (target = 0; target < 32; target++) {
1269c7f047b6SVivien Didelot 		port = 0x1f;
1270c7f047b6SVivien Didelot 		if (target < DSA_MAX_SWITCHES)
1271c7f047b6SVivien Didelot 			if (chip->ds->rtable[target] != DSA_RTABLE_NONE)
1272c7f047b6SVivien Didelot 				port = chip->ds->rtable[target];
1273c7f047b6SVivien Didelot 
1274c7f047b6SVivien Didelot 		err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
1275c7f047b6SVivien Didelot 		if (err)
1276c7f047b6SVivien Didelot 			return err;
1277c7f047b6SVivien Didelot 	}
1278c7f047b6SVivien Didelot 
127902317e68SVivien Didelot 	if (chip->info->ops->set_cascade_port) {
128002317e68SVivien Didelot 		port = MV88E6XXX_CASCADE_PORT_MULTIPLE;
128102317e68SVivien Didelot 		err = chip->info->ops->set_cascade_port(chip, port);
128202317e68SVivien Didelot 		if (err)
128302317e68SVivien Didelot 			return err;
128402317e68SVivien Didelot 	}
128502317e68SVivien Didelot 
128623c98919SVivien Didelot 	err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index);
128723c98919SVivien Didelot 	if (err)
128823c98919SVivien Didelot 		return err;
128923c98919SVivien Didelot 
1290c7f047b6SVivien Didelot 	return 0;
1291c7f047b6SVivien Didelot }
1292c7f047b6SVivien Didelot 
1293b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip)
1294b28f872dSVivien Didelot {
1295b28f872dSVivien Didelot 	/* Clear all trunk masks and mapping */
1296b28f872dSVivien Didelot 	if (chip->info->global2_addr)
1297b28f872dSVivien Didelot 		return mv88e6xxx_g2_trunk_clear(chip);
1298b28f872dSVivien Didelot 
1299b28f872dSVivien Didelot 	return 0;
1300b28f872dSVivien Didelot }
1301b28f872dSVivien Didelot 
13029e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
13039e5baf9bSVivien Didelot {
13049e5baf9bSVivien Didelot 	if (chip->info->ops->rmu_disable)
13059e5baf9bSVivien Didelot 		return chip->info->ops->rmu_disable(chip);
13069e5baf9bSVivien Didelot 
13079e5baf9bSVivien Didelot 	return 0;
13089e5baf9bSVivien Didelot }
13099e5baf9bSVivien Didelot 
13109e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
13119e907d73SVivien Didelot {
13129e907d73SVivien Didelot 	if (chip->info->ops->pot_clear)
13139e907d73SVivien Didelot 		return chip->info->ops->pot_clear(chip);
13149e907d73SVivien Didelot 
13159e907d73SVivien Didelot 	return 0;
13169e907d73SVivien Didelot }
13179e907d73SVivien Didelot 
131851c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip)
131951c901a7SVivien Didelot {
132051c901a7SVivien Didelot 	if (chip->info->ops->mgmt_rsvd2cpu)
132151c901a7SVivien Didelot 		return chip->info->ops->mgmt_rsvd2cpu(chip);
132251c901a7SVivien Didelot 
132351c901a7SVivien Didelot 	return 0;
132451c901a7SVivien Didelot }
132551c901a7SVivien Didelot 
1326a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
1327a2ac29d2SVivien Didelot {
1328c3a7d4adSVivien Didelot 	int err;
1329c3a7d4adSVivien Didelot 
1330daefc943SVivien Didelot 	err = mv88e6xxx_g1_atu_flush(chip, 0, true);
1331daefc943SVivien Didelot 	if (err)
1332daefc943SVivien Didelot 		return err;
1333daefc943SVivien Didelot 
1334c3a7d4adSVivien Didelot 	err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
1335c3a7d4adSVivien Didelot 	if (err)
1336c3a7d4adSVivien Didelot 		return err;
1337c3a7d4adSVivien Didelot 
1338a2ac29d2SVivien Didelot 	return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
1339a2ac29d2SVivien Didelot }
1340a2ac29d2SVivien Didelot 
1341cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip)
1342cd8da8bbSVivien Didelot {
1343cd8da8bbSVivien Didelot 	int port;
1344cd8da8bbSVivien Didelot 	int err;
1345cd8da8bbSVivien Didelot 
1346cd8da8bbSVivien Didelot 	if (!chip->info->ops->irl_init_all)
1347cd8da8bbSVivien Didelot 		return 0;
1348cd8da8bbSVivien Didelot 
1349cd8da8bbSVivien Didelot 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
1350cd8da8bbSVivien Didelot 		/* Disable ingress rate limiting by resetting all per port
1351cd8da8bbSVivien Didelot 		 * ingress rate limit resources to their initial state.
1352cd8da8bbSVivien Didelot 		 */
1353cd8da8bbSVivien Didelot 		err = chip->info->ops->irl_init_all(chip, port);
1354cd8da8bbSVivien Didelot 		if (err)
1355cd8da8bbSVivien Didelot 			return err;
1356cd8da8bbSVivien Didelot 	}
1357cd8da8bbSVivien Didelot 
1358cd8da8bbSVivien Didelot 	return 0;
1359cd8da8bbSVivien Didelot }
1360cd8da8bbSVivien Didelot 
136104a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip)
136204a69a17SVivien Didelot {
136304a69a17SVivien Didelot 	if (chip->info->ops->set_switch_mac) {
136404a69a17SVivien Didelot 		u8 addr[ETH_ALEN];
136504a69a17SVivien Didelot 
136604a69a17SVivien Didelot 		eth_random_addr(addr);
136704a69a17SVivien Didelot 
136804a69a17SVivien Didelot 		return chip->info->ops->set_switch_mac(chip, addr);
136904a69a17SVivien Didelot 	}
137004a69a17SVivien Didelot 
137104a69a17SVivien Didelot 	return 0;
137204a69a17SVivien Didelot }
137304a69a17SVivien Didelot 
137417a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
137517a1594eSVivien Didelot {
137617a1594eSVivien Didelot 	u16 pvlan = 0;
137717a1594eSVivien Didelot 
137817a1594eSVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
137917a1594eSVivien Didelot 		return -EOPNOTSUPP;
138017a1594eSVivien Didelot 
138117a1594eSVivien Didelot 	/* Skip the local source device, which uses in-chip port VLAN */
138217a1594eSVivien Didelot 	if (dev != chip->ds->index)
1383aec5ac88SVivien Didelot 		pvlan = mv88e6xxx_port_vlan(chip, dev, port);
138417a1594eSVivien Didelot 
138517a1594eSVivien Didelot 	return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
138617a1594eSVivien Didelot }
138717a1594eSVivien Didelot 
138881228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
138981228996SVivien Didelot {
139017a1594eSVivien Didelot 	int dev, port;
139117a1594eSVivien Didelot 	int err;
139217a1594eSVivien Didelot 
139381228996SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
139481228996SVivien Didelot 		return 0;
139581228996SVivien Didelot 
139681228996SVivien Didelot 	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
139781228996SVivien Didelot 	 * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
139881228996SVivien Didelot 	 */
139917a1594eSVivien Didelot 	err = mv88e6xxx_g2_misc_4_bit_port(chip);
140017a1594eSVivien Didelot 	if (err)
140117a1594eSVivien Didelot 		return err;
140217a1594eSVivien Didelot 
140317a1594eSVivien Didelot 	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) {
140417a1594eSVivien Didelot 		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) {
140517a1594eSVivien Didelot 			err = mv88e6xxx_pvt_map(chip, dev, port);
140617a1594eSVivien Didelot 			if (err)
140717a1594eSVivien Didelot 				return err;
140817a1594eSVivien Didelot 		}
140917a1594eSVivien Didelot 	}
141017a1594eSVivien Didelot 
141117a1594eSVivien Didelot 	return 0;
141281228996SVivien Didelot }
141381228996SVivien Didelot 
1414749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
1415749efcb8SVivien Didelot {
1416749efcb8SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1417749efcb8SVivien Didelot 	int err;
1418749efcb8SVivien Didelot 
1419749efcb8SVivien Didelot 	mutex_lock(&chip->reg_lock);
1420e606ca36SVivien Didelot 	err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
1421749efcb8SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1422749efcb8SVivien Didelot 
1423749efcb8SVivien Didelot 	if (err)
1424774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to flush ATU\n", port);
1425749efcb8SVivien Didelot }
1426749efcb8SVivien Didelot 
1427b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)
1428b486d7c9SVivien Didelot {
1429b486d7c9SVivien Didelot 	if (!chip->info->max_vid)
1430b486d7c9SVivien Didelot 		return 0;
1431b486d7c9SVivien Didelot 
1432b486d7c9SVivien Didelot 	return mv88e6xxx_g1_vtu_flush(chip);
1433b486d7c9SVivien Didelot }
1434b486d7c9SVivien Didelot 
1435f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,
1436f1394b78SVivien Didelot 				 struct mv88e6xxx_vtu_entry *entry)
1437f1394b78SVivien Didelot {
1438f1394b78SVivien Didelot 	if (!chip->info->ops->vtu_getnext)
1439f1394b78SVivien Didelot 		return -EOPNOTSUPP;
1440f1394b78SVivien Didelot 
1441f1394b78SVivien Didelot 	return chip->info->ops->vtu_getnext(chip, entry);
1442f1394b78SVivien Didelot }
1443f1394b78SVivien Didelot 
14440ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
14450ad5daf6SVivien Didelot 				   struct mv88e6xxx_vtu_entry *entry)
14460ad5daf6SVivien Didelot {
14470ad5daf6SVivien Didelot 	if (!chip->info->ops->vtu_loadpurge)
14480ad5daf6SVivien Didelot 		return -EOPNOTSUPP;
14490ad5daf6SVivien Didelot 
14500ad5daf6SVivien Didelot 	return chip->info->ops->vtu_loadpurge(chip, entry);
14510ad5daf6SVivien Didelot }
14520ad5daf6SVivien Didelot 
1453d7f435f9SVivien Didelot static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
1454fad09c73SVivien Didelot {
1455fad09c73SVivien Didelot 	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
14563afb4bdeSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan = {
14573afb4bdeSVivien Didelot 		.vid = chip->info->max_vid,
14583afb4bdeSVivien Didelot 	};
1459fad09c73SVivien Didelot 	int i, err;
1460fad09c73SVivien Didelot 
1461fad09c73SVivien Didelot 	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
1462fad09c73SVivien Didelot 
1463fad09c73SVivien Didelot 	/* Set every FID bit used by the (un)bridged ports */
1464370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1465b4e48c50SVivien Didelot 		err = mv88e6xxx_port_get_fid(chip, i, fid);
1466fad09c73SVivien Didelot 		if (err)
1467fad09c73SVivien Didelot 			return err;
1468fad09c73SVivien Didelot 
1469fad09c73SVivien Didelot 		set_bit(*fid, fid_bitmap);
1470fad09c73SVivien Didelot 	}
1471fad09c73SVivien Didelot 
1472fad09c73SVivien Didelot 	/* Set every FID bit used by the VLAN entries */
1473fad09c73SVivien Didelot 	do {
1474f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1475fad09c73SVivien Didelot 		if (err)
1476fad09c73SVivien Didelot 			return err;
1477fad09c73SVivien Didelot 
1478fad09c73SVivien Didelot 		if (!vlan.valid)
1479fad09c73SVivien Didelot 			break;
1480fad09c73SVivien Didelot 
1481fad09c73SVivien Didelot 		set_bit(vlan.fid, fid_bitmap);
14823cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
1483fad09c73SVivien Didelot 
1484fad09c73SVivien Didelot 	/* The reset value 0x000 is used to indicate that multiple address
1485fad09c73SVivien Didelot 	 * databases are not needed. Return the next positive available.
1486fad09c73SVivien Didelot 	 */
1487fad09c73SVivien Didelot 	*fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1);
1488fad09c73SVivien Didelot 	if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
1489fad09c73SVivien Didelot 		return -ENOSPC;
1490fad09c73SVivien Didelot 
1491fad09c73SVivien Didelot 	/* Clear the database */
1492daefc943SVivien Didelot 	return mv88e6xxx_g1_atu_flush(chip, *fid, true);
1493fad09c73SVivien Didelot }
1494fad09c73SVivien Didelot 
1495567aa59aSVivien Didelot static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
1496567aa59aSVivien Didelot 			     struct mv88e6xxx_vtu_entry *entry, bool new)
1497fad09c73SVivien Didelot {
1498fad09c73SVivien Didelot 	int err;
1499fad09c73SVivien Didelot 
1500fad09c73SVivien Didelot 	if (!vid)
1501fad09c73SVivien Didelot 		return -EINVAL;
1502fad09c73SVivien Didelot 
15033afb4bdeSVivien Didelot 	entry->vid = vid - 1;
15043afb4bdeSVivien Didelot 	entry->valid = false;
1505fad09c73SVivien Didelot 
1506f1394b78SVivien Didelot 	err = mv88e6xxx_vtu_getnext(chip, entry);
1507fad09c73SVivien Didelot 	if (err)
1508fad09c73SVivien Didelot 		return err;
1509fad09c73SVivien Didelot 
1510567aa59aSVivien Didelot 	if (entry->vid == vid && entry->valid)
1511567aa59aSVivien Didelot 		return 0;
1512fad09c73SVivien Didelot 
1513567aa59aSVivien Didelot 	if (new) {
1514567aa59aSVivien Didelot 		int i;
1515567aa59aSVivien Didelot 
1516567aa59aSVivien Didelot 		/* Initialize a fresh VLAN entry */
1517567aa59aSVivien Didelot 		memset(entry, 0, sizeof(*entry));
1518567aa59aSVivien Didelot 		entry->valid = true;
1519567aa59aSVivien Didelot 		entry->vid = vid;
1520567aa59aSVivien Didelot 
1521553a768dSVivien Didelot 		/* Exclude all ports */
1522567aa59aSVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
1523553a768dSVivien Didelot 			entry->member[i] =
15247ec60d6eSVivien Didelot 				MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1525567aa59aSVivien Didelot 
1526567aa59aSVivien Didelot 		return mv88e6xxx_atu_new(chip, &entry->fid);
1527fad09c73SVivien Didelot 	}
1528fad09c73SVivien Didelot 
1529567aa59aSVivien Didelot 	/* switchdev expects -EOPNOTSUPP to honor software VLANs */
1530567aa59aSVivien Didelot 	return -EOPNOTSUPP;
1531fad09c73SVivien Didelot }
1532fad09c73SVivien Didelot 
1533fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
1534fad09c73SVivien Didelot 					u16 vid_begin, u16 vid_end)
1535fad09c73SVivien Didelot {
153604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
15373afb4bdeSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan = {
15383afb4bdeSVivien Didelot 		.vid = vid_begin - 1,
15393afb4bdeSVivien Didelot 	};
1540fad09c73SVivien Didelot 	int i, err;
1541fad09c73SVivien Didelot 
1542db06ae41SAndrew Lunn 	/* DSA and CPU ports have to be members of multiple vlans */
1543db06ae41SAndrew Lunn 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
1544db06ae41SAndrew Lunn 		return 0;
1545db06ae41SAndrew Lunn 
1546fad09c73SVivien Didelot 	if (!vid_begin)
1547fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1548fad09c73SVivien Didelot 
1549fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1550fad09c73SVivien Didelot 
1551fad09c73SVivien Didelot 	do {
1552f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1553fad09c73SVivien Didelot 		if (err)
1554fad09c73SVivien Didelot 			goto unlock;
1555fad09c73SVivien Didelot 
1556fad09c73SVivien Didelot 		if (!vlan.valid)
1557fad09c73SVivien Didelot 			break;
1558fad09c73SVivien Didelot 
1559fad09c73SVivien Didelot 		if (vlan.vid > vid_end)
1560fad09c73SVivien Didelot 			break;
1561fad09c73SVivien Didelot 
1562370b4ffbSVivien Didelot 		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1563fad09c73SVivien Didelot 			if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
1564fad09c73SVivien Didelot 				continue;
1565fad09c73SVivien Didelot 
1566cd886469SAndrew Lunn 			if (!ds->ports[i].slave)
156766e2809dSAndrew Lunn 				continue;
156866e2809dSAndrew Lunn 
1569bd00e053SVivien Didelot 			if (vlan.member[i] ==
15707ec60d6eSVivien Didelot 			    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1571fad09c73SVivien Didelot 				continue;
1572fad09c73SVivien Didelot 
1573c8652c83SVivien Didelot 			if (dsa_to_port(ds, i)->bridge_dev ==
1574fae8a25eSVivien Didelot 			    ds->ports[port].bridge_dev)
1575fad09c73SVivien Didelot 				break; /* same bridge, check next VLAN */
1576fad09c73SVivien Didelot 
1577c8652c83SVivien Didelot 			if (!dsa_to_port(ds, i)->bridge_dev)
157866e2809dSAndrew Lunn 				continue;
157966e2809dSAndrew Lunn 
1580743fcc28SAndrew Lunn 			dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
1581743fcc28SAndrew Lunn 				port, vlan.vid, i,
1582c8652c83SVivien Didelot 				netdev_name(dsa_to_port(ds, i)->bridge_dev));
1583fad09c73SVivien Didelot 			err = -EOPNOTSUPP;
1584fad09c73SVivien Didelot 			goto unlock;
1585fad09c73SVivien Didelot 		}
1586fad09c73SVivien Didelot 	} while (vlan.vid < vid_end);
1587fad09c73SVivien Didelot 
1588fad09c73SVivien Didelot unlock:
1589fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1590fad09c73SVivien Didelot 
1591fad09c73SVivien Didelot 	return err;
1592fad09c73SVivien Didelot }
1593fad09c73SVivien Didelot 
1594fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
1595fad09c73SVivien Didelot 					 bool vlan_filtering)
1596fad09c73SVivien Didelot {
159704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
159881c6edb2SVivien Didelot 	u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
159981c6edb2SVivien Didelot 		MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
16000e7b9925SAndrew Lunn 	int err;
1601fad09c73SVivien Didelot 
16023cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1603fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1604fad09c73SVivien Didelot 
1605fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1606385a0995SVivien Didelot 	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
1607fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1608fad09c73SVivien Didelot 
16090e7b9925SAndrew Lunn 	return err;
1610fad09c73SVivien Didelot }
1611fad09c73SVivien Didelot 
1612fad09c73SVivien Didelot static int
1613fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
161480e02360SVivien Didelot 			    const struct switchdev_obj_port_vlan *vlan)
1615fad09c73SVivien Didelot {
161604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1617fad09c73SVivien Didelot 	int err;
1618fad09c73SVivien Didelot 
16193cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1620fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1621fad09c73SVivien Didelot 
1622fad09c73SVivien Didelot 	/* If the requested port doesn't belong to the same bridge as the VLAN
1623fad09c73SVivien Didelot 	 * members, do not support it (yet) and fallback to software VLAN.
1624fad09c73SVivien Didelot 	 */
1625fad09c73SVivien Didelot 	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
1626fad09c73SVivien Didelot 					   vlan->vid_end);
1627fad09c73SVivien Didelot 	if (err)
1628fad09c73SVivien Didelot 		return err;
1629fad09c73SVivien Didelot 
1630fad09c73SVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
1631fad09c73SVivien Didelot 	 * so skip the prepare phase.
1632fad09c73SVivien Didelot 	 */
1633fad09c73SVivien Didelot 	return 0;
1634fad09c73SVivien Didelot }
1635fad09c73SVivien Didelot 
1636a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
1637a4c93ae1SAndrew Lunn 					const unsigned char *addr, u16 vid,
1638a4c93ae1SAndrew Lunn 					u8 state)
1639a4c93ae1SAndrew Lunn {
1640a4c93ae1SAndrew Lunn 	struct mv88e6xxx_vtu_entry vlan;
1641a4c93ae1SAndrew Lunn 	struct mv88e6xxx_atu_entry entry;
1642a4c93ae1SAndrew Lunn 	int err;
1643a4c93ae1SAndrew Lunn 
1644a4c93ae1SAndrew Lunn 	/* Null VLAN ID corresponds to the port private database */
1645a4c93ae1SAndrew Lunn 	if (vid == 0)
1646a4c93ae1SAndrew Lunn 		err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
1647a4c93ae1SAndrew Lunn 	else
1648a4c93ae1SAndrew Lunn 		err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
1649a4c93ae1SAndrew Lunn 	if (err)
1650a4c93ae1SAndrew Lunn 		return err;
1651a4c93ae1SAndrew Lunn 
1652a4c93ae1SAndrew Lunn 	entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1653a4c93ae1SAndrew Lunn 	ether_addr_copy(entry.mac, addr);
1654a4c93ae1SAndrew Lunn 	eth_addr_dec(entry.mac);
1655a4c93ae1SAndrew Lunn 
1656a4c93ae1SAndrew Lunn 	err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry);
1657a4c93ae1SAndrew Lunn 	if (err)
1658a4c93ae1SAndrew Lunn 		return err;
1659a4c93ae1SAndrew Lunn 
1660a4c93ae1SAndrew Lunn 	/* Initialize a fresh ATU entry if it isn't found */
1661a4c93ae1SAndrew Lunn 	if (entry.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED ||
1662a4c93ae1SAndrew Lunn 	    !ether_addr_equal(entry.mac, addr)) {
1663a4c93ae1SAndrew Lunn 		memset(&entry, 0, sizeof(entry));
1664a4c93ae1SAndrew Lunn 		ether_addr_copy(entry.mac, addr);
1665a4c93ae1SAndrew Lunn 	}
1666a4c93ae1SAndrew Lunn 
1667a4c93ae1SAndrew Lunn 	/* Purge the ATU entry only if no port is using it anymore */
1668a4c93ae1SAndrew Lunn 	if (state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
1669a4c93ae1SAndrew Lunn 		entry.portvec &= ~BIT(port);
1670a4c93ae1SAndrew Lunn 		if (!entry.portvec)
1671a4c93ae1SAndrew Lunn 			entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1672a4c93ae1SAndrew Lunn 	} else {
1673a4c93ae1SAndrew Lunn 		entry.portvec |= BIT(port);
1674a4c93ae1SAndrew Lunn 		entry.state = state;
1675a4c93ae1SAndrew Lunn 	}
1676a4c93ae1SAndrew Lunn 
1677a4c93ae1SAndrew Lunn 	return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry);
1678a4c93ae1SAndrew Lunn }
1679a4c93ae1SAndrew Lunn 
168087fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
168187fa886eSAndrew Lunn 					u16 vid)
168287fa886eSAndrew Lunn {
168387fa886eSAndrew Lunn 	const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
168487fa886eSAndrew Lunn 	u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
168587fa886eSAndrew Lunn 
168687fa886eSAndrew Lunn 	return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
168787fa886eSAndrew Lunn }
168887fa886eSAndrew Lunn 
168987fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
169087fa886eSAndrew Lunn {
169187fa886eSAndrew Lunn 	int port;
169287fa886eSAndrew Lunn 	int err;
169387fa886eSAndrew Lunn 
169487fa886eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
169587fa886eSAndrew Lunn 		err = mv88e6xxx_port_add_broadcast(chip, port, vid);
169687fa886eSAndrew Lunn 		if (err)
169787fa886eSAndrew Lunn 			return err;
169887fa886eSAndrew Lunn 	}
169987fa886eSAndrew Lunn 
170087fa886eSAndrew Lunn 	return 0;
170187fa886eSAndrew Lunn }
170287fa886eSAndrew Lunn 
1703fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
1704c91498e1SVivien Didelot 				    u16 vid, u8 member)
1705fad09c73SVivien Didelot {
1706b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1707fad09c73SVivien Didelot 	int err;
1708fad09c73SVivien Didelot 
1709567aa59aSVivien Didelot 	err = mv88e6xxx_vtu_get(chip, vid, &vlan, true);
1710fad09c73SVivien Didelot 	if (err)
1711fad09c73SVivien Didelot 		return err;
1712fad09c73SVivien Didelot 
1713c91498e1SVivien Didelot 	vlan.member[port] = member;
1714fad09c73SVivien Didelot 
171587fa886eSAndrew Lunn 	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
171687fa886eSAndrew Lunn 	if (err)
171787fa886eSAndrew Lunn 		return err;
171887fa886eSAndrew Lunn 
171987fa886eSAndrew Lunn 	return mv88e6xxx_broadcast_setup(chip, vid);
1720fad09c73SVivien Didelot }
1721fad09c73SVivien Didelot 
1722fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
172380e02360SVivien Didelot 				    const struct switchdev_obj_port_vlan *vlan)
1724fad09c73SVivien Didelot {
172504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1726fad09c73SVivien Didelot 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1727fad09c73SVivien Didelot 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1728c91498e1SVivien Didelot 	u8 member;
1729fad09c73SVivien Didelot 	u16 vid;
1730fad09c73SVivien Didelot 
17313cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1732fad09c73SVivien Didelot 		return;
1733fad09c73SVivien Didelot 
1734c91498e1SVivien Didelot 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
17357ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED;
1736c91498e1SVivien Didelot 	else if (untagged)
17377ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED;
1738c91498e1SVivien Didelot 	else
17397ec60d6eSVivien Didelot 		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
1740c91498e1SVivien Didelot 
1741fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1742fad09c73SVivien Didelot 
1743fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
1744c91498e1SVivien Didelot 		if (_mv88e6xxx_port_vlan_add(chip, port, vid, member))
1745774439e5SVivien Didelot 			dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
1746fad09c73SVivien Didelot 				vid, untagged ? 'u' : 't');
1747fad09c73SVivien Didelot 
174877064f37SVivien Didelot 	if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end))
1749774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to set PVID %d\n", port,
1750fad09c73SVivien Didelot 			vlan->vid_end);
1751fad09c73SVivien Didelot 
1752fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1753fad09c73SVivien Didelot }
1754fad09c73SVivien Didelot 
1755fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
1756fad09c73SVivien Didelot 				    int port, u16 vid)
1757fad09c73SVivien Didelot {
1758b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan;
1759fad09c73SVivien Didelot 	int i, err;
1760fad09c73SVivien Didelot 
1761567aa59aSVivien Didelot 	err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
1762fad09c73SVivien Didelot 	if (err)
1763fad09c73SVivien Didelot 		return err;
1764fad09c73SVivien Didelot 
1765fad09c73SVivien Didelot 	/* Tell switchdev if this VLAN is handled in software */
17667ec60d6eSVivien Didelot 	if (vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1767fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1768fad09c73SVivien Didelot 
17697ec60d6eSVivien Didelot 	vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1770fad09c73SVivien Didelot 
1771fad09c73SVivien Didelot 	/* keep the VLAN unless all ports are excluded */
1772fad09c73SVivien Didelot 	vlan.valid = false;
1773370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
17747ec60d6eSVivien Didelot 		if (vlan.member[i] !=
17757ec60d6eSVivien Didelot 		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
1776fad09c73SVivien Didelot 			vlan.valid = true;
1777fad09c73SVivien Didelot 			break;
1778fad09c73SVivien Didelot 		}
1779fad09c73SVivien Didelot 	}
1780fad09c73SVivien Didelot 
17810ad5daf6SVivien Didelot 	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
1782fad09c73SVivien Didelot 	if (err)
1783fad09c73SVivien Didelot 		return err;
1784fad09c73SVivien Didelot 
1785e606ca36SVivien Didelot 	return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
1786fad09c73SVivien Didelot }
1787fad09c73SVivien Didelot 
1788fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
1789fad09c73SVivien Didelot 				   const struct switchdev_obj_port_vlan *vlan)
1790fad09c73SVivien Didelot {
179104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1792fad09c73SVivien Didelot 	u16 pvid, vid;
1793fad09c73SVivien Didelot 	int err = 0;
1794fad09c73SVivien Didelot 
17953cf3c846SVivien Didelot 	if (!chip->info->max_vid)
1796fad09c73SVivien Didelot 		return -EOPNOTSUPP;
1797fad09c73SVivien Didelot 
1798fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1799fad09c73SVivien Didelot 
180077064f37SVivien Didelot 	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
1801fad09c73SVivien Didelot 	if (err)
1802fad09c73SVivien Didelot 		goto unlock;
1803fad09c73SVivien Didelot 
1804fad09c73SVivien Didelot 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1805fad09c73SVivien Didelot 		err = _mv88e6xxx_port_vlan_del(chip, port, vid);
1806fad09c73SVivien Didelot 		if (err)
1807fad09c73SVivien Didelot 			goto unlock;
1808fad09c73SVivien Didelot 
1809fad09c73SVivien Didelot 		if (vid == pvid) {
181077064f37SVivien Didelot 			err = mv88e6xxx_port_set_pvid(chip, port, 0);
1811fad09c73SVivien Didelot 			if (err)
1812fad09c73SVivien Didelot 				goto unlock;
1813fad09c73SVivien Didelot 		}
1814fad09c73SVivien Didelot 	}
1815fad09c73SVivien Didelot 
1816fad09c73SVivien Didelot unlock:
1817fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1818fad09c73SVivien Didelot 
1819fad09c73SVivien Didelot 	return err;
1820fad09c73SVivien Didelot }
1821fad09c73SVivien Didelot 
18221b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
18236c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
1824fad09c73SVivien Didelot {
182504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
18261b6dd556SArkadi Sharshevsky 	int err;
1827fad09c73SVivien Didelot 
1828fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
18291b6dd556SArkadi Sharshevsky 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
18301b6dd556SArkadi Sharshevsky 					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
1831fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
18321b6dd556SArkadi Sharshevsky 
18331b6dd556SArkadi Sharshevsky 	return err;
1834fad09c73SVivien Didelot }
1835fad09c73SVivien Didelot 
1836fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
18376c2c1dcbSArkadi Sharshevsky 				  const unsigned char *addr, u16 vid)
1838fad09c73SVivien Didelot {
183904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
184083dabd1fSVivien Didelot 	int err;
1841fad09c73SVivien Didelot 
1842fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
18436c2c1dcbSArkadi Sharshevsky 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
184427c0e600SVivien Didelot 					   MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
1845fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1846fad09c73SVivien Didelot 
184783dabd1fSVivien Didelot 	return err;
1848fad09c73SVivien Didelot }
1849fad09c73SVivien Didelot 
185083dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
1851fad09c73SVivien Didelot 				      u16 fid, u16 vid, int port,
18522bedde1aSArkadi Sharshevsky 				      dsa_fdb_dump_cb_t *cb, void *data)
1853fad09c73SVivien Didelot {
1854dabc1a96SVivien Didelot 	struct mv88e6xxx_atu_entry addr;
18552bedde1aSArkadi Sharshevsky 	bool is_static;
1856fad09c73SVivien Didelot 	int err;
1857fad09c73SVivien Didelot 
185827c0e600SVivien Didelot 	addr.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1859dabc1a96SVivien Didelot 	eth_broadcast_addr(addr.mac);
1860fad09c73SVivien Didelot 
1861fad09c73SVivien Didelot 	do {
1862a61e5406SAndrew Lunn 		mutex_lock(&chip->reg_lock);
1863dabc1a96SVivien Didelot 		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
1864a61e5406SAndrew Lunn 		mutex_unlock(&chip->reg_lock);
1865fad09c73SVivien Didelot 		if (err)
186683dabd1fSVivien Didelot 			return err;
1867fad09c73SVivien Didelot 
186827c0e600SVivien Didelot 		if (addr.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED)
1869fad09c73SVivien Didelot 			break;
1870fad09c73SVivien Didelot 
187101bd96c8SVivien Didelot 		if (addr.trunk || (addr.portvec & BIT(port)) == 0)
187283dabd1fSVivien Didelot 			continue;
1873fad09c73SVivien Didelot 
187483dabd1fSVivien Didelot 		if (!is_unicast_ether_addr(addr.mac))
187583dabd1fSVivien Didelot 			continue;
187683dabd1fSVivien Didelot 
18772bedde1aSArkadi Sharshevsky 		is_static = (addr.state ==
18782bedde1aSArkadi Sharshevsky 			     MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
18792bedde1aSArkadi Sharshevsky 		err = cb(addr.mac, vid, is_static, data);
188083dabd1fSVivien Didelot 		if (err)
188183dabd1fSVivien Didelot 			return err;
1882fad09c73SVivien Didelot 	} while (!is_broadcast_ether_addr(addr.mac));
1883fad09c73SVivien Didelot 
1884fad09c73SVivien Didelot 	return err;
1885fad09c73SVivien Didelot }
1886fad09c73SVivien Didelot 
188783dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
18882bedde1aSArkadi Sharshevsky 				  dsa_fdb_dump_cb_t *cb, void *data)
188983dabd1fSVivien Didelot {
1890b4e47c0fSVivien Didelot 	struct mv88e6xxx_vtu_entry vlan = {
18913cf3c846SVivien Didelot 		.vid = chip->info->max_vid,
189283dabd1fSVivien Didelot 	};
189383dabd1fSVivien Didelot 	u16 fid;
189483dabd1fSVivien Didelot 	int err;
189583dabd1fSVivien Didelot 
189683dabd1fSVivien Didelot 	/* Dump port's default Filtering Information Database (VLAN ID 0) */
1897a61e5406SAndrew Lunn 	mutex_lock(&chip->reg_lock);
1898b4e48c50SVivien Didelot 	err = mv88e6xxx_port_get_fid(chip, port, &fid);
1899a61e5406SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
1900a61e5406SAndrew Lunn 
190183dabd1fSVivien Didelot 	if (err)
190283dabd1fSVivien Didelot 		return err;
190383dabd1fSVivien Didelot 
19042bedde1aSArkadi Sharshevsky 	err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data);
190583dabd1fSVivien Didelot 	if (err)
190683dabd1fSVivien Didelot 		return err;
190783dabd1fSVivien Didelot 
190883dabd1fSVivien Didelot 	/* Dump VLANs' Filtering Information Databases */
190983dabd1fSVivien Didelot 	do {
1910a61e5406SAndrew Lunn 		mutex_lock(&chip->reg_lock);
1911f1394b78SVivien Didelot 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1912a61e5406SAndrew Lunn 		mutex_unlock(&chip->reg_lock);
191383dabd1fSVivien Didelot 		if (err)
191483dabd1fSVivien Didelot 			return err;
191583dabd1fSVivien Didelot 
191683dabd1fSVivien Didelot 		if (!vlan.valid)
191783dabd1fSVivien Didelot 			break;
191883dabd1fSVivien Didelot 
191983dabd1fSVivien Didelot 		err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port,
19202bedde1aSArkadi Sharshevsky 						 cb, data);
192183dabd1fSVivien Didelot 		if (err)
192283dabd1fSVivien Didelot 			return err;
19233cf3c846SVivien Didelot 	} while (vlan.vid < chip->info->max_vid);
192483dabd1fSVivien Didelot 
192583dabd1fSVivien Didelot 	return err;
192683dabd1fSVivien Didelot }
192783dabd1fSVivien Didelot 
1928fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
19292bedde1aSArkadi Sharshevsky 				   dsa_fdb_dump_cb_t *cb, void *data)
1930fad09c73SVivien Didelot {
193104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1932fad09c73SVivien Didelot 
1933a61e5406SAndrew Lunn 	return mv88e6xxx_port_db_dump(chip, port, cb, data);
1934fad09c73SVivien Didelot }
1935fad09c73SVivien Didelot 
1936240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
1937240ea3efSVivien Didelot 				struct net_device *br)
1938240ea3efSVivien Didelot {
1939e96a6e02SVivien Didelot 	struct dsa_switch *ds;
1940240ea3efSVivien Didelot 	int port;
1941e96a6e02SVivien Didelot 	int dev;
1942240ea3efSVivien Didelot 	int err;
1943240ea3efSVivien Didelot 
1944240ea3efSVivien Didelot 	/* Remap the Port VLAN of each local bridge group member */
1945240ea3efSVivien Didelot 	for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) {
1946240ea3efSVivien Didelot 		if (chip->ds->ports[port].bridge_dev == br) {
1947240ea3efSVivien Didelot 			err = mv88e6xxx_port_vlan_map(chip, port);
1948240ea3efSVivien Didelot 			if (err)
1949240ea3efSVivien Didelot 				return err;
1950240ea3efSVivien Didelot 		}
1951240ea3efSVivien Didelot 	}
1952240ea3efSVivien Didelot 
1953e96a6e02SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
1954e96a6e02SVivien Didelot 		return 0;
1955e96a6e02SVivien Didelot 
1956e96a6e02SVivien Didelot 	/* Remap the Port VLAN of each cross-chip bridge group member */
1957e96a6e02SVivien Didelot 	for (dev = 0; dev < DSA_MAX_SWITCHES; ++dev) {
1958e96a6e02SVivien Didelot 		ds = chip->ds->dst->ds[dev];
1959e96a6e02SVivien Didelot 		if (!ds)
1960e96a6e02SVivien Didelot 			break;
1961e96a6e02SVivien Didelot 
1962e96a6e02SVivien Didelot 		for (port = 0; port < ds->num_ports; ++port) {
1963e96a6e02SVivien Didelot 			if (ds->ports[port].bridge_dev == br) {
1964e96a6e02SVivien Didelot 				err = mv88e6xxx_pvt_map(chip, dev, port);
1965e96a6e02SVivien Didelot 				if (err)
1966e96a6e02SVivien Didelot 					return err;
1967e96a6e02SVivien Didelot 			}
1968e96a6e02SVivien Didelot 		}
1969e96a6e02SVivien Didelot 	}
1970e96a6e02SVivien Didelot 
1971240ea3efSVivien Didelot 	return 0;
1972240ea3efSVivien Didelot }
1973240ea3efSVivien Didelot 
1974fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
1975fae8a25eSVivien Didelot 				      struct net_device *br)
1976fad09c73SVivien Didelot {
197704bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1978240ea3efSVivien Didelot 	int err;
1979fad09c73SVivien Didelot 
1980fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1981240ea3efSVivien Didelot 	err = mv88e6xxx_bridge_map(chip, br);
1982fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1983fad09c73SVivien Didelot 
1984fad09c73SVivien Didelot 	return err;
1985fad09c73SVivien Didelot }
1986fad09c73SVivien Didelot 
1987f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
1988f123f2fbSVivien Didelot 					struct net_device *br)
1989fad09c73SVivien Didelot {
199004bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
1991fad09c73SVivien Didelot 
1992fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
1993240ea3efSVivien Didelot 	if (mv88e6xxx_bridge_map(chip, br) ||
1994240ea3efSVivien Didelot 	    mv88e6xxx_port_vlan_map(chip, port))
1995240ea3efSVivien Didelot 		dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
1996fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
1997fad09c73SVivien Didelot }
1998fad09c73SVivien Didelot 
1999aec5ac88SVivien Didelot static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev,
2000aec5ac88SVivien Didelot 					   int port, struct net_device *br)
2001aec5ac88SVivien Didelot {
2002aec5ac88SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2003aec5ac88SVivien Didelot 	int err;
2004aec5ac88SVivien Didelot 
2005aec5ac88SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
2006aec5ac88SVivien Didelot 		return 0;
2007aec5ac88SVivien Didelot 
2008aec5ac88SVivien Didelot 	mutex_lock(&chip->reg_lock);
2009aec5ac88SVivien Didelot 	err = mv88e6xxx_pvt_map(chip, dev, port);
2010aec5ac88SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2011aec5ac88SVivien Didelot 
2012aec5ac88SVivien Didelot 	return err;
2013aec5ac88SVivien Didelot }
2014aec5ac88SVivien Didelot 
2015aec5ac88SVivien Didelot static void mv88e6xxx_crosschip_bridge_leave(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 
2020aec5ac88SVivien Didelot 	if (!mv88e6xxx_has_pvt(chip))
2021aec5ac88SVivien Didelot 		return;
2022aec5ac88SVivien Didelot 
2023aec5ac88SVivien Didelot 	mutex_lock(&chip->reg_lock);
2024aec5ac88SVivien Didelot 	if (mv88e6xxx_pvt_map(chip, dev, port))
2025aec5ac88SVivien Didelot 		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
2026aec5ac88SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2027aec5ac88SVivien Didelot }
2028aec5ac88SVivien Didelot 
202917e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
203017e708baSVivien Didelot {
203117e708baSVivien Didelot 	if (chip->info->ops->reset)
203217e708baSVivien Didelot 		return chip->info->ops->reset(chip);
203317e708baSVivien Didelot 
203417e708baSVivien Didelot 	return 0;
203517e708baSVivien Didelot }
203617e708baSVivien Didelot 
2037309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
2038309eca6dSVivien Didelot {
2039309eca6dSVivien Didelot 	struct gpio_desc *gpiod = chip->reset;
2040309eca6dSVivien Didelot 
2041309eca6dSVivien Didelot 	/* If there is a GPIO connected to the reset pin, toggle it */
2042309eca6dSVivien Didelot 	if (gpiod) {
2043309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 1);
2044309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2045309eca6dSVivien Didelot 		gpiod_set_value_cansleep(gpiod, 0);
2046309eca6dSVivien Didelot 		usleep_range(10000, 20000);
2047309eca6dSVivien Didelot 	}
2048309eca6dSVivien Didelot }
2049309eca6dSVivien Didelot 
20504ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
20514ac4b5a6SVivien Didelot {
20524ac4b5a6SVivien Didelot 	int i, err;
20534ac4b5a6SVivien Didelot 
20544ac4b5a6SVivien Didelot 	/* Set all ports to the Disabled state */
20554ac4b5a6SVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2056f894c29cSVivien Didelot 		err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED);
20574ac4b5a6SVivien Didelot 		if (err)
20584ac4b5a6SVivien Didelot 			return err;
20594ac4b5a6SVivien Didelot 	}
20604ac4b5a6SVivien Didelot 
20614ac4b5a6SVivien Didelot 	/* Wait for transmit queues to drain,
20624ac4b5a6SVivien Didelot 	 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
20634ac4b5a6SVivien Didelot 	 */
20644ac4b5a6SVivien Didelot 	usleep_range(2000, 4000);
20654ac4b5a6SVivien Didelot 
20664ac4b5a6SVivien Didelot 	return 0;
20674ac4b5a6SVivien Didelot }
20684ac4b5a6SVivien Didelot 
2069fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
2070fad09c73SVivien Didelot {
2071a935c052SVivien Didelot 	int err;
2072fad09c73SVivien Didelot 
20734ac4b5a6SVivien Didelot 	err = mv88e6xxx_disable_ports(chip);
20740e7b9925SAndrew Lunn 	if (err)
20750e7b9925SAndrew Lunn 		return err;
2076fad09c73SVivien Didelot 
2077309eca6dSVivien Didelot 	mv88e6xxx_hardware_reset(chip);
2078fad09c73SVivien Didelot 
207917e708baSVivien Didelot 	return mv88e6xxx_software_reset(chip);
2080fad09c73SVivien Didelot }
2081fad09c73SVivien Didelot 
20824314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
208331bef4e9SVivien Didelot 				   enum mv88e6xxx_frame_mode frame,
208431bef4e9SVivien Didelot 				   enum mv88e6xxx_egress_mode egress, u16 etype)
208556995cbcSAndrew Lunn {
208656995cbcSAndrew Lunn 	int err;
208756995cbcSAndrew Lunn 
20884314557cSVivien Didelot 	if (!chip->info->ops->port_set_frame_mode)
20894314557cSVivien Didelot 		return -EOPNOTSUPP;
20904314557cSVivien Didelot 
20914314557cSVivien Didelot 	err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
209256995cbcSAndrew Lunn 	if (err)
209356995cbcSAndrew Lunn 		return err;
209456995cbcSAndrew Lunn 
20954314557cSVivien Didelot 	err = chip->info->ops->port_set_frame_mode(chip, port, frame);
20964314557cSVivien Didelot 	if (err)
20974314557cSVivien Didelot 		return err;
20984314557cSVivien Didelot 
20994314557cSVivien Didelot 	if (chip->info->ops->port_set_ether_type)
21004314557cSVivien Didelot 		return chip->info->ops->port_set_ether_type(chip, port, etype);
21014314557cSVivien Didelot 
21024314557cSVivien Didelot 	return 0;
21034314557cSVivien Didelot }
21044314557cSVivien Didelot 
21054314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
21064314557cSVivien Didelot {
21074314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
210831bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2109b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
21104314557cSVivien Didelot }
21114314557cSVivien Didelot 
21124314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
21134314557cSVivien Didelot {
21144314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
211531bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2116b8109594SVivien Didelot 				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
21174314557cSVivien Didelot }
21184314557cSVivien Didelot 
21194314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
21204314557cSVivien Didelot {
21214314557cSVivien Didelot 	return mv88e6xxx_set_port_mode(chip, port,
21224314557cSVivien Didelot 				       MV88E6XXX_FRAME_MODE_ETHERTYPE,
212331bef4e9SVivien Didelot 				       MV88E6XXX_EGRESS_MODE_ETHERTYPE,
212431bef4e9SVivien Didelot 				       ETH_P_EDSA);
21254314557cSVivien Didelot }
21264314557cSVivien Didelot 
21274314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port)
21284314557cSVivien Didelot {
21294314557cSVivien Didelot 	if (dsa_is_dsa_port(chip->ds, port))
21304314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
21314314557cSVivien Didelot 
21322b3e9891SVivien Didelot 	if (dsa_is_user_port(chip->ds, port))
21334314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_normal(chip, port);
21344314557cSVivien Didelot 
21354314557cSVivien Didelot 	/* Setup CPU port mode depending on its supported tag format */
21364314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA)
21374314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_dsa(chip, port);
21384314557cSVivien Didelot 
21394314557cSVivien Didelot 	if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA)
21404314557cSVivien Didelot 		return mv88e6xxx_set_port_mode_edsa(chip, port);
21414314557cSVivien Didelot 
21424314557cSVivien Didelot 	return -EINVAL;
21434314557cSVivien Didelot }
21444314557cSVivien Didelot 
2145ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
2146ea698f4fSVivien Didelot {
2147ea698f4fSVivien Didelot 	bool message = dsa_is_dsa_port(chip->ds, port);
2148ea698f4fSVivien Didelot 
2149ea698f4fSVivien Didelot 	return mv88e6xxx_port_set_message_port(chip, port, message);
2150ea698f4fSVivien Didelot }
2151ea698f4fSVivien Didelot 
2152601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
2153601aeed3SVivien Didelot {
21543ee50cbfSVivien Didelot 	struct dsa_switch *ds = chip->ds;
21553ee50cbfSVivien Didelot 	bool flood;
2156601aeed3SVivien Didelot 
2157601aeed3SVivien Didelot 	/* Upstream ports flood frames with unknown unicast or multicast DA */
21583ee50cbfSVivien Didelot 	flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port);
2159601aeed3SVivien Didelot 	if (chip->info->ops->port_set_egress_floods)
2160601aeed3SVivien Didelot 		return chip->info->ops->port_set_egress_floods(chip, port,
2161601aeed3SVivien Didelot 							       flood, flood);
2162601aeed3SVivien Didelot 
2163601aeed3SVivien Didelot 	return 0;
2164601aeed3SVivien Didelot }
2165601aeed3SVivien Didelot 
21666d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
21676d91782fSAndrew Lunn 				  bool on)
21686d91782fSAndrew Lunn {
2169523a8904SVivien Didelot 	if (chip->info->ops->serdes_power)
2170523a8904SVivien Didelot 		return chip->info->ops->serdes_power(chip, port, on);
21716d91782fSAndrew Lunn 
2172523a8904SVivien Didelot 	return 0;
21736d91782fSAndrew Lunn }
21746d91782fSAndrew Lunn 
2175fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
2176fa371c80SVivien Didelot {
2177fa371c80SVivien Didelot 	struct dsa_switch *ds = chip->ds;
2178fa371c80SVivien Didelot 	int upstream_port;
2179fa371c80SVivien Didelot 	int err;
2180fa371c80SVivien Didelot 
218107073c79SVivien Didelot 	upstream_port = dsa_upstream_port(ds, port);
2182fa371c80SVivien Didelot 	if (chip->info->ops->port_set_upstream_port) {
2183fa371c80SVivien Didelot 		err = chip->info->ops->port_set_upstream_port(chip, port,
2184fa371c80SVivien Didelot 							      upstream_port);
2185fa371c80SVivien Didelot 		if (err)
2186fa371c80SVivien Didelot 			return err;
2187fa371c80SVivien Didelot 	}
2188fa371c80SVivien Didelot 
21890ea54ddaSVivien Didelot 	if (port == upstream_port) {
21900ea54ddaSVivien Didelot 		if (chip->info->ops->set_cpu_port) {
21910ea54ddaSVivien Didelot 			err = chip->info->ops->set_cpu_port(chip,
21920ea54ddaSVivien Didelot 							    upstream_port);
21930ea54ddaSVivien Didelot 			if (err)
21940ea54ddaSVivien Didelot 				return err;
21950ea54ddaSVivien Didelot 		}
21960ea54ddaSVivien Didelot 
21970ea54ddaSVivien Didelot 		if (chip->info->ops->set_egress_port) {
21980ea54ddaSVivien Didelot 			err = chip->info->ops->set_egress_port(chip,
21990ea54ddaSVivien Didelot 							       upstream_port);
22000ea54ddaSVivien Didelot 			if (err)
22010ea54ddaSVivien Didelot 				return err;
22020ea54ddaSVivien Didelot 		}
22030ea54ddaSVivien Didelot 	}
22040ea54ddaSVivien Didelot 
2205fa371c80SVivien Didelot 	return 0;
2206fa371c80SVivien Didelot }
2207fa371c80SVivien Didelot 
2208fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
2209fad09c73SVivien Didelot {
2210fad09c73SVivien Didelot 	struct dsa_switch *ds = chip->ds;
22110e7b9925SAndrew Lunn 	int err;
2212fad09c73SVivien Didelot 	u16 reg;
2213fad09c73SVivien Didelot 
22147b898469SAndrew Lunn 	chip->ports[port].chip = chip;
22157b898469SAndrew Lunn 	chip->ports[port].port = port;
22167b898469SAndrew Lunn 
2217d78343d2SVivien Didelot 	/* MAC Forcing register: don't force link, speed, duplex or flow control
2218d78343d2SVivien Didelot 	 * state to any particular values on physical ports, but force the CPU
2219d78343d2SVivien Didelot 	 * port and all DSA ports to their maximum bandwidth and full duplex.
2220fad09c73SVivien Didelot 	 */
2221d78343d2SVivien Didelot 	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
2222d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
2223d78343d2SVivien Didelot 					       SPEED_MAX, DUPLEX_FULL,
222454186b91SAndrew Lunn 					       PAUSE_OFF,
2225d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
2226fad09c73SVivien Didelot 	else
2227d78343d2SVivien Didelot 		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
2228d78343d2SVivien Didelot 					       SPEED_UNFORCED, DUPLEX_UNFORCED,
222954186b91SAndrew Lunn 					       PAUSE_ON,
2230d78343d2SVivien Didelot 					       PHY_INTERFACE_MODE_NA);
22310e7b9925SAndrew Lunn 	if (err)
22320e7b9925SAndrew Lunn 		return err;
2233fad09c73SVivien Didelot 
2234fad09c73SVivien Didelot 	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
2235fad09c73SVivien Didelot 	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
2236fad09c73SVivien Didelot 	 * tunneling, determine priority by looking at 802.1p and IP
2237fad09c73SVivien Didelot 	 * priority fields (IP prio has precedence), and set STP state
2238fad09c73SVivien Didelot 	 * to Forwarding.
2239fad09c73SVivien Didelot 	 *
2240fad09c73SVivien Didelot 	 * If this is the CPU link, use DSA or EDSA tagging depending
2241fad09c73SVivien Didelot 	 * on which tagging mode was configured.
2242fad09c73SVivien Didelot 	 *
2243fad09c73SVivien Didelot 	 * If this is a link to another switch, use DSA tagging mode.
2244fad09c73SVivien Didelot 	 *
2245fad09c73SVivien Didelot 	 * If this is the upstream port for this switch, enable
2246fad09c73SVivien Didelot 	 * forwarding of unknown unicasts and multicasts.
2247fad09c73SVivien Didelot 	 */
2248a89b433bSVivien Didelot 	reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP |
2249a89b433bSVivien Didelot 		MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
2250a89b433bSVivien Didelot 		MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
2251a89b433bSVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
22520e7b9925SAndrew Lunn 	if (err)
22530e7b9925SAndrew Lunn 		return err;
225456995cbcSAndrew Lunn 
2255601aeed3SVivien Didelot 	err = mv88e6xxx_setup_port_mode(chip, port);
225656995cbcSAndrew Lunn 	if (err)
225756995cbcSAndrew Lunn 		return err;
2258fad09c73SVivien Didelot 
2259601aeed3SVivien Didelot 	err = mv88e6xxx_setup_egress_floods(chip, port);
22604314557cSVivien Didelot 	if (err)
22614314557cSVivien Didelot 		return err;
22624314557cSVivien Didelot 
226304aca993SAndrew Lunn 	/* Enable the SERDES interface for DSA and CPU ports. Normal
226404aca993SAndrew Lunn 	 * ports SERDES are enabled when the port is enabled, thus
226504aca993SAndrew Lunn 	 * saving a bit of power.
2266fad09c73SVivien Didelot 	 */
226704aca993SAndrew Lunn 	if ((dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) {
22686d91782fSAndrew Lunn 		err = mv88e6xxx_serdes_power(chip, port, true);
22690e7b9925SAndrew Lunn 		if (err)
22700e7b9925SAndrew Lunn 			return err;
227104aca993SAndrew Lunn 	}
2272fad09c73SVivien Didelot 
2273fad09c73SVivien Didelot 	/* Port Control 2: don't force a good FCS, set the maximum frame size to
2274fad09c73SVivien Didelot 	 * 10240 bytes, disable 802.1q tags checking, don't discard tagged or
2275fad09c73SVivien Didelot 	 * untagged frames on this port, do a destination address lookup on all
2276fad09c73SVivien Didelot 	 * received packets as usual, disable ARP mirroring and don't send a
2277fad09c73SVivien Didelot 	 * copy of all transmitted/received frames on this port to the CPU.
2278fad09c73SVivien Didelot 	 */
2279a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_map_da(chip, port);
2280a23b2961SAndrew Lunn 	if (err)
2281a23b2961SAndrew Lunn 		return err;
2282a23b2961SAndrew Lunn 
2283fa371c80SVivien Didelot 	err = mv88e6xxx_setup_upstream_port(chip, port);
22840e7b9925SAndrew Lunn 	if (err)
22850e7b9925SAndrew Lunn 		return err;
2286fad09c73SVivien Didelot 
2287a23b2961SAndrew Lunn 	err = mv88e6xxx_port_set_8021q_mode(chip, port,
228881c6edb2SVivien Didelot 				MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED);
2289a23b2961SAndrew Lunn 	if (err)
2290a23b2961SAndrew Lunn 		return err;
2291a23b2961SAndrew Lunn 
2292cd782656SVivien Didelot 	if (chip->info->ops->port_set_jumbo_size) {
2293cd782656SVivien Didelot 		err = chip->info->ops->port_set_jumbo_size(chip, port, 10240);
22945f436666SAndrew Lunn 		if (err)
22955f436666SAndrew Lunn 			return err;
22965f436666SAndrew Lunn 	}
22975f436666SAndrew Lunn 
2298fad09c73SVivien Didelot 	/* Port Association Vector: when learning source addresses
2299fad09c73SVivien Didelot 	 * of packets, add the address to the address database using
2300fad09c73SVivien Didelot 	 * a port bitmap that has only the bit for this port set and
2301fad09c73SVivien Didelot 	 * the other bits clear.
2302fad09c73SVivien Didelot 	 */
2303fad09c73SVivien Didelot 	reg = 1 << port;
2304fad09c73SVivien Didelot 	/* Disable learning for CPU port */
2305fad09c73SVivien Didelot 	if (dsa_is_cpu_port(ds, port))
2306fad09c73SVivien Didelot 		reg = 0;
2307fad09c73SVivien Didelot 
23082a4614e4SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
23092a4614e4SVivien Didelot 				   reg);
23100e7b9925SAndrew Lunn 	if (err)
23110e7b9925SAndrew Lunn 		return err;
2312fad09c73SVivien Didelot 
2313fad09c73SVivien Didelot 	/* Egress rate control 2: disable egress rate control. */
23142cb8cb14SVivien Didelot 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2,
23152cb8cb14SVivien Didelot 				   0x0000);
23160e7b9925SAndrew Lunn 	if (err)
23170e7b9925SAndrew Lunn 		return err;
2318fad09c73SVivien Didelot 
23190898432cSVivien Didelot 	if (chip->info->ops->port_pause_limit) {
23200898432cSVivien Didelot 		err = chip->info->ops->port_pause_limit(chip, port, 0, 0);
2321b35d322aSAndrew Lunn 		if (err)
2322b35d322aSAndrew Lunn 			return err;
2323b35d322aSAndrew Lunn 	}
2324b35d322aSAndrew Lunn 
2325c8c94891SVivien Didelot 	if (chip->info->ops->port_disable_learn_limit) {
2326c8c94891SVivien Didelot 		err = chip->info->ops->port_disable_learn_limit(chip, port);
2327c8c94891SVivien Didelot 		if (err)
2328c8c94891SVivien Didelot 			return err;
2329c8c94891SVivien Didelot 	}
2330c8c94891SVivien Didelot 
23319dbfb4e1SVivien Didelot 	if (chip->info->ops->port_disable_pri_override) {
23329dbfb4e1SVivien Didelot 		err = chip->info->ops->port_disable_pri_override(chip, port);
23330e7b9925SAndrew Lunn 		if (err)
23340e7b9925SAndrew Lunn 			return err;
2335ef0a7318SAndrew Lunn 	}
23362bbb33beSAndrew Lunn 
2337ef0a7318SAndrew Lunn 	if (chip->info->ops->port_tag_remap) {
2338ef0a7318SAndrew Lunn 		err = chip->info->ops->port_tag_remap(chip, port);
23390e7b9925SAndrew Lunn 		if (err)
23400e7b9925SAndrew Lunn 			return err;
2341fad09c73SVivien Didelot 	}
2342fad09c73SVivien Didelot 
2343ef70b111SAndrew Lunn 	if (chip->info->ops->port_egress_rate_limiting) {
2344ef70b111SAndrew Lunn 		err = chip->info->ops->port_egress_rate_limiting(chip, port);
23450e7b9925SAndrew Lunn 		if (err)
23460e7b9925SAndrew Lunn 			return err;
2347fad09c73SVivien Didelot 	}
2348fad09c73SVivien Didelot 
2349ea698f4fSVivien Didelot 	err = mv88e6xxx_setup_message_port(chip, port);
23500e7b9925SAndrew Lunn 	if (err)
23510e7b9925SAndrew Lunn 		return err;
2352fad09c73SVivien Didelot 
2353fad09c73SVivien Didelot 	/* Port based VLAN map: give each port the same default address
2354fad09c73SVivien Didelot 	 * database, and allow bidirectional communication between the
2355fad09c73SVivien Didelot 	 * CPU and DSA port(s), and the other ports.
2356fad09c73SVivien Didelot 	 */
2357b4e48c50SVivien Didelot 	err = mv88e6xxx_port_set_fid(chip, port, 0);
23580e7b9925SAndrew Lunn 	if (err)
23590e7b9925SAndrew Lunn 		return err;
2360fad09c73SVivien Didelot 
2361240ea3efSVivien Didelot 	err = mv88e6xxx_port_vlan_map(chip, port);
23620e7b9925SAndrew Lunn 	if (err)
23630e7b9925SAndrew Lunn 		return err;
2364fad09c73SVivien Didelot 
2365fad09c73SVivien Didelot 	/* Default VLAN ID and priority: don't set a default VLAN
2366fad09c73SVivien Didelot 	 * ID, and set the default packet priority to zero.
2367fad09c73SVivien Didelot 	 */
2368b7929fb3SVivien Didelot 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0);
2369fad09c73SVivien Didelot }
2370fad09c73SVivien Didelot 
237104aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
237204aca993SAndrew Lunn 				 struct phy_device *phydev)
237304aca993SAndrew Lunn {
237404aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
2375523a8904SVivien Didelot 	int err;
237604aca993SAndrew Lunn 
237704aca993SAndrew Lunn 	mutex_lock(&chip->reg_lock);
2378efd1ba6aSAndrew Lunn 
2379523a8904SVivien Didelot 	err = mv88e6xxx_serdes_power(chip, port, true);
2380efd1ba6aSAndrew Lunn 
2381efd1ba6aSAndrew Lunn 	if (!err && chip->info->ops->serdes_irq_setup)
2382efd1ba6aSAndrew Lunn 		err = chip->info->ops->serdes_irq_setup(chip, port);
2383efd1ba6aSAndrew Lunn 
238404aca993SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
238504aca993SAndrew Lunn 
238604aca993SAndrew Lunn 	return err;
238704aca993SAndrew Lunn }
238804aca993SAndrew Lunn 
238904aca993SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port,
239004aca993SAndrew Lunn 				   struct phy_device *phydev)
239104aca993SAndrew Lunn {
239204aca993SAndrew Lunn 	struct mv88e6xxx_chip *chip = ds->priv;
239304aca993SAndrew Lunn 
239404aca993SAndrew Lunn 	mutex_lock(&chip->reg_lock);
2395efd1ba6aSAndrew Lunn 
2396efd1ba6aSAndrew Lunn 	if (chip->info->ops->serdes_irq_free)
2397efd1ba6aSAndrew Lunn 		chip->info->ops->serdes_irq_free(chip, port);
2398efd1ba6aSAndrew Lunn 
2399523a8904SVivien Didelot 	if (mv88e6xxx_serdes_power(chip, port, false))
2400523a8904SVivien Didelot 		dev_err(chip->dev, "failed to power off SERDES\n");
2401efd1ba6aSAndrew Lunn 
240204aca993SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
240304aca993SAndrew Lunn }
240404aca993SAndrew Lunn 
24052cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
24062cfcd964SVivien Didelot 				     unsigned int ageing_time)
24072cfcd964SVivien Didelot {
240804bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
24092cfcd964SVivien Didelot 	int err;
24102cfcd964SVivien Didelot 
24112cfcd964SVivien Didelot 	mutex_lock(&chip->reg_lock);
2412720c6343SVivien Didelot 	err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
24132cfcd964SVivien Didelot 	mutex_unlock(&chip->reg_lock);
24142cfcd964SVivien Didelot 
24152cfcd964SVivien Didelot 	return err;
24162cfcd964SVivien Didelot }
24172cfcd964SVivien Didelot 
2418447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
2419fad09c73SVivien Didelot {
2420fad09c73SVivien Didelot 	int err;
2421fad09c73SVivien Didelot 
2422de227387SAndrew Lunn 	/* Initialize the statistics unit */
2423447b1bb8SVivien Didelot 	if (chip->info->ops->stats_set_histogram) {
2424447b1bb8SVivien Didelot 		err = chip->info->ops->stats_set_histogram(chip);
2425de227387SAndrew Lunn 		if (err)
2426de227387SAndrew Lunn 			return err;
2427447b1bb8SVivien Didelot 	}
2428de227387SAndrew Lunn 
242940cff8fcSAndrew Lunn 	return mv88e6xxx_g1_stats_clear(chip);
24309729934cSVivien Didelot }
24319729934cSVivien Didelot 
2432ea89098eSAndrew Lunn /* The mv88e6390 has some hidden registers used for debug and
2433ea89098eSAndrew Lunn  * development. The errata also makes use of them.
2434ea89098eSAndrew Lunn  */
2435ea89098eSAndrew Lunn static int mv88e6390_hidden_write(struct mv88e6xxx_chip *chip, int port,
2436ea89098eSAndrew Lunn 				  int reg, u16 val)
2437ea89098eSAndrew Lunn {
2438ea89098eSAndrew Lunn 	u16 ctrl;
2439ea89098eSAndrew Lunn 	int err;
2440ea89098eSAndrew Lunn 
2441ea89098eSAndrew Lunn 	err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_DATA_PORT,
2442ea89098eSAndrew Lunn 				   PORT_RESERVED_1A, val);
2443ea89098eSAndrew Lunn 	if (err)
2444ea89098eSAndrew Lunn 		return err;
2445ea89098eSAndrew Lunn 
2446ea89098eSAndrew Lunn 	ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_WRITE |
2447ea89098eSAndrew Lunn 	       PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT |
2448ea89098eSAndrew Lunn 	       reg;
2449ea89098eSAndrew Lunn 
2450ea89098eSAndrew Lunn 	return mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT,
2451ea89098eSAndrew Lunn 				    PORT_RESERVED_1A, ctrl);
2452ea89098eSAndrew Lunn }
2453ea89098eSAndrew Lunn 
2454ea89098eSAndrew Lunn static int mv88e6390_hidden_wait(struct mv88e6xxx_chip *chip)
2455ea89098eSAndrew Lunn {
2456ea89098eSAndrew Lunn 	return mv88e6xxx_wait(chip, PORT_RESERVED_1A_CTRL_PORT,
2457ea89098eSAndrew Lunn 			      PORT_RESERVED_1A, PORT_RESERVED_1A_BUSY);
2458ea89098eSAndrew Lunn }
2459ea89098eSAndrew Lunn 
2460ea89098eSAndrew Lunn 
2461ea89098eSAndrew Lunn static int mv88e6390_hidden_read(struct mv88e6xxx_chip *chip, int port,
2462ea89098eSAndrew Lunn 				  int reg, u16 *val)
2463ea89098eSAndrew Lunn {
2464ea89098eSAndrew Lunn 	u16 ctrl;
2465ea89098eSAndrew Lunn 	int err;
2466ea89098eSAndrew Lunn 
2467ea89098eSAndrew Lunn 	ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_READ |
2468ea89098eSAndrew Lunn 	       PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT |
2469ea89098eSAndrew Lunn 	       reg;
2470ea89098eSAndrew Lunn 
2471ea89098eSAndrew Lunn 	err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT,
2472ea89098eSAndrew Lunn 				   PORT_RESERVED_1A, ctrl);
2473ea89098eSAndrew Lunn 	if (err)
2474ea89098eSAndrew Lunn 		return err;
2475ea89098eSAndrew Lunn 
2476ea89098eSAndrew Lunn 	err = mv88e6390_hidden_wait(chip);
2477ea89098eSAndrew Lunn 	if (err)
2478ea89098eSAndrew Lunn 		return err;
2479ea89098eSAndrew Lunn 
2480ea89098eSAndrew Lunn 	return 	mv88e6xxx_port_read(chip, PORT_RESERVED_1A_DATA_PORT,
2481ea89098eSAndrew Lunn 				    PORT_RESERVED_1A, val);
2482ea89098eSAndrew Lunn }
2483ea89098eSAndrew Lunn 
2484ea89098eSAndrew Lunn /* Check if the errata has already been applied. */
2485ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
2486ea89098eSAndrew Lunn {
2487ea89098eSAndrew Lunn 	int port;
2488ea89098eSAndrew Lunn 	int err;
2489ea89098eSAndrew Lunn 	u16 val;
2490ea89098eSAndrew Lunn 
2491ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
2492ea89098eSAndrew Lunn 		err = mv88e6390_hidden_read(chip, port, 0, &val);
2493ea89098eSAndrew Lunn 		if (err) {
2494ea89098eSAndrew Lunn 			dev_err(chip->dev,
2495ea89098eSAndrew Lunn 				"Error reading hidden register: %d\n", err);
2496ea89098eSAndrew Lunn 			return false;
2497ea89098eSAndrew Lunn 		}
2498ea89098eSAndrew Lunn 		if (val != 0x01c0)
2499ea89098eSAndrew Lunn 			return false;
2500ea89098eSAndrew Lunn 	}
2501ea89098eSAndrew Lunn 
2502ea89098eSAndrew Lunn 	return true;
2503ea89098eSAndrew Lunn }
2504ea89098eSAndrew Lunn 
2505ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic
2506ea89098eSAndrew Lunn  * values into undocumented hidden registers and then performing a
2507ea89098eSAndrew Lunn  * software reset.
2508ea89098eSAndrew Lunn  */
2509ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
2510ea89098eSAndrew Lunn {
2511ea89098eSAndrew Lunn 	int port;
2512ea89098eSAndrew Lunn 	int err;
2513ea89098eSAndrew Lunn 
2514ea89098eSAndrew Lunn 	if (mv88e6390_setup_errata_applied(chip))
2515ea89098eSAndrew Lunn 		return 0;
2516ea89098eSAndrew Lunn 
2517ea89098eSAndrew Lunn 	/* Set the ports into blocking mode */
2518ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
2519ea89098eSAndrew Lunn 		err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED);
2520ea89098eSAndrew Lunn 		if (err)
2521ea89098eSAndrew Lunn 			return err;
2522ea89098eSAndrew Lunn 	}
2523ea89098eSAndrew Lunn 
2524ea89098eSAndrew Lunn 	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
2525ea89098eSAndrew Lunn 		err = mv88e6390_hidden_write(chip, port, 0, 0x01c0);
2526ea89098eSAndrew Lunn 		if (err)
2527ea89098eSAndrew Lunn 			return err;
2528ea89098eSAndrew Lunn 	}
2529ea89098eSAndrew Lunn 
2530ea89098eSAndrew Lunn 	return mv88e6xxx_software_reset(chip);
2531ea89098eSAndrew Lunn }
2532ea89098eSAndrew Lunn 
2533fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds)
2534fad09c73SVivien Didelot {
253504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
25362d2e1dd2SAndrew Lunn 	u8 cmode;
2537fad09c73SVivien Didelot 	int err;
2538fad09c73SVivien Didelot 	int i;
2539fad09c73SVivien Didelot 
2540fad09c73SVivien Didelot 	chip->ds = ds;
2541a3c53be5SAndrew Lunn 	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
2542fad09c73SVivien Didelot 
2543fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
2544fad09c73SVivien Didelot 
2545ea89098eSAndrew Lunn 	if (chip->info->ops->setup_errata) {
2546ea89098eSAndrew Lunn 		err = chip->info->ops->setup_errata(chip);
2547ea89098eSAndrew Lunn 		if (err)
2548ea89098eSAndrew Lunn 			goto unlock;
2549ea89098eSAndrew Lunn 	}
2550ea89098eSAndrew Lunn 
25512d2e1dd2SAndrew Lunn 	/* Cache the cmode of each port. */
25522d2e1dd2SAndrew Lunn 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
25532d2e1dd2SAndrew Lunn 		if (chip->info->ops->port_get_cmode) {
25542d2e1dd2SAndrew Lunn 			err = chip->info->ops->port_get_cmode(chip, i, &cmode);
25552d2e1dd2SAndrew Lunn 			if (err)
2556e29129fcSDan Carpenter 				goto unlock;
25572d2e1dd2SAndrew Lunn 
25582d2e1dd2SAndrew Lunn 			chip->ports[i].cmode = cmode;
25592d2e1dd2SAndrew Lunn 		}
25602d2e1dd2SAndrew Lunn 	}
25612d2e1dd2SAndrew Lunn 
25629729934cSVivien Didelot 	/* Setup Switch Port Registers */
2563370b4ffbSVivien Didelot 	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
256491dee144SVivien Didelot 		if (dsa_is_unused_port(ds, i))
256591dee144SVivien Didelot 			continue;
256691dee144SVivien Didelot 
25679729934cSVivien Didelot 		err = mv88e6xxx_setup_port(chip, i);
25689729934cSVivien Didelot 		if (err)
25699729934cSVivien Didelot 			goto unlock;
25709729934cSVivien Didelot 	}
25719729934cSVivien Didelot 
2572cd8da8bbSVivien Didelot 	err = mv88e6xxx_irl_setup(chip);
2573cd8da8bbSVivien Didelot 	if (err)
2574cd8da8bbSVivien Didelot 		goto unlock;
2575cd8da8bbSVivien Didelot 
257604a69a17SVivien Didelot 	err = mv88e6xxx_mac_setup(chip);
257704a69a17SVivien Didelot 	if (err)
257804a69a17SVivien Didelot 		goto unlock;
257904a69a17SVivien Didelot 
25801b17aedfSVivien Didelot 	err = mv88e6xxx_phy_setup(chip);
25811b17aedfSVivien Didelot 	if (err)
25821b17aedfSVivien Didelot 		goto unlock;
25831b17aedfSVivien Didelot 
2584b486d7c9SVivien Didelot 	err = mv88e6xxx_vtu_setup(chip);
2585b486d7c9SVivien Didelot 	if (err)
2586b486d7c9SVivien Didelot 		goto unlock;
2587b486d7c9SVivien Didelot 
258881228996SVivien Didelot 	err = mv88e6xxx_pvt_setup(chip);
258981228996SVivien Didelot 	if (err)
259081228996SVivien Didelot 		goto unlock;
259181228996SVivien Didelot 
2592a2ac29d2SVivien Didelot 	err = mv88e6xxx_atu_setup(chip);
2593a2ac29d2SVivien Didelot 	if (err)
2594a2ac29d2SVivien Didelot 		goto unlock;
2595a2ac29d2SVivien Didelot 
259687fa886eSAndrew Lunn 	err = mv88e6xxx_broadcast_setup(chip, 0);
259787fa886eSAndrew Lunn 	if (err)
259887fa886eSAndrew Lunn 		goto unlock;
259987fa886eSAndrew Lunn 
26009e907d73SVivien Didelot 	err = mv88e6xxx_pot_setup(chip);
26019e907d73SVivien Didelot 	if (err)
26029e907d73SVivien Didelot 		goto unlock;
26039e907d73SVivien Didelot 
26049e5baf9bSVivien Didelot 	err = mv88e6xxx_rmu_setup(chip);
26059e5baf9bSVivien Didelot 	if (err)
26069e5baf9bSVivien Didelot 		goto unlock;
26079e5baf9bSVivien Didelot 
260851c901a7SVivien Didelot 	err = mv88e6xxx_rsvd2cpu_setup(chip);
26096e55f698SAndrew Lunn 	if (err)
26106e55f698SAndrew Lunn 		goto unlock;
26116e55f698SAndrew Lunn 
2612b28f872dSVivien Didelot 	err = mv88e6xxx_trunk_setup(chip);
2613b28f872dSVivien Didelot 	if (err)
2614b28f872dSVivien Didelot 		goto unlock;
2615b28f872dSVivien Didelot 
2616c7f047b6SVivien Didelot 	err = mv88e6xxx_devmap_setup(chip);
2617c7f047b6SVivien Didelot 	if (err)
2618c7f047b6SVivien Didelot 		goto unlock;
2619c7f047b6SVivien Didelot 
262093e18d61SVivien Didelot 	err = mv88e6xxx_pri_setup(chip);
262193e18d61SVivien Didelot 	if (err)
262293e18d61SVivien Didelot 		goto unlock;
262393e18d61SVivien Didelot 
2624c6fe0ad2SBrandon Streiff 	/* Setup PTP Hardware Clock and timestamping */
26252fa8d3afSBrandon Streiff 	if (chip->info->ptp_support) {
26262fa8d3afSBrandon Streiff 		err = mv88e6xxx_ptp_setup(chip);
26272fa8d3afSBrandon Streiff 		if (err)
26282fa8d3afSBrandon Streiff 			goto unlock;
2629c6fe0ad2SBrandon Streiff 
2630c6fe0ad2SBrandon Streiff 		err = mv88e6xxx_hwtstamp_setup(chip);
2631c6fe0ad2SBrandon Streiff 		if (err)
2632c6fe0ad2SBrandon Streiff 			goto unlock;
26332fa8d3afSBrandon Streiff 	}
26342fa8d3afSBrandon Streiff 
2635447b1bb8SVivien Didelot 	err = mv88e6xxx_stats_setup(chip);
2636447b1bb8SVivien Didelot 	if (err)
2637447b1bb8SVivien Didelot 		goto unlock;
2638447b1bb8SVivien Didelot 
2639fad09c73SVivien Didelot unlock:
2640fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2641fad09c73SVivien Didelot 
2642fad09c73SVivien Didelot 	return err;
2643fad09c73SVivien Didelot }
2644fad09c73SVivien Didelot 
2645e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
2646fad09c73SVivien Didelot {
26470dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
26480dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
2649e57e5e77SVivien Didelot 	u16 val;
2650e57e5e77SVivien Didelot 	int err;
2651fad09c73SVivien Didelot 
2652ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_read)
2653ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
2654ee26a228SAndrew Lunn 
2655fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
2656ee26a228SAndrew Lunn 	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
2657fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2658e57e5e77SVivien Didelot 
2659da9f3301SAndrew Lunn 	if (reg == MII_PHYSID2) {
2660ddc49acbSAndrew Lunn 		/* Some internal PHYs don't have a model number. */
2661ddc49acbSAndrew Lunn 		if (chip->info->family != MV88E6XXX_FAMILY_6165)
2662ddc49acbSAndrew Lunn 			/* Then there is the 6165 family. It gets is
2663ddc49acbSAndrew Lunn 			 * PHYs correct. But it can also have two
2664ddc49acbSAndrew Lunn 			 * SERDES interfaces in the PHY address
2665ddc49acbSAndrew Lunn 			 * space. And these don't have a model
2666ddc49acbSAndrew Lunn 			 * number. But they are not PHYs, so we don't
2667ddc49acbSAndrew Lunn 			 * want to give them something a PHY driver
2668ddc49acbSAndrew Lunn 			 * will recognise.
2669ddc49acbSAndrew Lunn 			 *
2670ddc49acbSAndrew Lunn 			 * Use the mv88e6390 family model number
2671ddc49acbSAndrew Lunn 			 * instead, for anything which really could be
2672ddc49acbSAndrew Lunn 			 * a PHY,
2673da9f3301SAndrew Lunn 			 */
2674da9f3301SAndrew Lunn 			if (!(val & 0x3f0))
2675107fcc10SVivien Didelot 				val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4;
2676da9f3301SAndrew Lunn 	}
2677da9f3301SAndrew Lunn 
2678e57e5e77SVivien Didelot 	return err ? err : val;
2679fad09c73SVivien Didelot }
2680fad09c73SVivien Didelot 
2681e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
2682fad09c73SVivien Didelot {
26830dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
26840dd12d54SAndrew Lunn 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
2685e57e5e77SVivien Didelot 	int err;
2686fad09c73SVivien Didelot 
2687ee26a228SAndrew Lunn 	if (!chip->info->ops->phy_write)
2688ee26a228SAndrew Lunn 		return -EOPNOTSUPP;
2689ee26a228SAndrew Lunn 
2690fad09c73SVivien Didelot 	mutex_lock(&chip->reg_lock);
2691ee26a228SAndrew Lunn 	err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
2692fad09c73SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2693e57e5e77SVivien Didelot 
2694e57e5e77SVivien Didelot 	return err;
2695fad09c73SVivien Didelot }
2696fad09c73SVivien Didelot 
2697fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
2698a3c53be5SAndrew Lunn 				   struct device_node *np,
2699a3c53be5SAndrew Lunn 				   bool external)
2700fad09c73SVivien Didelot {
2701fad09c73SVivien Didelot 	static int index;
27020dd12d54SAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
2703fad09c73SVivien Didelot 	struct mii_bus *bus;
2704fad09c73SVivien Didelot 	int err;
2705fad09c73SVivien Didelot 
27062510babcSAndrew Lunn 	if (external) {
27072510babcSAndrew Lunn 		mutex_lock(&chip->reg_lock);
27082510babcSAndrew Lunn 		err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
27092510babcSAndrew Lunn 		mutex_unlock(&chip->reg_lock);
27102510babcSAndrew Lunn 
27112510babcSAndrew Lunn 		if (err)
27122510babcSAndrew Lunn 			return err;
27132510babcSAndrew Lunn 	}
27142510babcSAndrew Lunn 
27150dd12d54SAndrew Lunn 	bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
2716fad09c73SVivien Didelot 	if (!bus)
2717fad09c73SVivien Didelot 		return -ENOMEM;
2718fad09c73SVivien Didelot 
27190dd12d54SAndrew Lunn 	mdio_bus = bus->priv;
2720a3c53be5SAndrew Lunn 	mdio_bus->bus = bus;
27210dd12d54SAndrew Lunn 	mdio_bus->chip = chip;
2722a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&mdio_bus->list);
2723a3c53be5SAndrew Lunn 	mdio_bus->external = external;
27240dd12d54SAndrew Lunn 
2725fad09c73SVivien Didelot 	if (np) {
2726fad09c73SVivien Didelot 		bus->name = np->full_name;
2727f7ce9103SRob Herring 		snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np);
2728fad09c73SVivien Didelot 	} else {
2729fad09c73SVivien Didelot 		bus->name = "mv88e6xxx SMI";
2730fad09c73SVivien Didelot 		snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
2731fad09c73SVivien Didelot 	}
2732fad09c73SVivien Didelot 
2733fad09c73SVivien Didelot 	bus->read = mv88e6xxx_mdio_read;
2734fad09c73SVivien Didelot 	bus->write = mv88e6xxx_mdio_write;
2735fad09c73SVivien Didelot 	bus->parent = chip->dev;
2736fad09c73SVivien Didelot 
27376f88284fSAndrew Lunn 	if (!external) {
27386f88284fSAndrew Lunn 		err = mv88e6xxx_g2_irq_mdio_setup(chip, bus);
27396f88284fSAndrew Lunn 		if (err)
27406f88284fSAndrew Lunn 			return err;
27416f88284fSAndrew Lunn 	}
27426f88284fSAndrew Lunn 
2743a3c53be5SAndrew Lunn 	err = of_mdiobus_register(bus, np);
2744fad09c73SVivien Didelot 	if (err) {
2745fad09c73SVivien Didelot 		dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
27466f88284fSAndrew Lunn 		mv88e6xxx_g2_irq_mdio_free(chip, bus);
2747fad09c73SVivien Didelot 		return err;
2748fad09c73SVivien Didelot 	}
2749fad09c73SVivien Didelot 
2750a3c53be5SAndrew Lunn 	if (external)
2751a3c53be5SAndrew Lunn 		list_add_tail(&mdio_bus->list, &chip->mdios);
2752a3c53be5SAndrew Lunn 	else
2753a3c53be5SAndrew Lunn 		list_add(&mdio_bus->list, &chip->mdios);
2754a3c53be5SAndrew Lunn 
2755a3c53be5SAndrew Lunn 	return 0;
2756a3c53be5SAndrew Lunn }
2757a3c53be5SAndrew Lunn 
2758a3c53be5SAndrew Lunn static const struct of_device_id mv88e6xxx_mdio_external_match[] = {
2759a3c53be5SAndrew Lunn 	{ .compatible = "marvell,mv88e6xxx-mdio-external",
2760a3c53be5SAndrew Lunn 	  .data = (void *)true },
2761a3c53be5SAndrew Lunn 	{ },
2762a3c53be5SAndrew Lunn };
2763a3c53be5SAndrew Lunn 
27643126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
27653126aeecSAndrew Lunn 
27663126aeecSAndrew Lunn {
27673126aeecSAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus;
27683126aeecSAndrew Lunn 	struct mii_bus *bus;
27693126aeecSAndrew Lunn 
27703126aeecSAndrew Lunn 	list_for_each_entry(mdio_bus, &chip->mdios, list) {
27713126aeecSAndrew Lunn 		bus = mdio_bus->bus;
27723126aeecSAndrew Lunn 
27736f88284fSAndrew Lunn 		if (!mdio_bus->external)
27746f88284fSAndrew Lunn 			mv88e6xxx_g2_irq_mdio_free(chip, bus);
27756f88284fSAndrew Lunn 
27763126aeecSAndrew Lunn 		mdiobus_unregister(bus);
27773126aeecSAndrew Lunn 	}
27783126aeecSAndrew Lunn }
27793126aeecSAndrew Lunn 
2780a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
2781a3c53be5SAndrew Lunn 				    struct device_node *np)
2782a3c53be5SAndrew Lunn {
2783a3c53be5SAndrew Lunn 	const struct of_device_id *match;
2784a3c53be5SAndrew Lunn 	struct device_node *child;
2785a3c53be5SAndrew Lunn 	int err;
2786a3c53be5SAndrew Lunn 
2787a3c53be5SAndrew Lunn 	/* Always register one mdio bus for the internal/default mdio
2788a3c53be5SAndrew Lunn 	 * bus. This maybe represented in the device tree, but is
2789a3c53be5SAndrew Lunn 	 * optional.
2790a3c53be5SAndrew Lunn 	 */
2791a3c53be5SAndrew Lunn 	child = of_get_child_by_name(np, "mdio");
2792a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdio_register(chip, child, false);
2793a3c53be5SAndrew Lunn 	if (err)
2794a3c53be5SAndrew Lunn 		return err;
2795a3c53be5SAndrew Lunn 
2796a3c53be5SAndrew Lunn 	/* Walk the device tree, and see if there are any other nodes
2797a3c53be5SAndrew Lunn 	 * which say they are compatible with the external mdio
2798a3c53be5SAndrew Lunn 	 * bus.
2799a3c53be5SAndrew Lunn 	 */
2800a3c53be5SAndrew Lunn 	for_each_available_child_of_node(np, child) {
2801a3c53be5SAndrew Lunn 		match = of_match_node(mv88e6xxx_mdio_external_match, child);
2802a3c53be5SAndrew Lunn 		if (match) {
2803a3c53be5SAndrew Lunn 			err = mv88e6xxx_mdio_register(chip, child, true);
28043126aeecSAndrew Lunn 			if (err) {
28053126aeecSAndrew Lunn 				mv88e6xxx_mdios_unregister(chip);
2806a3c53be5SAndrew Lunn 				return err;
2807a3c53be5SAndrew Lunn 			}
2808a3c53be5SAndrew Lunn 		}
28093126aeecSAndrew Lunn 	}
2810a3c53be5SAndrew Lunn 
2811a3c53be5SAndrew Lunn 	return 0;
2812a3c53be5SAndrew Lunn }
2813a3c53be5SAndrew Lunn 
2814855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
2815855b1932SVivien Didelot {
281604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2817855b1932SVivien Didelot 
2818855b1932SVivien Didelot 	return chip->eeprom_len;
2819855b1932SVivien Didelot }
2820855b1932SVivien Didelot 
2821855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
2822855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
2823855b1932SVivien Didelot {
282404bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2825855b1932SVivien Didelot 	int err;
2826855b1932SVivien Didelot 
2827ee4dc2e7SVivien Didelot 	if (!chip->info->ops->get_eeprom)
2828ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
2829ee4dc2e7SVivien Didelot 
2830855b1932SVivien Didelot 	mutex_lock(&chip->reg_lock);
2831ee4dc2e7SVivien Didelot 	err = chip->info->ops->get_eeprom(chip, eeprom, data);
2832855b1932SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2833855b1932SVivien Didelot 
2834855b1932SVivien Didelot 	if (err)
2835855b1932SVivien Didelot 		return err;
2836855b1932SVivien Didelot 
2837855b1932SVivien Didelot 	eeprom->magic = 0xc3ec4951;
2838855b1932SVivien Didelot 
2839855b1932SVivien Didelot 	return 0;
2840855b1932SVivien Didelot }
2841855b1932SVivien Didelot 
2842855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
2843855b1932SVivien Didelot 				struct ethtool_eeprom *eeprom, u8 *data)
2844855b1932SVivien Didelot {
284504bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
2846855b1932SVivien Didelot 	int err;
2847855b1932SVivien Didelot 
2848ee4dc2e7SVivien Didelot 	if (!chip->info->ops->set_eeprom)
2849ee4dc2e7SVivien Didelot 		return -EOPNOTSUPP;
2850ee4dc2e7SVivien Didelot 
2851855b1932SVivien Didelot 	if (eeprom->magic != 0xc3ec4951)
2852855b1932SVivien Didelot 		return -EINVAL;
2853855b1932SVivien Didelot 
2854855b1932SVivien Didelot 	mutex_lock(&chip->reg_lock);
2855ee4dc2e7SVivien Didelot 	err = chip->info->ops->set_eeprom(chip, eeprom, data);
2856855b1932SVivien Didelot 	mutex_unlock(&chip->reg_lock);
2857855b1932SVivien Didelot 
2858855b1932SVivien Didelot 	return err;
2859855b1932SVivien Didelot }
2860855b1932SVivien Didelot 
2861b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = {
28624b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6097 */
286393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
286493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2865cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
2866b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
28677e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
28687e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
286908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
28707f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
287196a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
2872ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
287356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2874601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
287556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
2876ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
28770898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
2878c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
28799dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
28806c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
28812d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
2882a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
288340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2884dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
2885dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
2886052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
2887fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
2888fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
2889fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
289051c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
28919e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
2892a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
2893a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
289417e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
28959e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
2896f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
28970ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
28986c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
2899b3469dd8SVivien Didelot };
2900b3469dd8SVivien Didelot 
2901b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = {
29024b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6095 */
290393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
290493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2905b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
29067e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
29077e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
290808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
29097f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
291096a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
291156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
2912601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
2913a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
29146c422e34SRussell King 	.port_link_state = mv88e6185_port_link_state,
29152d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
2916a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
291740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2918dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
2919dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
2920052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
292151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
2922a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
2923a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
292417e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
2925f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
29260ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
29276c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
2928b3469dd8SVivien Didelot };
2929b3469dd8SVivien Didelot 
29307d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = {
293115da3cc8SStefan Eichenberger 	/* MV88E6XXX_FAMILY_6097 */
293293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
293393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2934cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
29357d381a02SStefan Eichenberger 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
29367d381a02SStefan Eichenberger 	.phy_read = mv88e6xxx_g2_smi_phy_read,
29377d381a02SStefan Eichenberger 	.phy_write = mv88e6xxx_g2_smi_phy_write,
29387d381a02SStefan Eichenberger 	.port_set_link = mv88e6xxx_port_set_link,
29397d381a02SStefan Eichenberger 	.port_set_duplex = mv88e6xxx_port_set_duplex,
29407d381a02SStefan Eichenberger 	.port_set_speed = mv88e6185_port_set_speed,
2941ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
294256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2943601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
294456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
2945cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2946ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
29470898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
2948c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
29499dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
29506c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
29512d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
29527d381a02SStefan Eichenberger 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
295340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
29547d381a02SStefan Eichenberger 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
29557d381a02SStefan Eichenberger 	.stats_get_strings = mv88e6095_stats_get_strings,
29567d381a02SStefan Eichenberger 	.stats_get_stats = mv88e6095_stats_get_stats,
2957fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
2958fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
295991eaa475SVolodymyr Bendiuga 	.watchdog_ops = &mv88e6097_watchdog_ops,
296051c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
29619e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
296217e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
29639e5baf9bSVivien Didelot 	.rmu_disable = mv88e6085_g1_rmu_disable,
2964f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
29650ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
29666c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
29677d381a02SStefan Eichenberger };
29687d381a02SStefan Eichenberger 
2969b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = {
29704b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
297193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
297293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
2973cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
2974b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2975ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
2976ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
297708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
29787f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
297996a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
298056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
2981601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2982c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
29839dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
29846c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
29852d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
29860ac64c39SAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
298740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2988dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
2989dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
2990052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
2991fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
2992fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
2993fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
299451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
29959e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
299617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
2997f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
29980ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
29996c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3000b3469dd8SVivien Didelot };
3001b3469dd8SVivien Didelot 
3002b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = {
30034b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
300493e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
300593e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3006b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
30077e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
30087e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
300908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
30107f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
301196a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3012ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
301356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3014601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
301556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3016a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
3017cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3018ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
30190898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
302054186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
30216c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
30222d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3023a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
302440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3025dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3026dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3027052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3028fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3029fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3030fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
303151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3032a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
303302317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3034a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
303517e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3036f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
30370ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
30386c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3039b3469dd8SVivien Didelot };
3040b3469dd8SVivien Didelot 
3041990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = {
3042990e27b0SVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
304393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
304493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3045cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3046990e27b0SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
3047990e27b0SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3048990e27b0SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3049990e27b0SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3050990e27b0SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
3051990e27b0SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
3052990e27b0SVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3053990e27b0SVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
305426422340SMarek Behún 	.port_set_speed = mv88e6341_port_set_speed,
3055990e27b0SVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
3056990e27b0SVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3057990e27b0SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3058990e27b0SVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3059cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3060990e27b0SVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
30610898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3062990e27b0SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3063990e27b0SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
30646c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
30652d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3066990e27b0SVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
306740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3068990e27b0SVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3069990e27b0SVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
3070990e27b0SVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
3071fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3072fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
3073990e27b0SVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
3074990e27b0SVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
30759e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
3076990e27b0SVivien Didelot 	.reset = mv88e6352_g1_reset,
3077f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
30780ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
30796751e7c6SAndrew Lunn 	.serdes_power = mv88e6341_serdes_power,
3080a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
30816c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
3082990e27b0SVivien Didelot };
3083990e27b0SVivien Didelot 
3084b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = {
30854b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
308693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
308793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3088cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3089b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3090ec8378bbSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3091ec8378bbSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
309208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
30937f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
309496a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3095ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
309656995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3097601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
309856995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3099cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3100ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
31010898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3102c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
31039dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
31046c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
31052d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
31060ac64c39SAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
310740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3108dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3109dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3110052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3111fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3112fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3113fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
311451c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
31159e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
311617e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3117f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
31180ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3119a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3120dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
31216c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3122b3469dd8SVivien Didelot };
3123b3469dd8SVivien Didelot 
3124b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = {
31254b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6165 */
312693e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
312793e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3128cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3129b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3130efb3e74dSAndrew Lunn 	.phy_read = mv88e6165_phy_read,
3131efb3e74dSAndrew Lunn 	.phy_write = mv88e6165_phy_write,
313208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
31337f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
313496a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3135c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
31369dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
31376c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
31382d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3139a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
314040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3141dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3142dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3143052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3144fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3145fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3146fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
314751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
31489e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
314917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3150f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
31510ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3152a469a612SAndrew Lunn 	.avb_ops = &mv88e6165_avb_ops,
3153dfa54348SAndrew Lunn 	.ptp_ops = &mv88e6165_ptp_ops,
31546c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3155b3469dd8SVivien Didelot };
3156b3469dd8SVivien Didelot 
3157b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = {
31584b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
315993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
316093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3161cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3162b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3163b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3164b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
316508ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
31667f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
316794d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
316896a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3169ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
317056995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3171601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
317256995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3173cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3174ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
31750898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3176c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
31779dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
31786c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
31792d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3180a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
318140cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3182dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3183dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3184052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3185fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3186fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3187fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
318851c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
31899e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
319017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3191f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
31920ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
31936c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3194b3469dd8SVivien Didelot };
3195b3469dd8SVivien Didelot 
3196b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = {
31974b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
319893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
319993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3200cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3201ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3202ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3203b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3204b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3205b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
320608ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
32077f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3208a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
320996a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3210ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
321156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3212601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
321356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3214cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3215ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
32160898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3217c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
32189dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
32196c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
32202d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3221a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
322240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3223dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3224dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3225052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3226fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3227fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3228fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
322951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
32309e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
323117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
32329e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
3233f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
32340ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
32356d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
3236a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
32376c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3238b3469dd8SVivien Didelot };
3239b3469dd8SVivien Didelot 
3240b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = {
32414b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
324293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
324393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3244cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3245b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3246b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3247b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
324808ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
32497f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
325094d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
325196a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3252ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
325356995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3254601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
325556995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3256cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3257ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
32580898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3259c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
32609dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
32616c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
32622d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3263a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
326440cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3265dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3266dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3267052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3268fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3269fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3270fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
327151c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
32729e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
327317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3274f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
32750ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
32766c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3277b3469dd8SVivien Didelot };
3278b3469dd8SVivien Didelot 
3279b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = {
32804b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
328193e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
328293e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3283cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3284ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3285ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3286b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3287b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3288b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
328908ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
32907f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3291a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
329296a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3293ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
329456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3295601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
329656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3297cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3298ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
32990898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3300c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
33019dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
33026c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
33032d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3304a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
330540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3306dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3307dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3308052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3309fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3310fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3311fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
331251c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
33139e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
331417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
33159e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
3316f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
33170ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
33186d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
33194382172fSAndrew Lunn 	.serdes_irq_setup = mv88e6352_serdes_irq_setup,
33204382172fSAndrew Lunn 	.serdes_irq_free = mv88e6352_serdes_irq_free,
3321a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
33226c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3323b3469dd8SVivien Didelot };
3324b3469dd8SVivien Didelot 
3325b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = {
33264b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6185 */
332793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
332893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3329b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
33307e20cfb5SVivien Didelot 	.phy_read = mv88e6185_phy_ppu_read,
33317e20cfb5SVivien Didelot 	.phy_write = mv88e6185_phy_ppu_write,
333208ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
33337f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
333496a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
333556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3336601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
3337ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
3338a23b2961SAndrew Lunn 	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
333954186b91SAndrew Lunn 	.port_set_pause = mv88e6185_port_set_pause,
33406c422e34SRussell King 	.port_link_state = mv88e6185_port_link_state,
33412d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6185_port_get_cmode,
3342a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
334340cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3344dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3345dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3346052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3347fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3348fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3349fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
335051c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
335102317e68SVivien Didelot 	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3352a199d8b6SVivien Didelot 	.ppu_enable = mv88e6185_g1_ppu_enable,
3353a199d8b6SVivien Didelot 	.ppu_disable = mv88e6185_g1_ppu_disable,
335417e708baSVivien Didelot 	.reset = mv88e6185_g1_reset,
3355f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
33560ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
33576c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3358b3469dd8SVivien Didelot };
3359b3469dd8SVivien Didelot 
33601a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = {
33614b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3362ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3363cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
336498fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
336598fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
33661a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
33671a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
33681a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
33691a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
33701a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
33711a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
33721a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
3373ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
337456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3375601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
337656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
33770898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3378c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
33799dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
33806c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
33812d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3382fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
338379523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3384de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3385dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3386dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3387e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3388fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3389fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
339061303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
33916e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
33929e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
339317e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
33949e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3395931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3396931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
33976335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
3398efd1ba6aSAndrew Lunn 	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
3399efd1ba6aSAndrew Lunn 	.serdes_irq_free = mv88e6390_serdes_irq_free,
3400a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
34016c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
34021a3b39ecSAndrew Lunn };
34031a3b39ecSAndrew Lunn 
34041a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = {
34054b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3406ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3407cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
340898fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
340998fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
34101a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
34111a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
34121a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
34131a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
34141a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
34151a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
34161a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390x_port_set_speed,
3417ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
341856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3419601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
342056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
34210898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3422c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
34239dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34246c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
34252d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3426fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
342779523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3428de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3429dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3430dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3431e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3432fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3433fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
343461303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
34356e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
34369e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
343717e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
34389e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3439931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3440931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
344107ffbd74SAndrew Lunn 	.serdes_power = mv88e6390x_serdes_power,
34422defda1fSAndrew Lunn 	.serdes_irq_setup = mv88e6390x_serdes_irq_setup,
34432defda1fSAndrew Lunn 	.serdes_irq_free = mv88e6390x_serdes_irq_free,
3444a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
34456c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
34461a3b39ecSAndrew Lunn };
34471a3b39ecSAndrew Lunn 
34481a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = {
34494b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3450ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3451cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
345298fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
345398fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
34541a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
34551a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
34561a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
34571a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
34581a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
34591a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
34601a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
3461ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
346256995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3463601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
346456995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
34650898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3466c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
34679dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
34686c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
34692d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3470fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
347179523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3472de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3473dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3474dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3475e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3476fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3477fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
347861303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
34796e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
34809e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
348117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
34829e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3483931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3484931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
34856335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
3486efd1ba6aSAndrew Lunn 	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
3487efd1ba6aSAndrew Lunn 	.serdes_irq_free = mv88e6390_serdes_irq_free,
34886d2ac8eeSAndrew Lunn 	.avb_ops = &mv88e6390_avb_ops,
34896d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
34906c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
34911a3b39ecSAndrew Lunn };
34921a3b39ecSAndrew Lunn 
3493b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = {
34944b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
349593e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
349693e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3497cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3498ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3499ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3500b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3501b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3502b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
350308ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
35047f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3505a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
350696a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3507ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
350856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3509601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
351056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3511cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3512ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
35130898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3514c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
35159dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35166c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
35172d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3518a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
351940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3520dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3521dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3522052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3523fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3524fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3525fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
352651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
35279e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
352817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
35299e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
3530f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
35310ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
35326d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
35334382172fSAndrew Lunn 	.serdes_irq_setup = mv88e6352_serdes_irq_setup,
35344382172fSAndrew Lunn 	.serdes_irq_free = mv88e6352_serdes_irq_free,
3535a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
35360d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
35376d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
35386c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3539b3469dd8SVivien Didelot };
3540b3469dd8SVivien Didelot 
35411a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = {
35424b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3543ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3544cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
354598fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
354698fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
35471a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
35481a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
35491a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
35501a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
35511a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
35521a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
35531a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
3554ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
355556995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3556601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
355756995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
35580898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3559c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
35609dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
35616c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
35622d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3563fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
356479523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3565de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3566dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3567dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3568e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3569fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3570fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
357161303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
35726e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
35739e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
357417e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
35759e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3576931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3577931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
35786335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
3579efd1ba6aSAndrew Lunn 	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
3580efd1ba6aSAndrew Lunn 	.serdes_irq_free = mv88e6390_serdes_irq_free,
3581a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
35820d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
35836d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
35846c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
35851a3b39ecSAndrew Lunn };
35861a3b39ecSAndrew Lunn 
3587b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = {
35884b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6320 */
358993e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
359093e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3591cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3592ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3593ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3594b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3595b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3596b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
359708ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
35987f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
359996a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3600ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
360156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3602601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
360356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3604cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3605ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36060898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3607c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36089dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36096c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
36102d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3611a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
361240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3613dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3614dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3615052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
3616fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3617fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
36189c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
361951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
36209e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
362117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3622f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
36230ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
3624a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
36250d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
36266d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
36276c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3628b3469dd8SVivien Didelot };
3629b3469dd8SVivien Didelot 
3630b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = {
3631bd807204SVivien Didelot 	/* MV88E6XXX_FAMILY_6320 */
363293e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
363393e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3634cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3635ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3636ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3637b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3638b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3639b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
364008ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
36417f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
364296a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3643ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
364456995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3645601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
364656995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3647cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3648ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36490898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3650c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
36519dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36526c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
36532d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3654a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
365540cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3656dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3657dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3658052f947fSAndrew Lunn 	.stats_get_stats = mv88e6320_stats_get_stats,
3659fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3660fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
36619c7f37e5SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
366217e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3663f1394b78SVivien Didelot 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
36640ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
3665a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
36660d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
36676d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
36686c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3669b3469dd8SVivien Didelot };
3670b3469dd8SVivien Didelot 
367116e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = {
367216e329aeSVivien Didelot 	/* MV88E6XXX_FAMILY_6341 */
367393e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
367493e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3675cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
367616e329aeSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
367716e329aeSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
367816e329aeSVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
367916e329aeSVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
368016e329aeSVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
368116e329aeSVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
368216e329aeSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
368316e329aeSVivien Didelot 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
368426422340SMarek Behún 	.port_set_speed = mv88e6341_port_set_speed,
368516e329aeSVivien Didelot 	.port_tag_remap = mv88e6095_port_tag_remap,
368616e329aeSVivien Didelot 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
368716e329aeSVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
368816e329aeSVivien Didelot 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3689cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
369016e329aeSVivien Didelot 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
36910898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
369216e329aeSVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
369316e329aeSVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
36946c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
36952d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
369616e329aeSVivien Didelot 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
369740cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
369816e329aeSVivien Didelot 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
369916e329aeSVivien Didelot 	.stats_get_strings = mv88e6320_stats_get_strings,
370016e329aeSVivien Didelot 	.stats_get_stats = mv88e6390_stats_get_stats,
3701fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3702fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
370316e329aeSVivien Didelot 	.watchdog_ops = &mv88e6390_watchdog_ops,
370416e329aeSVivien Didelot 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
37059e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
370616e329aeSVivien Didelot 	.reset = mv88e6352_g1_reset,
3707f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37080ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37096751e7c6SAndrew Lunn 	.serdes_power = mv88e6341_serdes_power,
3710a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
37110d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
37126d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
37136c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
371416e329aeSVivien Didelot };
371516e329aeSVivien Didelot 
3716b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = {
37174b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
371893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
371993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3720cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3721b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3722b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3723b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
372408ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
37257f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
372694d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
372796a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3728ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
372956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3730601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
373156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3732cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3733ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37340898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3735c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
37369dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37376c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
37382d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3739a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
374040cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3741dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3742dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3743052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3744fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3745fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3746fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
374751c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
37489e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
374917e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3750f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37510ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37526c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3753b3469dd8SVivien Didelot };
3754b3469dd8SVivien Didelot 
3755b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = {
37564b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6351 */
375793e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
375893e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3759cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3760b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3761b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3762b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
376308ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
37647f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
376594d66ae6SAndrew Lunn 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
376696a2b40cSVivien Didelot 	.port_set_speed = mv88e6185_port_set_speed,
3767ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
376856995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3769601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
377056995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3771cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3772ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
37730898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3774c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
37759dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
37766c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
37772d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3778a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
377940cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3780dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3781dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3782052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3783fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3784fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3785fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
378651c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
37879e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
378817e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
3789f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
37900ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
37910d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
37926d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
37936c422e34SRussell King 	.phylink_validate = mv88e6185_phylink_validate,
3794b3469dd8SVivien Didelot };
3795b3469dd8SVivien Didelot 
3796b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = {
37974b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6352 */
379893e18d61SVivien Didelot 	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
379993e18d61SVivien Didelot 	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3800cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6352_g2_irl_init_all,
3801ee4dc2e7SVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
3802ee4dc2e7SVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3803b073d4e2SVivien Didelot 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3804b3469dd8SVivien Didelot 	.phy_read = mv88e6xxx_g2_smi_phy_read,
3805b3469dd8SVivien Didelot 	.phy_write = mv88e6xxx_g2_smi_phy_write,
380608ef7f10SVivien Didelot 	.port_set_link = mv88e6xxx_port_set_link,
38077f1ae07bSVivien Didelot 	.port_set_duplex = mv88e6xxx_port_set_duplex,
3808a0a0f622SVivien Didelot 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
380996a2b40cSVivien Didelot 	.port_set_speed = mv88e6352_port_set_speed,
3810ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6095_port_tag_remap,
381156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3812601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
381356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3814cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3815ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
38160898432cSVivien Didelot 	.port_pause_limit = mv88e6097_port_pause_limit,
3817c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38189dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38196c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
38202d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3821a605a0feSAndrew Lunn 	.stats_snapshot = mv88e6320_g1_stats_snapshot,
382240cff8fcSAndrew Lunn 	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3823dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
3824dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6095_stats_get_strings,
3825052f947fSAndrew Lunn 	.stats_get_stats = mv88e6095_stats_get_stats,
3826fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
3827fa8d1179SVivien Didelot 	.set_egress_port = mv88e6095_g1_set_egress_port,
3828fcd25166SAndrew Lunn 	.watchdog_ops = &mv88e6097_watchdog_ops,
382951c901a7SVivien Didelot 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
38309e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
383117e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
38329e5baf9bSVivien Didelot 	.rmu_disable = mv88e6352_g1_rmu_disable,
3833f1394b78SVivien Didelot 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
38340ad5daf6SVivien Didelot 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
38356d91782fSAndrew Lunn 	.serdes_power = mv88e6352_serdes_power,
38364382172fSAndrew Lunn 	.serdes_irq_setup = mv88e6352_serdes_irq_setup,
38374382172fSAndrew Lunn 	.serdes_irq_free = mv88e6352_serdes_irq_free,
3838a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
38390d632c3dSBrandon Streiff 	.avb_ops = &mv88e6352_avb_ops,
38406d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
3841cda9f4aaSAndrew Lunn 	.serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
3842cda9f4aaSAndrew Lunn 	.serdes_get_strings = mv88e6352_serdes_get_strings,
3843cda9f4aaSAndrew Lunn 	.serdes_get_stats = mv88e6352_serdes_get_stats,
38446c422e34SRussell King 	.phylink_validate = mv88e6352_phylink_validate,
3845b3469dd8SVivien Didelot };
3846b3469dd8SVivien Didelot 
38471a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = {
38484b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3849ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3850cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
385198fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
385298fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
38531a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
38541a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
38551a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
38561a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
38571a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
38581a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
38591a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390_port_set_speed,
3860ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
386156995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3862601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
386356995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3864cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3865ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
38660898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3867c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
38689dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
38696c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
38702d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3871fdc71eeaSAndrew Lunn 	.port_set_cmode = mv88e6390_port_set_cmode,
387279523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3873de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3874dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3875dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3876e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3877fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3878fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
387961303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
38806e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
38819e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
388217e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
38839e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3884931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3885931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
38866335e9f2SAndrew Lunn 	.serdes_power = mv88e6390_serdes_power,
3887efd1ba6aSAndrew Lunn 	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
3888efd1ba6aSAndrew Lunn 	.serdes_irq_free = mv88e6390_serdes_irq_free,
3889a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
38900d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
38916d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
38926c422e34SRussell King 	.phylink_validate = mv88e6390_phylink_validate,
38931a3b39ecSAndrew Lunn };
38941a3b39ecSAndrew Lunn 
38951a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = {
38964b325d8cSAndrew Lunn 	/* MV88E6XXX_FAMILY_6390 */
3897ea89098eSAndrew Lunn 	.setup_errata = mv88e6390_setup_errata,
3898cd8da8bbSVivien Didelot 	.irl_init_all = mv88e6390_g2_irl_init_all,
389998fc3c6fSVivien Didelot 	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
390098fc3c6fSVivien Didelot 	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
39011a3b39ecSAndrew Lunn 	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
39021a3b39ecSAndrew Lunn 	.phy_read = mv88e6xxx_g2_smi_phy_read,
39031a3b39ecSAndrew Lunn 	.phy_write = mv88e6xxx_g2_smi_phy_write,
39041a3b39ecSAndrew Lunn 	.port_set_link = mv88e6xxx_port_set_link,
39051a3b39ecSAndrew Lunn 	.port_set_duplex = mv88e6xxx_port_set_duplex,
39061a3b39ecSAndrew Lunn 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
39071a3b39ecSAndrew Lunn 	.port_set_speed = mv88e6390x_port_set_speed,
3908ef0a7318SAndrew Lunn 	.port_tag_remap = mv88e6390_port_tag_remap,
390956995cbcSAndrew Lunn 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3910601aeed3SVivien Didelot 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
391156995cbcSAndrew Lunn 	.port_set_ether_type = mv88e6351_port_set_ether_type,
3912cd782656SVivien Didelot 	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3913ef70b111SAndrew Lunn 	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
39140898432cSVivien Didelot 	.port_pause_limit = mv88e6390_port_pause_limit,
3915c8c94891SVivien Didelot 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
39169dbfb4e1SVivien Didelot 	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
39176c422e34SRussell King 	.port_link_state = mv88e6352_port_link_state,
39182d2e1dd2SAndrew Lunn 	.port_get_cmode = mv88e6352_port_get_cmode,
3919b3dce4daSAndrew Lunn 	.port_set_cmode = mv88e6390x_port_set_cmode,
392079523473SAndrew Lunn 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3921de227387SAndrew Lunn 	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3922dfafe449SAndrew Lunn 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
3923dfafe449SAndrew Lunn 	.stats_get_strings = mv88e6320_stats_get_strings,
3924e0d8b615SAndrew Lunn 	.stats_get_stats = mv88e6390_stats_get_stats,
3925fa8d1179SVivien Didelot 	.set_cpu_port = mv88e6390_g1_set_cpu_port,
3926fa8d1179SVivien Didelot 	.set_egress_port = mv88e6390_g1_set_egress_port,
392761303736SAndrew Lunn 	.watchdog_ops = &mv88e6390_watchdog_ops,
39286e55f698SAndrew Lunn 	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
39299e907d73SVivien Didelot 	.pot_clear = mv88e6xxx_g2_pot_clear,
393017e708baSVivien Didelot 	.reset = mv88e6352_g1_reset,
39319e5baf9bSVivien Didelot 	.rmu_disable = mv88e6390_g1_rmu_disable,
3932931d1822SVivien Didelot 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
3933931d1822SVivien Didelot 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
393407ffbd74SAndrew Lunn 	.serdes_power = mv88e6390x_serdes_power,
39352defda1fSAndrew Lunn 	.serdes_irq_setup = mv88e6390x_serdes_irq_setup,
39362defda1fSAndrew Lunn 	.serdes_irq_free = mv88e6390x_serdes_irq_free,
3937a73ccd61SBrandon Streiff 	.gpio_ops = &mv88e6352_gpio_ops,
39380d632c3dSBrandon Streiff 	.avb_ops = &mv88e6390_avb_ops,
39396d2ac8eeSAndrew Lunn 	.ptp_ops = &mv88e6352_ptp_ops,
39406c422e34SRussell King 	.phylink_validate = mv88e6390x_phylink_validate,
39411a3b39ecSAndrew Lunn };
39421a3b39ecSAndrew Lunn 
3943fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3944fad09c73SVivien Didelot 	[MV88E6085] = {
3945107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
3946fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6097,
3947fad09c73SVivien Didelot 		.name = "Marvell 88E6085",
3948fad09c73SVivien Didelot 		.num_databases = 4096,
3949fad09c73SVivien Didelot 		.num_ports = 10,
3950bc393155SAndrew Lunn 		.num_internal_phys = 5,
39513cf3c846SVivien Didelot 		.max_vid = 4095,
3952fad09c73SVivien Didelot 		.port_base_addr = 0x10,
39539255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
3954a935c052SVivien Didelot 		.global1_addr = 0x1b,
39559069c13aSVivien Didelot 		.global2_addr = 0x1c,
3956acddbd21SVivien Didelot 		.age_time_coeff = 15000,
3957dc30c35bSAndrew Lunn 		.g1_irqs = 8,
3958d6c5e6afSVivien Didelot 		.g2_irqs = 10,
3959e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
3960f3645652SVivien Didelot 		.pvt = true,
3961b3e05aa1SVivien Didelot 		.multi_chip = true,
3962443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
3963b3469dd8SVivien Didelot 		.ops = &mv88e6085_ops,
3964fad09c73SVivien Didelot 	},
3965fad09c73SVivien Didelot 
3966fad09c73SVivien Didelot 	[MV88E6095] = {
3967107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095,
3968fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6095,
3969fad09c73SVivien Didelot 		.name = "Marvell 88E6095/88E6095F",
3970fad09c73SVivien Didelot 		.num_databases = 256,
3971fad09c73SVivien Didelot 		.num_ports = 11,
3972bc393155SAndrew Lunn 		.num_internal_phys = 0,
39733cf3c846SVivien Didelot 		.max_vid = 4095,
3974fad09c73SVivien Didelot 		.port_base_addr = 0x10,
39759255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
3976a935c052SVivien Didelot 		.global1_addr = 0x1b,
39779069c13aSVivien Didelot 		.global2_addr = 0x1c,
3978acddbd21SVivien Didelot 		.age_time_coeff = 15000,
3979dc30c35bSAndrew Lunn 		.g1_irqs = 8,
3980e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
3981b3e05aa1SVivien Didelot 		.multi_chip = true,
3982443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
3983b3469dd8SVivien Didelot 		.ops = &mv88e6095_ops,
3984fad09c73SVivien Didelot 	},
3985fad09c73SVivien Didelot 
39867d381a02SStefan Eichenberger 	[MV88E6097] = {
3987107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097,
39887d381a02SStefan Eichenberger 		.family = MV88E6XXX_FAMILY_6097,
39897d381a02SStefan Eichenberger 		.name = "Marvell 88E6097/88E6097F",
39907d381a02SStefan Eichenberger 		.num_databases = 4096,
39917d381a02SStefan Eichenberger 		.num_ports = 11,
3992bc393155SAndrew Lunn 		.num_internal_phys = 8,
39933cf3c846SVivien Didelot 		.max_vid = 4095,
39947d381a02SStefan Eichenberger 		.port_base_addr = 0x10,
39959255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
39967d381a02SStefan Eichenberger 		.global1_addr = 0x1b,
39979069c13aSVivien Didelot 		.global2_addr = 0x1c,
39987d381a02SStefan Eichenberger 		.age_time_coeff = 15000,
3999c534178bSStefan Eichenberger 		.g1_irqs = 8,
4000d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4001e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4002f3645652SVivien Didelot 		.pvt = true,
4003b3e05aa1SVivien Didelot 		.multi_chip = true,
40042bfcfcd3SStefan Eichenberger 		.tag_protocol = DSA_TAG_PROTO_EDSA,
40057d381a02SStefan Eichenberger 		.ops = &mv88e6097_ops,
40067d381a02SStefan Eichenberger 	},
40077d381a02SStefan Eichenberger 
4008fad09c73SVivien Didelot 	[MV88E6123] = {
4009107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123,
4010fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4011fad09c73SVivien Didelot 		.name = "Marvell 88E6123",
4012fad09c73SVivien Didelot 		.num_databases = 4096,
4013fad09c73SVivien Didelot 		.num_ports = 3,
4014bc393155SAndrew Lunn 		.num_internal_phys = 5,
40153cf3c846SVivien Didelot 		.max_vid = 4095,
4016fad09c73SVivien Didelot 		.port_base_addr = 0x10,
40179255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4018a935c052SVivien Didelot 		.global1_addr = 0x1b,
40199069c13aSVivien Didelot 		.global2_addr = 0x1c,
4020acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4021dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4022d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4023e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4024f3645652SVivien Didelot 		.pvt = true,
4025b3e05aa1SVivien Didelot 		.multi_chip = true,
40265ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4027b3469dd8SVivien Didelot 		.ops = &mv88e6123_ops,
4028fad09c73SVivien Didelot 	},
4029fad09c73SVivien Didelot 
4030fad09c73SVivien Didelot 	[MV88E6131] = {
4031107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131,
4032fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
4033fad09c73SVivien Didelot 		.name = "Marvell 88E6131",
4034fad09c73SVivien Didelot 		.num_databases = 256,
4035fad09c73SVivien Didelot 		.num_ports = 8,
4036bc393155SAndrew Lunn 		.num_internal_phys = 0,
40373cf3c846SVivien Didelot 		.max_vid = 4095,
4038fad09c73SVivien Didelot 		.port_base_addr = 0x10,
40399255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4040a935c052SVivien Didelot 		.global1_addr = 0x1b,
40419069c13aSVivien Didelot 		.global2_addr = 0x1c,
4042acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4043dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4044e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4045b3e05aa1SVivien Didelot 		.multi_chip = true,
4046443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4047b3469dd8SVivien Didelot 		.ops = &mv88e6131_ops,
4048fad09c73SVivien Didelot 	},
4049fad09c73SVivien Didelot 
4050990e27b0SVivien Didelot 	[MV88E6141] = {
4051107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141,
4052990e27b0SVivien Didelot 		.family = MV88E6XXX_FAMILY_6341,
405379a68b26SUwe Kleine-König 		.name = "Marvell 88E6141",
4054990e27b0SVivien Didelot 		.num_databases = 4096,
4055990e27b0SVivien Didelot 		.num_ports = 6,
4056bc393155SAndrew Lunn 		.num_internal_phys = 5,
4057a73ccd61SBrandon Streiff 		.num_gpio = 11,
40583cf3c846SVivien Didelot 		.max_vid = 4095,
4059990e27b0SVivien Didelot 		.port_base_addr = 0x10,
40609255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
4061990e27b0SVivien Didelot 		.global1_addr = 0x1b,
40629069c13aSVivien Didelot 		.global2_addr = 0x1c,
4063990e27b0SVivien Didelot 		.age_time_coeff = 3750,
4064990e27b0SVivien Didelot 		.atu_move_port_mask = 0x1f,
4065adfccf11SAndrew Lunn 		.g1_irqs = 9,
4066d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4067f3645652SVivien Didelot 		.pvt = true,
4068b3e05aa1SVivien Didelot 		.multi_chip = true,
4069990e27b0SVivien Didelot 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4070990e27b0SVivien Didelot 		.ops = &mv88e6141_ops,
4071990e27b0SVivien Didelot 	},
4072990e27b0SVivien Didelot 
4073fad09c73SVivien Didelot 	[MV88E6161] = {
4074107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161,
4075fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4076fad09c73SVivien Didelot 		.name = "Marvell 88E6161",
4077fad09c73SVivien Didelot 		.num_databases = 4096,
4078fad09c73SVivien Didelot 		.num_ports = 6,
4079bc393155SAndrew Lunn 		.num_internal_phys = 5,
40803cf3c846SVivien Didelot 		.max_vid = 4095,
4081fad09c73SVivien Didelot 		.port_base_addr = 0x10,
40829255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4083a935c052SVivien Didelot 		.global1_addr = 0x1b,
40849069c13aSVivien Didelot 		.global2_addr = 0x1c,
4085acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4086dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4087d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4088e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4089f3645652SVivien Didelot 		.pvt = true,
4090b3e05aa1SVivien Didelot 		.multi_chip = true,
40915ebe31d7SAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4092dfa54348SAndrew Lunn 		.ptp_support = true,
4093b3469dd8SVivien Didelot 		.ops = &mv88e6161_ops,
4094fad09c73SVivien Didelot 	},
4095fad09c73SVivien Didelot 
4096fad09c73SVivien Didelot 	[MV88E6165] = {
4097107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165,
4098fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6165,
4099fad09c73SVivien Didelot 		.name = "Marvell 88E6165",
4100fad09c73SVivien Didelot 		.num_databases = 4096,
4101fad09c73SVivien Didelot 		.num_ports = 6,
4102bc393155SAndrew Lunn 		.num_internal_phys = 0,
41033cf3c846SVivien Didelot 		.max_vid = 4095,
4104fad09c73SVivien Didelot 		.port_base_addr = 0x10,
41059255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4106a935c052SVivien Didelot 		.global1_addr = 0x1b,
41079069c13aSVivien Didelot 		.global2_addr = 0x1c,
4108acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4109dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4110d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4111e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4112f3645652SVivien Didelot 		.pvt = true,
4113b3e05aa1SVivien Didelot 		.multi_chip = true,
4114443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4115dfa54348SAndrew Lunn 		.ptp_support = true,
4116b3469dd8SVivien Didelot 		.ops = &mv88e6165_ops,
4117fad09c73SVivien Didelot 	},
4118fad09c73SVivien Didelot 
4119fad09c73SVivien Didelot 	[MV88E6171] = {
4120107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171,
4121fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4122fad09c73SVivien Didelot 		.name = "Marvell 88E6171",
4123fad09c73SVivien Didelot 		.num_databases = 4096,
4124fad09c73SVivien Didelot 		.num_ports = 7,
4125bc393155SAndrew Lunn 		.num_internal_phys = 5,
41263cf3c846SVivien Didelot 		.max_vid = 4095,
4127fad09c73SVivien Didelot 		.port_base_addr = 0x10,
41289255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4129a935c052SVivien Didelot 		.global1_addr = 0x1b,
41309069c13aSVivien Didelot 		.global2_addr = 0x1c,
4131acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4132dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4133d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4134e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4135f3645652SVivien Didelot 		.pvt = true,
4136b3e05aa1SVivien Didelot 		.multi_chip = true,
4137443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4138b3469dd8SVivien Didelot 		.ops = &mv88e6171_ops,
4139fad09c73SVivien Didelot 	},
4140fad09c73SVivien Didelot 
4141fad09c73SVivien Didelot 	[MV88E6172] = {
4142107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172,
4143fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4144fad09c73SVivien Didelot 		.name = "Marvell 88E6172",
4145fad09c73SVivien Didelot 		.num_databases = 4096,
4146fad09c73SVivien Didelot 		.num_ports = 7,
4147bc393155SAndrew Lunn 		.num_internal_phys = 5,
4148a73ccd61SBrandon Streiff 		.num_gpio = 15,
41493cf3c846SVivien Didelot 		.max_vid = 4095,
4150fad09c73SVivien Didelot 		.port_base_addr = 0x10,
41519255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4152a935c052SVivien Didelot 		.global1_addr = 0x1b,
41539069c13aSVivien Didelot 		.global2_addr = 0x1c,
4154acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4155dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4156d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4157e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4158f3645652SVivien Didelot 		.pvt = true,
4159b3e05aa1SVivien Didelot 		.multi_chip = true,
4160443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4161b3469dd8SVivien Didelot 		.ops = &mv88e6172_ops,
4162fad09c73SVivien Didelot 	},
4163fad09c73SVivien Didelot 
4164fad09c73SVivien Didelot 	[MV88E6175] = {
4165107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175,
4166fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4167fad09c73SVivien Didelot 		.name = "Marvell 88E6175",
4168fad09c73SVivien Didelot 		.num_databases = 4096,
4169fad09c73SVivien Didelot 		.num_ports = 7,
4170bc393155SAndrew Lunn 		.num_internal_phys = 5,
41713cf3c846SVivien Didelot 		.max_vid = 4095,
4172fad09c73SVivien Didelot 		.port_base_addr = 0x10,
41739255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4174a935c052SVivien Didelot 		.global1_addr = 0x1b,
41759069c13aSVivien Didelot 		.global2_addr = 0x1c,
4176acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4177dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4178d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4179e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4180f3645652SVivien Didelot 		.pvt = true,
4181b3e05aa1SVivien Didelot 		.multi_chip = true,
4182443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4183b3469dd8SVivien Didelot 		.ops = &mv88e6175_ops,
4184fad09c73SVivien Didelot 	},
4185fad09c73SVivien Didelot 
4186fad09c73SVivien Didelot 	[MV88E6176] = {
4187107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176,
4188fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4189fad09c73SVivien Didelot 		.name = "Marvell 88E6176",
4190fad09c73SVivien Didelot 		.num_databases = 4096,
4191fad09c73SVivien Didelot 		.num_ports = 7,
4192bc393155SAndrew Lunn 		.num_internal_phys = 5,
4193a73ccd61SBrandon Streiff 		.num_gpio = 15,
41943cf3c846SVivien Didelot 		.max_vid = 4095,
4195fad09c73SVivien Didelot 		.port_base_addr = 0x10,
41969255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4197a935c052SVivien Didelot 		.global1_addr = 0x1b,
41989069c13aSVivien Didelot 		.global2_addr = 0x1c,
4199acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4200dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4201d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4202e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4203f3645652SVivien Didelot 		.pvt = true,
4204b3e05aa1SVivien Didelot 		.multi_chip = true,
4205443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4206b3469dd8SVivien Didelot 		.ops = &mv88e6176_ops,
4207fad09c73SVivien Didelot 	},
4208fad09c73SVivien Didelot 
4209fad09c73SVivien Didelot 	[MV88E6185] = {
4210107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185,
4211fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6185,
4212fad09c73SVivien Didelot 		.name = "Marvell 88E6185",
4213fad09c73SVivien Didelot 		.num_databases = 256,
4214fad09c73SVivien Didelot 		.num_ports = 10,
4215bc393155SAndrew Lunn 		.num_internal_phys = 0,
42163cf3c846SVivien Didelot 		.max_vid = 4095,
4217fad09c73SVivien Didelot 		.port_base_addr = 0x10,
42189255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4219a935c052SVivien Didelot 		.global1_addr = 0x1b,
42209069c13aSVivien Didelot 		.global2_addr = 0x1c,
4221acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4222dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4223e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4224b3e05aa1SVivien Didelot 		.multi_chip = true,
4225443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4226b3469dd8SVivien Didelot 		.ops = &mv88e6185_ops,
4227fad09c73SVivien Didelot 	},
4228fad09c73SVivien Didelot 
42291a3b39ecSAndrew Lunn 	[MV88E6190] = {
4230107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190,
42311a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
42321a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190",
42331a3b39ecSAndrew Lunn 		.num_databases = 4096,
42341a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
4235bc393155SAndrew Lunn 		.num_internal_phys = 11,
4236a73ccd61SBrandon Streiff 		.num_gpio = 16,
4237931d1822SVivien Didelot 		.max_vid = 8191,
42381a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
42399255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
42401a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
42419069c13aSVivien Didelot 		.global2_addr = 0x1c,
4242443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
4243b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
42441a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4245d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4246f3645652SVivien Didelot 		.pvt = true,
4247b3e05aa1SVivien Didelot 		.multi_chip = true,
4248e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
42491a3b39ecSAndrew Lunn 		.ops = &mv88e6190_ops,
42501a3b39ecSAndrew Lunn 	},
42511a3b39ecSAndrew Lunn 
42521a3b39ecSAndrew Lunn 	[MV88E6190X] = {
4253107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X,
42541a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
42551a3b39ecSAndrew Lunn 		.name = "Marvell 88E6190X",
42561a3b39ecSAndrew Lunn 		.num_databases = 4096,
42571a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
4258bc393155SAndrew Lunn 		.num_internal_phys = 11,
4259a73ccd61SBrandon Streiff 		.num_gpio = 16,
4260931d1822SVivien Didelot 		.max_vid = 8191,
42611a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
42629255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
42631a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
42649069c13aSVivien Didelot 		.global2_addr = 0x1c,
4265b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
42661a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4267d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4268e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4269f3645652SVivien Didelot 		.pvt = true,
4270b3e05aa1SVivien Didelot 		.multi_chip = true,
4271443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
42721a3b39ecSAndrew Lunn 		.ops = &mv88e6190x_ops,
42731a3b39ecSAndrew Lunn 	},
42741a3b39ecSAndrew Lunn 
42751a3b39ecSAndrew Lunn 	[MV88E6191] = {
4276107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191,
42771a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
42781a3b39ecSAndrew Lunn 		.name = "Marvell 88E6191",
42791a3b39ecSAndrew Lunn 		.num_databases = 4096,
42801a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
4281bc393155SAndrew Lunn 		.num_internal_phys = 11,
4282931d1822SVivien Didelot 		.max_vid = 8191,
42831a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
42849255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
42851a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
42869069c13aSVivien Didelot 		.global2_addr = 0x1c,
4287b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
4288443d5a1bSAndrew Lunn 		.g1_irqs = 9,
4289d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4290e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4291f3645652SVivien Didelot 		.pvt = true,
4292b3e05aa1SVivien Didelot 		.multi_chip = true,
4293443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
42942fa8d3afSBrandon Streiff 		.ptp_support = true,
42952cf4cefbSVivien Didelot 		.ops = &mv88e6191_ops,
42961a3b39ecSAndrew Lunn 	},
42971a3b39ecSAndrew Lunn 
4298fad09c73SVivien Didelot 	[MV88E6240] = {
4299107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240,
4300fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4301fad09c73SVivien Didelot 		.name = "Marvell 88E6240",
4302fad09c73SVivien Didelot 		.num_databases = 4096,
4303fad09c73SVivien Didelot 		.num_ports = 7,
4304bc393155SAndrew Lunn 		.num_internal_phys = 5,
4305a73ccd61SBrandon Streiff 		.num_gpio = 15,
43063cf3c846SVivien Didelot 		.max_vid = 4095,
4307fad09c73SVivien Didelot 		.port_base_addr = 0x10,
43089255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4309a935c052SVivien Didelot 		.global1_addr = 0x1b,
43109069c13aSVivien Didelot 		.global2_addr = 0x1c,
4311acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4312dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4313d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4314e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4315f3645652SVivien Didelot 		.pvt = true,
4316b3e05aa1SVivien Didelot 		.multi_chip = true,
4317443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
43182fa8d3afSBrandon Streiff 		.ptp_support = true,
4319b3469dd8SVivien Didelot 		.ops = &mv88e6240_ops,
4320fad09c73SVivien Didelot 	},
4321fad09c73SVivien Didelot 
43221a3b39ecSAndrew Lunn 	[MV88E6290] = {
4323107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
43241a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
43251a3b39ecSAndrew Lunn 		.name = "Marvell 88E6290",
43261a3b39ecSAndrew Lunn 		.num_databases = 4096,
43271a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
4328bc393155SAndrew Lunn 		.num_internal_phys = 11,
4329a73ccd61SBrandon Streiff 		.num_gpio = 16,
4330931d1822SVivien Didelot 		.max_vid = 8191,
43311a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
43329255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
43331a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
43349069c13aSVivien Didelot 		.global2_addr = 0x1c,
4335b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
43361a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4337d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4338e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4339f3645652SVivien Didelot 		.pvt = true,
4340b3e05aa1SVivien Didelot 		.multi_chip = true,
4341443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
43422fa8d3afSBrandon Streiff 		.ptp_support = true,
43431a3b39ecSAndrew Lunn 		.ops = &mv88e6290_ops,
43441a3b39ecSAndrew Lunn 	},
43451a3b39ecSAndrew Lunn 
4346fad09c73SVivien Didelot 	[MV88E6320] = {
4347107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320,
4348fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
4349fad09c73SVivien Didelot 		.name = "Marvell 88E6320",
4350fad09c73SVivien Didelot 		.num_databases = 4096,
4351fad09c73SVivien Didelot 		.num_ports = 7,
4352bc393155SAndrew Lunn 		.num_internal_phys = 5,
4353a73ccd61SBrandon Streiff 		.num_gpio = 15,
43543cf3c846SVivien Didelot 		.max_vid = 4095,
4355fad09c73SVivien Didelot 		.port_base_addr = 0x10,
43569255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4357a935c052SVivien Didelot 		.global1_addr = 0x1b,
43589069c13aSVivien Didelot 		.global2_addr = 0x1c,
4359acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4360dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4361bc393155SAndrew Lunn 		.g2_irqs = 10,
4362e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4363f3645652SVivien Didelot 		.pvt = true,
4364b3e05aa1SVivien Didelot 		.multi_chip = true,
4365443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
43662fa8d3afSBrandon Streiff 		.ptp_support = true,
4367b3469dd8SVivien Didelot 		.ops = &mv88e6320_ops,
4368fad09c73SVivien Didelot 	},
4369fad09c73SVivien Didelot 
4370fad09c73SVivien Didelot 	[MV88E6321] = {
4371107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321,
4372fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6320,
4373fad09c73SVivien Didelot 		.name = "Marvell 88E6321",
4374fad09c73SVivien Didelot 		.num_databases = 4096,
4375fad09c73SVivien Didelot 		.num_ports = 7,
4376bc393155SAndrew Lunn 		.num_internal_phys = 5,
4377a73ccd61SBrandon Streiff 		.num_gpio = 15,
43783cf3c846SVivien Didelot 		.max_vid = 4095,
4379fad09c73SVivien Didelot 		.port_base_addr = 0x10,
43809255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4381a935c052SVivien Didelot 		.global1_addr = 0x1b,
43829069c13aSVivien Didelot 		.global2_addr = 0x1c,
4383acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4384dc30c35bSAndrew Lunn 		.g1_irqs = 8,
4385bc393155SAndrew Lunn 		.g2_irqs = 10,
4386e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4387b3e05aa1SVivien Didelot 		.multi_chip = true,
4388443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
43892fa8d3afSBrandon Streiff 		.ptp_support = true,
4390b3469dd8SVivien Didelot 		.ops = &mv88e6321_ops,
4391fad09c73SVivien Didelot 	},
4392fad09c73SVivien Didelot 
4393a75961d0SGregory CLEMENT 	[MV88E6341] = {
4394107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
4395a75961d0SGregory CLEMENT 		.family = MV88E6XXX_FAMILY_6341,
4396a75961d0SGregory CLEMENT 		.name = "Marvell 88E6341",
4397a75961d0SGregory CLEMENT 		.num_databases = 4096,
4398bc393155SAndrew Lunn 		.num_internal_phys = 5,
4399a75961d0SGregory CLEMENT 		.num_ports = 6,
4400a73ccd61SBrandon Streiff 		.num_gpio = 11,
44013cf3c846SVivien Didelot 		.max_vid = 4095,
4402a75961d0SGregory CLEMENT 		.port_base_addr = 0x10,
44039255bacdSAndrew Lunn 		.phy_base_addr = 0x10,
4404a75961d0SGregory CLEMENT 		.global1_addr = 0x1b,
44059069c13aSVivien Didelot 		.global2_addr = 0x1c,
4406a75961d0SGregory CLEMENT 		.age_time_coeff = 3750,
4407e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4408adfccf11SAndrew Lunn 		.g1_irqs = 9,
4409d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4410f3645652SVivien Didelot 		.pvt = true,
4411b3e05aa1SVivien Didelot 		.multi_chip = true,
4412a75961d0SGregory CLEMENT 		.tag_protocol = DSA_TAG_PROTO_EDSA,
44132fa8d3afSBrandon Streiff 		.ptp_support = true,
4414a75961d0SGregory CLEMENT 		.ops = &mv88e6341_ops,
4415a75961d0SGregory CLEMENT 	},
4416a75961d0SGregory CLEMENT 
4417fad09c73SVivien Didelot 	[MV88E6350] = {
4418107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350,
4419fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4420fad09c73SVivien Didelot 		.name = "Marvell 88E6350",
4421fad09c73SVivien Didelot 		.num_databases = 4096,
4422fad09c73SVivien Didelot 		.num_ports = 7,
4423bc393155SAndrew Lunn 		.num_internal_phys = 5,
44243cf3c846SVivien Didelot 		.max_vid = 4095,
4425fad09c73SVivien Didelot 		.port_base_addr = 0x10,
44269255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4427a935c052SVivien Didelot 		.global1_addr = 0x1b,
44289069c13aSVivien Didelot 		.global2_addr = 0x1c,
4429acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4430dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4431d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4432e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4433f3645652SVivien Didelot 		.pvt = true,
4434b3e05aa1SVivien Didelot 		.multi_chip = true,
4435443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4436b3469dd8SVivien Didelot 		.ops = &mv88e6350_ops,
4437fad09c73SVivien Didelot 	},
4438fad09c73SVivien Didelot 
4439fad09c73SVivien Didelot 	[MV88E6351] = {
4440107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351,
4441fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6351,
4442fad09c73SVivien Didelot 		.name = "Marvell 88E6351",
4443fad09c73SVivien Didelot 		.num_databases = 4096,
4444fad09c73SVivien Didelot 		.num_ports = 7,
4445bc393155SAndrew Lunn 		.num_internal_phys = 5,
44463cf3c846SVivien Didelot 		.max_vid = 4095,
4447fad09c73SVivien Didelot 		.port_base_addr = 0x10,
44489255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4449a935c052SVivien Didelot 		.global1_addr = 0x1b,
44509069c13aSVivien Didelot 		.global2_addr = 0x1c,
4451acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4452dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4453d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4454e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4455f3645652SVivien Didelot 		.pvt = true,
4456b3e05aa1SVivien Didelot 		.multi_chip = true,
4457443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
4458b3469dd8SVivien Didelot 		.ops = &mv88e6351_ops,
4459fad09c73SVivien Didelot 	},
4460fad09c73SVivien Didelot 
4461fad09c73SVivien Didelot 	[MV88E6352] = {
4462107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352,
4463fad09c73SVivien Didelot 		.family = MV88E6XXX_FAMILY_6352,
4464fad09c73SVivien Didelot 		.name = "Marvell 88E6352",
4465fad09c73SVivien Didelot 		.num_databases = 4096,
4466fad09c73SVivien Didelot 		.num_ports = 7,
4467bc393155SAndrew Lunn 		.num_internal_phys = 5,
4468a73ccd61SBrandon Streiff 		.num_gpio = 15,
44693cf3c846SVivien Didelot 		.max_vid = 4095,
4470fad09c73SVivien Didelot 		.port_base_addr = 0x10,
44719255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
4472a935c052SVivien Didelot 		.global1_addr = 0x1b,
44739069c13aSVivien Didelot 		.global2_addr = 0x1c,
4474acddbd21SVivien Didelot 		.age_time_coeff = 15000,
4475dc30c35bSAndrew Lunn 		.g1_irqs = 9,
4476d6c5e6afSVivien Didelot 		.g2_irqs = 10,
4477e606ca36SVivien Didelot 		.atu_move_port_mask = 0xf,
4478f3645652SVivien Didelot 		.pvt = true,
4479b3e05aa1SVivien Didelot 		.multi_chip = true,
4480443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_EDSA,
44812fa8d3afSBrandon Streiff 		.ptp_support = true,
4482b3469dd8SVivien Didelot 		.ops = &mv88e6352_ops,
4483fad09c73SVivien Didelot 	},
44841a3b39ecSAndrew Lunn 	[MV88E6390] = {
4485107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
44861a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
44871a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390",
44881a3b39ecSAndrew Lunn 		.num_databases = 4096,
44891a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
4490bc393155SAndrew Lunn 		.num_internal_phys = 11,
4491a73ccd61SBrandon Streiff 		.num_gpio = 16,
4492931d1822SVivien Didelot 		.max_vid = 8191,
44931a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
44949255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
44951a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
44969069c13aSVivien Didelot 		.global2_addr = 0x1c,
4497b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
44981a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4499d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4500e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4501f3645652SVivien Didelot 		.pvt = true,
4502b3e05aa1SVivien Didelot 		.multi_chip = true,
4503443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
45042fa8d3afSBrandon Streiff 		.ptp_support = true,
45051a3b39ecSAndrew Lunn 		.ops = &mv88e6390_ops,
45061a3b39ecSAndrew Lunn 	},
45071a3b39ecSAndrew Lunn 	[MV88E6390X] = {
4508107fcc10SVivien Didelot 		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X,
45091a3b39ecSAndrew Lunn 		.family = MV88E6XXX_FAMILY_6390,
45101a3b39ecSAndrew Lunn 		.name = "Marvell 88E6390X",
45111a3b39ecSAndrew Lunn 		.num_databases = 4096,
45121a3b39ecSAndrew Lunn 		.num_ports = 11,	/* 10 + Z80 */
4513bc393155SAndrew Lunn 		.num_internal_phys = 11,
4514a73ccd61SBrandon Streiff 		.num_gpio = 16,
4515931d1822SVivien Didelot 		.max_vid = 8191,
45161a3b39ecSAndrew Lunn 		.port_base_addr = 0x0,
45179255bacdSAndrew Lunn 		.phy_base_addr = 0x0,
45181a3b39ecSAndrew Lunn 		.global1_addr = 0x1b,
45199069c13aSVivien Didelot 		.global2_addr = 0x1c,
4520b91e055cSAndrew Lunn 		.age_time_coeff = 3750,
45211a3b39ecSAndrew Lunn 		.g1_irqs = 9,
4522d6c5e6afSVivien Didelot 		.g2_irqs = 14,
4523e606ca36SVivien Didelot 		.atu_move_port_mask = 0x1f,
4524f3645652SVivien Didelot 		.pvt = true,
4525b3e05aa1SVivien Didelot 		.multi_chip = true,
4526443d5a1bSAndrew Lunn 		.tag_protocol = DSA_TAG_PROTO_DSA,
45272fa8d3afSBrandon Streiff 		.ptp_support = true,
45281a3b39ecSAndrew Lunn 		.ops = &mv88e6390x_ops,
45291a3b39ecSAndrew Lunn 	},
4530fad09c73SVivien Didelot };
4531fad09c73SVivien Didelot 
4532fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
4533fad09c73SVivien Didelot {
4534fad09c73SVivien Didelot 	int i;
4535fad09c73SVivien Didelot 
4536fad09c73SVivien Didelot 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
4537fad09c73SVivien Didelot 		if (mv88e6xxx_table[i].prod_num == prod_num)
4538fad09c73SVivien Didelot 			return &mv88e6xxx_table[i];
4539fad09c73SVivien Didelot 
4540fad09c73SVivien Didelot 	return NULL;
4541fad09c73SVivien Didelot }
4542fad09c73SVivien Didelot 
4543fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
4544fad09c73SVivien Didelot {
4545fad09c73SVivien Didelot 	const struct mv88e6xxx_info *info;
45468f6345b2SVivien Didelot 	unsigned int prod_num, rev;
45478f6345b2SVivien Didelot 	u16 id;
45488f6345b2SVivien Didelot 	int err;
4549fad09c73SVivien Didelot 
45508f6345b2SVivien Didelot 	mutex_lock(&chip->reg_lock);
4551107fcc10SVivien Didelot 	err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
45528f6345b2SVivien Didelot 	mutex_unlock(&chip->reg_lock);
45538f6345b2SVivien Didelot 	if (err)
45548f6345b2SVivien Didelot 		return err;
4555fad09c73SVivien Didelot 
4556107fcc10SVivien Didelot 	prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK;
4557107fcc10SVivien Didelot 	rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK;
4558fad09c73SVivien Didelot 
4559fad09c73SVivien Didelot 	info = mv88e6xxx_lookup_info(prod_num);
4560fad09c73SVivien Didelot 	if (!info)
4561fad09c73SVivien Didelot 		return -ENODEV;
4562fad09c73SVivien Didelot 
4563fad09c73SVivien Didelot 	/* Update the compatible info with the probed one */
4564fad09c73SVivien Didelot 	chip->info = info;
4565fad09c73SVivien Didelot 
4566ca070c10SVivien Didelot 	err = mv88e6xxx_g2_require(chip);
4567ca070c10SVivien Didelot 	if (err)
4568ca070c10SVivien Didelot 		return err;
4569ca070c10SVivien Didelot 
4570fad09c73SVivien Didelot 	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
4571fad09c73SVivien Didelot 		 chip->info->prod_num, chip->info->name, rev);
4572fad09c73SVivien Didelot 
4573fad09c73SVivien Didelot 	return 0;
4574fad09c73SVivien Didelot }
4575fad09c73SVivien Didelot 
4576fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
4577fad09c73SVivien Didelot {
4578fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
4579fad09c73SVivien Didelot 
4580fad09c73SVivien Didelot 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
4581fad09c73SVivien Didelot 	if (!chip)
4582fad09c73SVivien Didelot 		return NULL;
4583fad09c73SVivien Didelot 
4584fad09c73SVivien Didelot 	chip->dev = dev;
4585fad09c73SVivien Didelot 
4586fad09c73SVivien Didelot 	mutex_init(&chip->reg_lock);
4587a3c53be5SAndrew Lunn 	INIT_LIST_HEAD(&chip->mdios);
4588fad09c73SVivien Didelot 
4589fad09c73SVivien Didelot 	return chip;
4590fad09c73SVivien Didelot }
4591fad09c73SVivien Didelot 
4592fad09c73SVivien Didelot static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
4593fad09c73SVivien Didelot 			      struct mii_bus *bus, int sw_addr)
4594fad09c73SVivien Didelot {
4595fad09c73SVivien Didelot 	if (sw_addr == 0)
4596fad09c73SVivien Didelot 		chip->smi_ops = &mv88e6xxx_smi_single_chip_ops;
4597b3e05aa1SVivien Didelot 	else if (chip->info->multi_chip)
4598fad09c73SVivien Didelot 		chip->smi_ops = &mv88e6xxx_smi_multi_chip_ops;
4599fad09c73SVivien Didelot 	else
4600fad09c73SVivien Didelot 		return -EINVAL;
4601fad09c73SVivien Didelot 
4602fad09c73SVivien Didelot 	chip->bus = bus;
4603fad09c73SVivien Didelot 	chip->sw_addr = sw_addr;
4604fad09c73SVivien Didelot 
4605fad09c73SVivien Didelot 	return 0;
4606fad09c73SVivien Didelot }
4607fad09c73SVivien Didelot 
46085ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
46095ed4e3ebSFlorian Fainelli 							int port)
46107b314362SAndrew Lunn {
461104bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
46122bbb33beSAndrew Lunn 
4613443d5a1bSAndrew Lunn 	return chip->info->tag_protocol;
46147b314362SAndrew Lunn }
46157b314362SAndrew Lunn 
46162a93c1a3SFlorian Fainelli #if IS_ENABLED(CONFIG_NET_DSA_LEGACY)
4617fad09c73SVivien Didelot static const char *mv88e6xxx_drv_probe(struct device *dsa_dev,
4618fad09c73SVivien Didelot 				       struct device *host_dev, int sw_addr,
4619fad09c73SVivien Didelot 				       void **priv)
4620fad09c73SVivien Didelot {
4621fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
4622fad09c73SVivien Didelot 	struct mii_bus *bus;
4623fad09c73SVivien Didelot 	int err;
4624fad09c73SVivien Didelot 
4625fad09c73SVivien Didelot 	bus = dsa_host_dev_to_mii_bus(host_dev);
4626fad09c73SVivien Didelot 	if (!bus)
4627fad09c73SVivien Didelot 		return NULL;
4628fad09c73SVivien Didelot 
4629fad09c73SVivien Didelot 	chip = mv88e6xxx_alloc_chip(dsa_dev);
4630fad09c73SVivien Didelot 	if (!chip)
4631fad09c73SVivien Didelot 		return NULL;
4632fad09c73SVivien Didelot 
4633fad09c73SVivien Didelot 	/* Legacy SMI probing will only support chips similar to 88E6085 */
4634fad09c73SVivien Didelot 	chip->info = &mv88e6xxx_table[MV88E6085];
4635fad09c73SVivien Didelot 
4636fad09c73SVivien Didelot 	err = mv88e6xxx_smi_init(chip, bus, sw_addr);
4637fad09c73SVivien Didelot 	if (err)
4638fad09c73SVivien Didelot 		goto free;
4639fad09c73SVivien Didelot 
4640fad09c73SVivien Didelot 	err = mv88e6xxx_detect(chip);
4641fad09c73SVivien Didelot 	if (err)
4642fad09c73SVivien Didelot 		goto free;
4643fad09c73SVivien Didelot 
4644dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
4645dc30c35bSAndrew Lunn 	err = mv88e6xxx_switch_reset(chip);
4646dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
4647dc30c35bSAndrew Lunn 	if (err)
4648dc30c35bSAndrew Lunn 		goto free;
4649dc30c35bSAndrew Lunn 
4650e57e5e77SVivien Didelot 	mv88e6xxx_phy_init(chip);
4651e57e5e77SVivien Didelot 
4652a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdios_register(chip, NULL);
4653fad09c73SVivien Didelot 	if (err)
4654fad09c73SVivien Didelot 		goto free;
4655fad09c73SVivien Didelot 
4656fad09c73SVivien Didelot 	*priv = chip;
4657fad09c73SVivien Didelot 
4658fad09c73SVivien Didelot 	return chip->info->name;
4659fad09c73SVivien Didelot free:
4660fad09c73SVivien Didelot 	devm_kfree(dsa_dev, chip);
4661fad09c73SVivien Didelot 
4662fad09c73SVivien Didelot 	return NULL;
4663fad09c73SVivien Didelot }
46642a93c1a3SFlorian Fainelli #endif
4665fad09c73SVivien Didelot 
46667df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port,
46673709aadcSVivien Didelot 				      const struct switchdev_obj_port_mdb *mdb)
46687df8fbddSVivien Didelot {
46697df8fbddSVivien Didelot 	/* We don't need any dynamic resource from the kernel (yet),
46707df8fbddSVivien Didelot 	 * so skip the prepare phase.
46717df8fbddSVivien Didelot 	 */
46727df8fbddSVivien Didelot 
46737df8fbddSVivien Didelot 	return 0;
46747df8fbddSVivien Didelot }
46757df8fbddSVivien Didelot 
46767df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
46773709aadcSVivien Didelot 				   const struct switchdev_obj_port_mdb *mdb)
46787df8fbddSVivien Didelot {
467904bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
46807df8fbddSVivien Didelot 
46817df8fbddSVivien Didelot 	mutex_lock(&chip->reg_lock);
46827df8fbddSVivien Didelot 	if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
468327c0e600SVivien Didelot 					 MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC))
4684774439e5SVivien Didelot 		dev_err(ds->dev, "p%d: failed to load multicast MAC address\n",
4685774439e5SVivien Didelot 			port);
46867df8fbddSVivien Didelot 	mutex_unlock(&chip->reg_lock);
46877df8fbddSVivien Didelot }
46887df8fbddSVivien Didelot 
46897df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
46907df8fbddSVivien Didelot 				  const struct switchdev_obj_port_mdb *mdb)
46917df8fbddSVivien Didelot {
469204bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
46937df8fbddSVivien Didelot 	int err;
46947df8fbddSVivien Didelot 
46957df8fbddSVivien Didelot 	mutex_lock(&chip->reg_lock);
46967df8fbddSVivien Didelot 	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
469727c0e600SVivien Didelot 					   MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
46987df8fbddSVivien Didelot 	mutex_unlock(&chip->reg_lock);
46997df8fbddSVivien Didelot 
47007df8fbddSVivien Didelot 	return err;
47017df8fbddSVivien Didelot }
47027df8fbddSVivien Didelot 
47034f85901fSRussell King static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
47044f85901fSRussell King 					 bool unicast, bool multicast)
47054f85901fSRussell King {
47064f85901fSRussell King 	struct mv88e6xxx_chip *chip = ds->priv;
47074f85901fSRussell King 	int err = -EOPNOTSUPP;
47084f85901fSRussell King 
47094f85901fSRussell King 	mutex_lock(&chip->reg_lock);
47104f85901fSRussell King 	if (chip->info->ops->port_set_egress_floods)
47114f85901fSRussell King 		err = chip->info->ops->port_set_egress_floods(chip, port,
47124f85901fSRussell King 							      unicast,
47134f85901fSRussell King 							      multicast);
47144f85901fSRussell King 	mutex_unlock(&chip->reg_lock);
47154f85901fSRussell King 
47164f85901fSRussell King 	return err;
47174f85901fSRussell King }
47184f85901fSRussell King 
4719a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
47202a93c1a3SFlorian Fainelli #if IS_ENABLED(CONFIG_NET_DSA_LEGACY)
4721fad09c73SVivien Didelot 	.probe			= mv88e6xxx_drv_probe,
47222a93c1a3SFlorian Fainelli #endif
47237b314362SAndrew Lunn 	.get_tag_protocol	= mv88e6xxx_get_tag_protocol,
4724fad09c73SVivien Didelot 	.setup			= mv88e6xxx_setup,
4725fad09c73SVivien Didelot 	.adjust_link		= mv88e6xxx_adjust_link,
4726c9a2356fSRussell King 	.phylink_validate	= mv88e6xxx_validate,
4727c9a2356fSRussell King 	.phylink_mac_link_state	= mv88e6xxx_link_state,
4728c9a2356fSRussell King 	.phylink_mac_config	= mv88e6xxx_mac_config,
4729c9a2356fSRussell King 	.phylink_mac_link_down	= mv88e6xxx_mac_link_down,
4730c9a2356fSRussell King 	.phylink_mac_link_up	= mv88e6xxx_mac_link_up,
4731fad09c73SVivien Didelot 	.get_strings		= mv88e6xxx_get_strings,
4732fad09c73SVivien Didelot 	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
4733fad09c73SVivien Didelot 	.get_sset_count		= mv88e6xxx_get_sset_count,
473404aca993SAndrew Lunn 	.port_enable		= mv88e6xxx_port_enable,
473504aca993SAndrew Lunn 	.port_disable		= mv88e6xxx_port_disable,
473608f50061SVivien Didelot 	.get_mac_eee		= mv88e6xxx_get_mac_eee,
473708f50061SVivien Didelot 	.set_mac_eee		= mv88e6xxx_set_mac_eee,
4738fad09c73SVivien Didelot 	.get_eeprom_len		= mv88e6xxx_get_eeprom_len,
4739fad09c73SVivien Didelot 	.get_eeprom		= mv88e6xxx_get_eeprom,
4740fad09c73SVivien Didelot 	.set_eeprom		= mv88e6xxx_set_eeprom,
4741fad09c73SVivien Didelot 	.get_regs_len		= mv88e6xxx_get_regs_len,
4742fad09c73SVivien Didelot 	.get_regs		= mv88e6xxx_get_regs,
47432cfcd964SVivien Didelot 	.set_ageing_time	= mv88e6xxx_set_ageing_time,
4744fad09c73SVivien Didelot 	.port_bridge_join	= mv88e6xxx_port_bridge_join,
4745fad09c73SVivien Didelot 	.port_bridge_leave	= mv88e6xxx_port_bridge_leave,
47464f85901fSRussell King 	.port_egress_floods	= mv88e6xxx_port_egress_floods,
4747fad09c73SVivien Didelot 	.port_stp_state_set	= mv88e6xxx_port_stp_state_set,
4748749efcb8SVivien Didelot 	.port_fast_age		= mv88e6xxx_port_fast_age,
4749fad09c73SVivien Didelot 	.port_vlan_filtering	= mv88e6xxx_port_vlan_filtering,
4750fad09c73SVivien Didelot 	.port_vlan_prepare	= mv88e6xxx_port_vlan_prepare,
4751fad09c73SVivien Didelot 	.port_vlan_add		= mv88e6xxx_port_vlan_add,
4752fad09c73SVivien Didelot 	.port_vlan_del		= mv88e6xxx_port_vlan_del,
4753fad09c73SVivien Didelot 	.port_fdb_add           = mv88e6xxx_port_fdb_add,
4754fad09c73SVivien Didelot 	.port_fdb_del           = mv88e6xxx_port_fdb_del,
4755fad09c73SVivien Didelot 	.port_fdb_dump          = mv88e6xxx_port_fdb_dump,
47567df8fbddSVivien Didelot 	.port_mdb_prepare       = mv88e6xxx_port_mdb_prepare,
47577df8fbddSVivien Didelot 	.port_mdb_add           = mv88e6xxx_port_mdb_add,
47587df8fbddSVivien Didelot 	.port_mdb_del           = mv88e6xxx_port_mdb_del,
4759aec5ac88SVivien Didelot 	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
4760aec5ac88SVivien Didelot 	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
4761c6fe0ad2SBrandon Streiff 	.port_hwtstamp_set	= mv88e6xxx_port_hwtstamp_set,
4762c6fe0ad2SBrandon Streiff 	.port_hwtstamp_get	= mv88e6xxx_port_hwtstamp_get,
4763c6fe0ad2SBrandon Streiff 	.port_txtstamp		= mv88e6xxx_port_txtstamp,
4764c6fe0ad2SBrandon Streiff 	.port_rxtstamp		= mv88e6xxx_port_rxtstamp,
4765c6fe0ad2SBrandon Streiff 	.get_ts_info		= mv88e6xxx_get_ts_info,
4766fad09c73SVivien Didelot };
4767fad09c73SVivien Didelot 
4768ab3d408dSFlorian Fainelli static struct dsa_switch_driver mv88e6xxx_switch_drv = {
4769ab3d408dSFlorian Fainelli 	.ops			= &mv88e6xxx_switch_ops,
4770ab3d408dSFlorian Fainelli };
4771ab3d408dSFlorian Fainelli 
477255ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
4773fad09c73SVivien Didelot {
4774fad09c73SVivien Didelot 	struct device *dev = chip->dev;
4775fad09c73SVivien Didelot 	struct dsa_switch *ds;
4776fad09c73SVivien Didelot 
477773b1204dSVivien Didelot 	ds = dsa_switch_alloc(dev, mv88e6xxx_num_ports(chip));
4778fad09c73SVivien Didelot 	if (!ds)
4779fad09c73SVivien Didelot 		return -ENOMEM;
4780fad09c73SVivien Didelot 
4781fad09c73SVivien Didelot 	ds->priv = chip;
4782877b7cb0SAndrew Lunn 	ds->dev = dev;
47839d490b4eSVivien Didelot 	ds->ops = &mv88e6xxx_switch_ops;
47849ff74f24SVivien Didelot 	ds->ageing_time_min = chip->info->age_time_coeff;
47859ff74f24SVivien Didelot 	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
4786fad09c73SVivien Didelot 
4787fad09c73SVivien Didelot 	dev_set_drvdata(dev, ds);
4788fad09c73SVivien Didelot 
478923c9ee49SVivien Didelot 	return dsa_register_switch(ds);
4790fad09c73SVivien Didelot }
4791fad09c73SVivien Didelot 
4792fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
4793fad09c73SVivien Didelot {
4794fad09c73SVivien Didelot 	dsa_unregister_switch(chip->ds);
4795fad09c73SVivien Didelot }
4796fad09c73SVivien Didelot 
4797877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev)
4798877b7cb0SAndrew Lunn {
4799877b7cb0SAndrew Lunn 	const struct of_device_id *matches = dev->driver->of_match_table;
4800877b7cb0SAndrew Lunn 	const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data;
4801877b7cb0SAndrew Lunn 
4802877b7cb0SAndrew Lunn 	for (; matches->name[0] || matches->type[0] || matches->compatible[0];
4803877b7cb0SAndrew Lunn 	     matches++) {
4804877b7cb0SAndrew Lunn 		if (!strcmp(pdata->compatible, matches->compatible))
4805877b7cb0SAndrew Lunn 			return matches->data;
4806877b7cb0SAndrew Lunn 	}
4807877b7cb0SAndrew Lunn 	return NULL;
4808877b7cb0SAndrew Lunn }
4809877b7cb0SAndrew Lunn 
4810bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration
4811bcd3d9d9SMiquel Raynal  * would be lost after a power cycle so prevent it to be suspended.
4812bcd3d9d9SMiquel Raynal  */
4813bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev)
4814bcd3d9d9SMiquel Raynal {
4815bcd3d9d9SMiquel Raynal 	return -EOPNOTSUPP;
4816bcd3d9d9SMiquel Raynal }
4817bcd3d9d9SMiquel Raynal 
4818bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev)
4819bcd3d9d9SMiquel Raynal {
4820bcd3d9d9SMiquel Raynal 	return 0;
4821bcd3d9d9SMiquel Raynal }
4822bcd3d9d9SMiquel Raynal 
4823bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume);
4824bcd3d9d9SMiquel Raynal 
4825fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev)
4826fad09c73SVivien Didelot {
4827877b7cb0SAndrew Lunn 	struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data;
48287ddae24fSDavid S. Miller 	const struct mv88e6xxx_info *compat_info = NULL;
4829fad09c73SVivien Didelot 	struct device *dev = &mdiodev->dev;
4830fad09c73SVivien Didelot 	struct device_node *np = dev->of_node;
4831fad09c73SVivien Didelot 	struct mv88e6xxx_chip *chip;
4832877b7cb0SAndrew Lunn 	int port;
4833fad09c73SVivien Didelot 	int err;
4834fad09c73SVivien Didelot 
48357bb8c996SAndrew Lunn 	if (!np && !pdata)
48367bb8c996SAndrew Lunn 		return -EINVAL;
48377bb8c996SAndrew Lunn 
4838877b7cb0SAndrew Lunn 	if (np)
4839fad09c73SVivien Didelot 		compat_info = of_device_get_match_data(dev);
4840877b7cb0SAndrew Lunn 
4841877b7cb0SAndrew Lunn 	if (pdata) {
4842877b7cb0SAndrew Lunn 		compat_info = pdata_device_get_match_data(dev);
4843877b7cb0SAndrew Lunn 
4844877b7cb0SAndrew Lunn 		if (!pdata->netdev)
4845877b7cb0SAndrew Lunn 			return -EINVAL;
4846877b7cb0SAndrew Lunn 
4847877b7cb0SAndrew Lunn 		for (port = 0; port < DSA_MAX_PORTS; port++) {
4848877b7cb0SAndrew Lunn 			if (!(pdata->enabled_ports & (1 << port)))
4849877b7cb0SAndrew Lunn 				continue;
4850877b7cb0SAndrew Lunn 			if (strcmp(pdata->cd.port_names[port], "cpu"))
4851877b7cb0SAndrew Lunn 				continue;
4852877b7cb0SAndrew Lunn 			pdata->cd.netdev[port] = &pdata->netdev->dev;
4853877b7cb0SAndrew Lunn 			break;
4854877b7cb0SAndrew Lunn 		}
4855877b7cb0SAndrew Lunn 	}
4856877b7cb0SAndrew Lunn 
4857fad09c73SVivien Didelot 	if (!compat_info)
4858fad09c73SVivien Didelot 		return -EINVAL;
4859fad09c73SVivien Didelot 
4860fad09c73SVivien Didelot 	chip = mv88e6xxx_alloc_chip(dev);
4861877b7cb0SAndrew Lunn 	if (!chip) {
4862877b7cb0SAndrew Lunn 		err = -ENOMEM;
4863877b7cb0SAndrew Lunn 		goto out;
4864877b7cb0SAndrew Lunn 	}
4865fad09c73SVivien Didelot 
4866fad09c73SVivien Didelot 	chip->info = compat_info;
4867fad09c73SVivien Didelot 
4868fad09c73SVivien Didelot 	err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
4869fad09c73SVivien Didelot 	if (err)
4870877b7cb0SAndrew Lunn 		goto out;
4871fad09c73SVivien Didelot 
4872b4308f04SAndrew Lunn 	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
4873877b7cb0SAndrew Lunn 	if (IS_ERR(chip->reset)) {
4874877b7cb0SAndrew Lunn 		err = PTR_ERR(chip->reset);
4875877b7cb0SAndrew Lunn 		goto out;
4876877b7cb0SAndrew Lunn 	}
4877b4308f04SAndrew Lunn 
4878fad09c73SVivien Didelot 	err = mv88e6xxx_detect(chip);
4879fad09c73SVivien Didelot 	if (err)
4880877b7cb0SAndrew Lunn 		goto out;
4881fad09c73SVivien Didelot 
4882e57e5e77SVivien Didelot 	mv88e6xxx_phy_init(chip);
4883e57e5e77SVivien Didelot 
488400baabe5SAndrew Lunn 	if (chip->info->ops->get_eeprom) {
488500baabe5SAndrew Lunn 		if (np)
488600baabe5SAndrew Lunn 			of_property_read_u32(np, "eeprom-length",
488700baabe5SAndrew Lunn 					     &chip->eeprom_len);
488800baabe5SAndrew Lunn 		else
488900baabe5SAndrew Lunn 			chip->eeprom_len = pdata->eeprom_len;
489000baabe5SAndrew Lunn 	}
4891fad09c73SVivien Didelot 
4892dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
4893dc30c35bSAndrew Lunn 	err = mv88e6xxx_switch_reset(chip);
4894dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
4895fad09c73SVivien Didelot 	if (err)
4896dc30c35bSAndrew Lunn 		goto out;
4897fad09c73SVivien Didelot 
4898dc30c35bSAndrew Lunn 	chip->irq = of_irq_get(np, 0);
4899dc30c35bSAndrew Lunn 	if (chip->irq == -EPROBE_DEFER) {
4900dc30c35bSAndrew Lunn 		err = chip->irq;
4901dc30c35bSAndrew Lunn 		goto out;
4902fad09c73SVivien Didelot 	}
4903fad09c73SVivien Didelot 
4904294d711eSAndrew Lunn 	/* Has to be performed before the MDIO bus is created, because
4905a708767eSUwe Kleine-König 	 * the PHYs will link their interrupts to these interrupt
4906294d711eSAndrew Lunn 	 * controllers
4907dc30c35bSAndrew Lunn 	 */
4908dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
4909294d711eSAndrew Lunn 	if (chip->irq > 0)
4910dc30c35bSAndrew Lunn 		err = mv88e6xxx_g1_irq_setup(chip);
4911294d711eSAndrew Lunn 	else
4912294d711eSAndrew Lunn 		err = mv88e6xxx_irq_poll_setup(chip);
4913dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
4914dc30c35bSAndrew Lunn 
4915dc30c35bSAndrew Lunn 	if (err)
4916dc30c35bSAndrew Lunn 		goto out;
4917dc30c35bSAndrew Lunn 
4918d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0) {
4919dc30c35bSAndrew Lunn 		err = mv88e6xxx_g2_irq_setup(chip);
4920dc30c35bSAndrew Lunn 		if (err)
4921dc30c35bSAndrew Lunn 			goto out_g1_irq;
4922dc30c35bSAndrew Lunn 	}
49230977644cSAndrew Lunn 
49240977644cSAndrew Lunn 	err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
49250977644cSAndrew Lunn 	if (err)
49260977644cSAndrew Lunn 		goto out_g2_irq;
492762eb1162SAndrew Lunn 
492862eb1162SAndrew Lunn 	err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
492962eb1162SAndrew Lunn 	if (err)
493062eb1162SAndrew Lunn 		goto out_g1_atu_prob_irq;
4931dc30c35bSAndrew Lunn 
4932a3c53be5SAndrew Lunn 	err = mv88e6xxx_mdios_register(chip, np);
4933dc30c35bSAndrew Lunn 	if (err)
493462eb1162SAndrew Lunn 		goto out_g1_vtu_prob_irq;
4935dc30c35bSAndrew Lunn 
493655ed0ce0SFlorian Fainelli 	err = mv88e6xxx_register_switch(chip);
4937dc30c35bSAndrew Lunn 	if (err)
4938dc30c35bSAndrew Lunn 		goto out_mdio;
4939dc30c35bSAndrew Lunn 
4940fad09c73SVivien Didelot 	return 0;
4941dc30c35bSAndrew Lunn 
4942dc30c35bSAndrew Lunn out_mdio:
4943a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
494462eb1162SAndrew Lunn out_g1_vtu_prob_irq:
494562eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
49460977644cSAndrew Lunn out_g1_atu_prob_irq:
49470977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
4948dc30c35bSAndrew Lunn out_g2_irq:
4949294d711eSAndrew Lunn 	if (chip->info->g2_irqs > 0)
4950dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
4951dc30c35bSAndrew Lunn out_g1_irq:
4952294d711eSAndrew Lunn 	if (chip->irq > 0)
4953dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
4954294d711eSAndrew Lunn 	else
4955294d711eSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
4956dc30c35bSAndrew Lunn out:
4957877b7cb0SAndrew Lunn 	if (pdata)
4958877b7cb0SAndrew Lunn 		dev_put(pdata->netdev);
4959877b7cb0SAndrew Lunn 
4960dc30c35bSAndrew Lunn 	return err;
4961fad09c73SVivien Didelot }
4962fad09c73SVivien Didelot 
4963fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev)
4964fad09c73SVivien Didelot {
4965fad09c73SVivien Didelot 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
496604bed143SVivien Didelot 	struct mv88e6xxx_chip *chip = ds->priv;
4967fad09c73SVivien Didelot 
4968c6fe0ad2SBrandon Streiff 	if (chip->info->ptp_support) {
4969c6fe0ad2SBrandon Streiff 		mv88e6xxx_hwtstamp_free(chip);
49702fa8d3afSBrandon Streiff 		mv88e6xxx_ptp_free(chip);
4971c6fe0ad2SBrandon Streiff 	}
49722fa8d3afSBrandon Streiff 
4973930188ceSAndrew Lunn 	mv88e6xxx_phy_destroy(chip);
4974fad09c73SVivien Didelot 	mv88e6xxx_unregister_switch(chip);
4975a3c53be5SAndrew Lunn 	mv88e6xxx_mdios_unregister(chip);
4976dc30c35bSAndrew Lunn 
497762eb1162SAndrew Lunn 	mv88e6xxx_g1_vtu_prob_irq_free(chip);
49780977644cSAndrew Lunn 	mv88e6xxx_g1_atu_prob_irq_free(chip);
497976f38f1fSAndrew Lunn 
4980d6c5e6afSVivien Didelot 	if (chip->info->g2_irqs > 0)
4981dc30c35bSAndrew Lunn 		mv88e6xxx_g2_irq_free(chip);
498276f38f1fSAndrew Lunn 
498376f38f1fSAndrew Lunn 	if (chip->irq > 0)
4984dc30c35bSAndrew Lunn 		mv88e6xxx_g1_irq_free(chip);
498576f38f1fSAndrew Lunn 	else
498676f38f1fSAndrew Lunn 		mv88e6xxx_irq_poll_free(chip);
4987fad09c73SVivien Didelot }
4988fad09c73SVivien Didelot 
4989fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = {
4990fad09c73SVivien Didelot 	{
4991fad09c73SVivien Didelot 		.compatible = "marvell,mv88e6085",
4992fad09c73SVivien Didelot 		.data = &mv88e6xxx_table[MV88E6085],
4993fad09c73SVivien Didelot 	},
49941a3b39ecSAndrew Lunn 	{
49951a3b39ecSAndrew Lunn 		.compatible = "marvell,mv88e6190",
49961a3b39ecSAndrew Lunn 		.data = &mv88e6xxx_table[MV88E6190],
49971a3b39ecSAndrew Lunn 	},
4998fad09c73SVivien Didelot 	{ /* sentinel */ },
4999fad09c73SVivien Didelot };
5000fad09c73SVivien Didelot 
5001fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);
5002fad09c73SVivien Didelot 
5003fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = {
5004fad09c73SVivien Didelot 	.probe	= mv88e6xxx_probe,
5005fad09c73SVivien Didelot 	.remove = mv88e6xxx_remove,
5006fad09c73SVivien Didelot 	.mdiodrv.driver = {
5007fad09c73SVivien Didelot 		.name = "mv88e6085",
5008fad09c73SVivien Didelot 		.of_match_table = mv88e6xxx_of_match,
5009bcd3d9d9SMiquel Raynal 		.pm = &mv88e6xxx_pm_ops,
5010fad09c73SVivien Didelot 	},
5011fad09c73SVivien Didelot };
5012fad09c73SVivien Didelot 
5013fad09c73SVivien Didelot static int __init mv88e6xxx_init(void)
5014fad09c73SVivien Didelot {
5015ab3d408dSFlorian Fainelli 	register_switch_driver(&mv88e6xxx_switch_drv);
5016fad09c73SVivien Didelot 	return mdio_driver_register(&mv88e6xxx_driver);
5017fad09c73SVivien Didelot }
5018fad09c73SVivien Didelot module_init(mv88e6xxx_init);
5019fad09c73SVivien Didelot 
5020fad09c73SVivien Didelot static void __exit mv88e6xxx_cleanup(void)
5021fad09c73SVivien Didelot {
5022fad09c73SVivien Didelot 	mdio_driver_unregister(&mv88e6xxx_driver);
5023ab3d408dSFlorian Fainelli 	unregister_switch_driver(&mv88e6xxx_switch_drv);
5024fad09c73SVivien Didelot }
5025fad09c73SVivien Didelot module_exit(mv88e6xxx_cleanup);
5026fad09c73SVivien Didelot 
5027fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
5028fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
5029fad09c73SVivien Didelot MODULE_LICENSE("GPL");
5030