162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Marvell 88e6xxx Ethernet switch single-chip support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2008 Marvell Semiconductor
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
1062306a36Sopenharmony_ci *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/bitfield.h>
1462306a36Sopenharmony_ci#include <linux/delay.h>
1562306a36Sopenharmony_ci#include <linux/dsa/mv88e6xxx.h>
1662306a36Sopenharmony_ci#include <linux/etherdevice.h>
1762306a36Sopenharmony_ci#include <linux/ethtool.h>
1862306a36Sopenharmony_ci#include <linux/if_bridge.h>
1962306a36Sopenharmony_ci#include <linux/interrupt.h>
2062306a36Sopenharmony_ci#include <linux/irq.h>
2162306a36Sopenharmony_ci#include <linux/irqdomain.h>
2262306a36Sopenharmony_ci#include <linux/jiffies.h>
2362306a36Sopenharmony_ci#include <linux/list.h>
2462306a36Sopenharmony_ci#include <linux/mdio.h>
2562306a36Sopenharmony_ci#include <linux/module.h>
2662306a36Sopenharmony_ci#include <linux/of.h>
2762306a36Sopenharmony_ci#include <linux/of_irq.h>
2862306a36Sopenharmony_ci#include <linux/of_mdio.h>
2962306a36Sopenharmony_ci#include <linux/platform_data/mv88e6xxx.h>
3062306a36Sopenharmony_ci#include <linux/netdevice.h>
3162306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
3262306a36Sopenharmony_ci#include <linux/phylink.h>
3362306a36Sopenharmony_ci#include <net/dsa.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include "chip.h"
3662306a36Sopenharmony_ci#include "devlink.h"
3762306a36Sopenharmony_ci#include "global1.h"
3862306a36Sopenharmony_ci#include "global2.h"
3962306a36Sopenharmony_ci#include "hwtstamp.h"
4062306a36Sopenharmony_ci#include "phy.h"
4162306a36Sopenharmony_ci#include "port.h"
4262306a36Sopenharmony_ci#include "ptp.h"
4362306a36Sopenharmony_ci#include "serdes.h"
4462306a36Sopenharmony_ci#include "smi.h"
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic void assert_reg_lock(struct mv88e6xxx_chip *chip)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	if (unlikely(!mutex_is_locked(&chip->reg_lock))) {
4962306a36Sopenharmony_ci		dev_err(chip->dev, "Switch registers lock not held!\n");
5062306a36Sopenharmony_ci		dump_stack();
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ciint mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	int err;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	assert_reg_lock(chip);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	err = mv88e6xxx_smi_read(chip, addr, reg, val);
6162306a36Sopenharmony_ci	if (err)
6262306a36Sopenharmony_ci		return err;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
6562306a36Sopenharmony_ci		addr, reg, *val);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	return 0;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciint mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	int err;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	assert_reg_lock(chip);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	err = mv88e6xxx_smi_write(chip, addr, reg, val);
7762306a36Sopenharmony_ci	if (err)
7862306a36Sopenharmony_ci		return err;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
8162306a36Sopenharmony_ci		addr, reg, val);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	return 0;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ciint mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg,
8762306a36Sopenharmony_ci			u16 mask, u16 val)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	const unsigned long timeout = jiffies + msecs_to_jiffies(50);
9062306a36Sopenharmony_ci	u16 data;
9162306a36Sopenharmony_ci	int err;
9262306a36Sopenharmony_ci	int i;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	/* There's no bus specific operation to wait for a mask. Even
9562306a36Sopenharmony_ci	 * if the initial poll takes longer than 50ms, always do at
9662306a36Sopenharmony_ci	 * least one more attempt.
9762306a36Sopenharmony_ci	 */
9862306a36Sopenharmony_ci	for (i = 0; time_before(jiffies, timeout) || (i < 2); i++) {
9962306a36Sopenharmony_ci		err = mv88e6xxx_read(chip, addr, reg, &data);
10062306a36Sopenharmony_ci		if (err)
10162306a36Sopenharmony_ci			return err;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci		if ((data & mask) == val)
10462306a36Sopenharmony_ci			return 0;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		if (i < 2)
10762306a36Sopenharmony_ci			cpu_relax();
10862306a36Sopenharmony_ci		else
10962306a36Sopenharmony_ci			usleep_range(1000, 2000);
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	err = mv88e6xxx_read(chip, addr, reg, &data);
11362306a36Sopenharmony_ci	if (err)
11462306a36Sopenharmony_ci		return err;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if ((data & mask) == val)
11762306a36Sopenharmony_ci		return 0;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	dev_err(chip->dev, "Timeout while waiting for switch\n");
12062306a36Sopenharmony_ci	return -ETIMEDOUT;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ciint mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg,
12462306a36Sopenharmony_ci		       int bit, int val)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit),
12762306a36Sopenharmony_ci				   val ? BIT(bit) : 0x0000);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistruct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	struct mv88e6xxx_mdio_bus *mdio_bus;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus,
13562306a36Sopenharmony_ci				    list);
13662306a36Sopenharmony_ci	if (!mdio_bus)
13762306a36Sopenharmony_ci		return NULL;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return mdio_bus->bus;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic void mv88e6xxx_g1_irq_mask(struct irq_data *d)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
14562306a36Sopenharmony_ci	unsigned int n = d->hwirq;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	chip->g1_irq.masked |= (1 << n);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void mv88e6xxx_g1_irq_unmask(struct irq_data *d)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
15362306a36Sopenharmony_ci	unsigned int n = d->hwirq;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	chip->g1_irq.masked &= ~(1 << n);
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	unsigned int nhandled = 0;
16162306a36Sopenharmony_ci	unsigned int sub_irq;
16262306a36Sopenharmony_ci	unsigned int n;
16362306a36Sopenharmony_ci	u16 reg;
16462306a36Sopenharmony_ci	u16 ctl1;
16562306a36Sopenharmony_ci	int err;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
16862306a36Sopenharmony_ci	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
16962306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (err)
17262306a36Sopenharmony_ci		goto out;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	do {
17562306a36Sopenharmony_ci		for (n = 0; n < chip->g1_irq.nirqs; ++n) {
17662306a36Sopenharmony_ci			if (reg & (1 << n)) {
17762306a36Sopenharmony_ci				sub_irq = irq_find_mapping(chip->g1_irq.domain,
17862306a36Sopenharmony_ci							   n);
17962306a36Sopenharmony_ci				handle_nested_irq(sub_irq);
18062306a36Sopenharmony_ci				++nhandled;
18162306a36Sopenharmony_ci			}
18262306a36Sopenharmony_ci		}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci		mv88e6xxx_reg_lock(chip);
18562306a36Sopenharmony_ci		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1);
18662306a36Sopenharmony_ci		if (err)
18762306a36Sopenharmony_ci			goto unlock;
18862306a36Sopenharmony_ci		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
18962306a36Sopenharmony_ciunlock:
19062306a36Sopenharmony_ci		mv88e6xxx_reg_unlock(chip);
19162306a36Sopenharmony_ci		if (err)
19262306a36Sopenharmony_ci			goto out;
19362306a36Sopenharmony_ci		ctl1 &= GENMASK(chip->g1_irq.nirqs, 0);
19462306a36Sopenharmony_ci	} while (reg & ctl1);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ciout:
19762306a36Sopenharmony_ci	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = dev_id;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return mv88e6xxx_g1_irq_thread_work(chip);
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
21762306a36Sopenharmony_ci	u16 mask = GENMASK(chip->g1_irq.nirqs, 0);
21862306a36Sopenharmony_ci	u16 reg;
21962306a36Sopenharmony_ci	int err;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &reg);
22262306a36Sopenharmony_ci	if (err)
22362306a36Sopenharmony_ci		goto out;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	reg &= ~mask;
22662306a36Sopenharmony_ci	reg |= (~chip->g1_irq.masked & mask);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg);
22962306a36Sopenharmony_ci	if (err)
23062306a36Sopenharmony_ci		goto out;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ciout:
23362306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic const struct irq_chip mv88e6xxx_g1_irq_chip = {
23762306a36Sopenharmony_ci	.name			= "mv88e6xxx-g1",
23862306a36Sopenharmony_ci	.irq_mask		= mv88e6xxx_g1_irq_mask,
23962306a36Sopenharmony_ci	.irq_unmask		= mv88e6xxx_g1_irq_unmask,
24062306a36Sopenharmony_ci	.irq_bus_lock		= mv88e6xxx_g1_irq_bus_lock,
24162306a36Sopenharmony_ci	.irq_bus_sync_unlock	= mv88e6xxx_g1_irq_bus_sync_unlock,
24262306a36Sopenharmony_ci};
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d,
24562306a36Sopenharmony_ci				       unsigned int irq,
24662306a36Sopenharmony_ci				       irq_hw_number_t hwirq)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = d->host_data;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	irq_set_chip_data(irq, d->host_data);
25162306a36Sopenharmony_ci	irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq);
25262306a36Sopenharmony_ci	irq_set_noprobe(irq);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return 0;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = {
25862306a36Sopenharmony_ci	.map	= mv88e6xxx_g1_irq_domain_map,
25962306a36Sopenharmony_ci	.xlate	= irq_domain_xlate_twocell,
26062306a36Sopenharmony_ci};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/* To be called with reg_lock held */
26362306a36Sopenharmony_cistatic void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	int irq, virq;
26662306a36Sopenharmony_ci	u16 mask;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
26962306a36Sopenharmony_ci	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
27062306a36Sopenharmony_ci	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	for (irq = 0; irq < chip->g1_irq.nirqs; irq++) {
27362306a36Sopenharmony_ci		virq = irq_find_mapping(chip->g1_irq.domain, irq);
27462306a36Sopenharmony_ci		irq_dispose_mapping(virq);
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	irq_domain_remove(chip->g1_irq.domain);
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	/*
28362306a36Sopenharmony_ci	 * free_irq must be called without reg_lock taken because the irq
28462306a36Sopenharmony_ci	 * handler takes this lock, too.
28562306a36Sopenharmony_ci	 */
28662306a36Sopenharmony_ci	free_irq(chip->irq, chip);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
28962306a36Sopenharmony_ci	mv88e6xxx_g1_irq_free_common(chip);
29062306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	int err, irq, virq;
29662306a36Sopenharmony_ci	u16 reg, mask;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	chip->g1_irq.nirqs = chip->info->g1_irqs;
29962306a36Sopenharmony_ci	chip->g1_irq.domain = irq_domain_add_simple(
30062306a36Sopenharmony_ci		NULL, chip->g1_irq.nirqs, 0,
30162306a36Sopenharmony_ci		&mv88e6xxx_g1_irq_domain_ops, chip);
30262306a36Sopenharmony_ci	if (!chip->g1_irq.domain)
30362306a36Sopenharmony_ci		return -ENOMEM;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	for (irq = 0; irq < chip->g1_irq.nirqs; irq++)
30662306a36Sopenharmony_ci		irq_create_mapping(chip->g1_irq.domain, irq);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	chip->g1_irq.chip = mv88e6xxx_g1_irq_chip;
30962306a36Sopenharmony_ci	chip->g1_irq.masked = ~0;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
31262306a36Sopenharmony_ci	if (err)
31362306a36Sopenharmony_ci		goto out_mapping;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
31862306a36Sopenharmony_ci	if (err)
31962306a36Sopenharmony_ci		goto out_disable;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	/* Reading the interrupt status clears (most of) them */
32262306a36Sopenharmony_ci	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
32362306a36Sopenharmony_ci	if (err)
32462306a36Sopenharmony_ci		goto out_disable;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	return 0;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ciout_disable:
32962306a36Sopenharmony_ci	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
33062306a36Sopenharmony_ci	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ciout_mapping:
33362306a36Sopenharmony_ci	for (irq = 0; irq < 16; irq++) {
33462306a36Sopenharmony_ci		virq = irq_find_mapping(chip->g1_irq.domain, irq);
33562306a36Sopenharmony_ci		irq_dispose_mapping(virq);
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	irq_domain_remove(chip->g1_irq.domain);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	return err;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	static struct lock_class_key lock_key;
34662306a36Sopenharmony_ci	static struct lock_class_key request_key;
34762306a36Sopenharmony_ci	int err;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	err = mv88e6xxx_g1_irq_setup_common(chip);
35062306a36Sopenharmony_ci	if (err)
35162306a36Sopenharmony_ci		return err;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* These lock classes tells lockdep that global 1 irqs are in
35462306a36Sopenharmony_ci	 * a different category than their parent GPIO, so it won't
35562306a36Sopenharmony_ci	 * report false recursion.
35662306a36Sopenharmony_ci	 */
35762306a36Sopenharmony_ci	irq_set_lockdep_class(chip->irq, &lock_key, &request_key);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	snprintf(chip->irq_name, sizeof(chip->irq_name),
36062306a36Sopenharmony_ci		 "mv88e6xxx-%s", dev_name(chip->dev));
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
36362306a36Sopenharmony_ci	err = request_threaded_irq(chip->irq, NULL,
36462306a36Sopenharmony_ci				   mv88e6xxx_g1_irq_thread_fn,
36562306a36Sopenharmony_ci				   IRQF_ONESHOT | IRQF_SHARED,
36662306a36Sopenharmony_ci				   chip->irq_name, chip);
36762306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
36862306a36Sopenharmony_ci	if (err)
36962306a36Sopenharmony_ci		mv88e6xxx_g1_irq_free_common(chip);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	return err;
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_cistatic void mv88e6xxx_irq_poll(struct kthread_work *work)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = container_of(work,
37762306a36Sopenharmony_ci						   struct mv88e6xxx_chip,
37862306a36Sopenharmony_ci						   irq_poll_work.work);
37962306a36Sopenharmony_ci	mv88e6xxx_g1_irq_thread_work(chip);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
38262306a36Sopenharmony_ci				   msecs_to_jiffies(100));
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	int err;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	err = mv88e6xxx_g1_irq_setup_common(chip);
39062306a36Sopenharmony_ci	if (err)
39162306a36Sopenharmony_ci		return err;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	kthread_init_delayed_work(&chip->irq_poll_work,
39462306a36Sopenharmony_ci				  mv88e6xxx_irq_poll);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev));
39762306a36Sopenharmony_ci	if (IS_ERR(chip->kworker))
39862306a36Sopenharmony_ci		return PTR_ERR(chip->kworker);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
40162306a36Sopenharmony_ci				   msecs_to_jiffies(100));
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	return 0;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	kthread_cancel_delayed_work_sync(&chip->irq_poll_work);
40962306a36Sopenharmony_ci	kthread_destroy_worker(chip->kworker);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
41262306a36Sopenharmony_ci	mv88e6xxx_g1_irq_free_common(chip);
41362306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip,
41762306a36Sopenharmony_ci					   int port, phy_interface_t interface)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	int err;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	if (chip->info->ops->port_set_rgmii_delay) {
42262306a36Sopenharmony_ci		err = chip->info->ops->port_set_rgmii_delay(chip, port,
42362306a36Sopenharmony_ci							    interface);
42462306a36Sopenharmony_ci		if (err && err != -EOPNOTSUPP)
42562306a36Sopenharmony_ci			return err;
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	if (chip->info->ops->port_set_cmode) {
42962306a36Sopenharmony_ci		err = chip->info->ops->port_set_cmode(chip, port,
43062306a36Sopenharmony_ci						      interface);
43162306a36Sopenharmony_ci		if (err && err != -EOPNOTSUPP)
43262306a36Sopenharmony_ci			return err;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	return 0;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
43962306a36Sopenharmony_ci				    int link, int speed, int duplex, int pause,
44062306a36Sopenharmony_ci				    phy_interface_t mode)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	int err;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (!chip->info->ops->port_set_link)
44562306a36Sopenharmony_ci		return 0;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	/* Port's MAC control must not be changed unless the link is down */
44862306a36Sopenharmony_ci	err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN);
44962306a36Sopenharmony_ci	if (err)
45062306a36Sopenharmony_ci		return err;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (chip->info->ops->port_set_speed_duplex) {
45362306a36Sopenharmony_ci		err = chip->info->ops->port_set_speed_duplex(chip, port,
45462306a36Sopenharmony_ci							     speed, duplex);
45562306a36Sopenharmony_ci		if (err && err != -EOPNOTSUPP)
45662306a36Sopenharmony_ci			goto restore_link;
45762306a36Sopenharmony_ci	}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	if (chip->info->ops->port_set_pause) {
46062306a36Sopenharmony_ci		err = chip->info->ops->port_set_pause(chip, port, pause);
46162306a36Sopenharmony_ci		if (err)
46262306a36Sopenharmony_ci			goto restore_link;
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	err = mv88e6xxx_port_config_interface(chip, port, mode);
46662306a36Sopenharmony_cirestore_link:
46762306a36Sopenharmony_ci	if (chip->info->ops->port_set_link(chip, port, link))
46862306a36Sopenharmony_ci		dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	return err;
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic int mv88e6xxx_phy_is_internal(struct mv88e6xxx_chip *chip, int port)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	return port >= chip->info->internal_phys_offset &&
47662306a36Sopenharmony_ci		port < chip->info->num_internal_phys +
47762306a36Sopenharmony_ci			chip->info->internal_phys_offset;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	u16 reg;
48362306a36Sopenharmony_ci	int err;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	/* The 88e6250 family does not have the PHY detect bit. Instead,
48662306a36Sopenharmony_ci	 * report whether the port is internal.
48762306a36Sopenharmony_ci	 */
48862306a36Sopenharmony_ci	if (chip->info->family == MV88E6XXX_FAMILY_6250)
48962306a36Sopenharmony_ci		return mv88e6xxx_phy_is_internal(chip, port);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
49262306a36Sopenharmony_ci	if (err) {
49362306a36Sopenharmony_ci		dev_err(chip->dev,
49462306a36Sopenharmony_ci			"p%d: %s: failed to read port status\n",
49562306a36Sopenharmony_ci			port, __func__);
49662306a36Sopenharmony_ci		return err;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	return !!(reg & MV88E6XXX_PORT_STS_PHY_DETECT);
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic const u8 mv88e6185_phy_interface_modes[] = {
50362306a36Sopenharmony_ci	[MV88E6185_PORT_STS_CMODE_GMII_FD]	 = PHY_INTERFACE_MODE_GMII,
50462306a36Sopenharmony_ci	[MV88E6185_PORT_STS_CMODE_MII_100_FD_PS] = PHY_INTERFACE_MODE_MII,
50562306a36Sopenharmony_ci	[MV88E6185_PORT_STS_CMODE_MII_100]	 = PHY_INTERFACE_MODE_MII,
50662306a36Sopenharmony_ci	[MV88E6185_PORT_STS_CMODE_MII_10]	 = PHY_INTERFACE_MODE_MII,
50762306a36Sopenharmony_ci	[MV88E6185_PORT_STS_CMODE_SERDES]	 = PHY_INTERFACE_MODE_1000BASEX,
50862306a36Sopenharmony_ci	[MV88E6185_PORT_STS_CMODE_1000BASE_X]	 = PHY_INTERFACE_MODE_1000BASEX,
50962306a36Sopenharmony_ci	[MV88E6185_PORT_STS_CMODE_PHY]		 = PHY_INTERFACE_MODE_SGMII,
51062306a36Sopenharmony_ci};
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic void mv88e6095_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
51362306a36Sopenharmony_ci				       struct phylink_config *config)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	u8 cmode = chip->ports[port].cmode;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	if (mv88e6xxx_phy_is_internal(chip, port)) {
52062306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
52162306a36Sopenharmony_ci	} else {
52262306a36Sopenharmony_ci		if (cmode < ARRAY_SIZE(mv88e6185_phy_interface_modes) &&
52362306a36Sopenharmony_ci		    mv88e6185_phy_interface_modes[cmode])
52462306a36Sopenharmony_ci			__set_bit(mv88e6185_phy_interface_modes[cmode],
52562306a36Sopenharmony_ci				  config->supported_interfaces);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		config->mac_capabilities |= MAC_1000FD;
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic void mv88e6185_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
53262306a36Sopenharmony_ci				       struct phylink_config *config)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	u8 cmode = chip->ports[port].cmode;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	if (cmode < ARRAY_SIZE(mv88e6185_phy_interface_modes) &&
53762306a36Sopenharmony_ci	    mv88e6185_phy_interface_modes[cmode])
53862306a36Sopenharmony_ci		__set_bit(mv88e6185_phy_interface_modes[cmode],
53962306a36Sopenharmony_ci			  config->supported_interfaces);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
54262306a36Sopenharmony_ci				   MAC_1000FD;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistatic const u8 mv88e6xxx_phy_interface_modes[] = {
54662306a36Sopenharmony_ci	[MV88E6XXX_PORT_STS_CMODE_MII_PHY]	= PHY_INTERFACE_MODE_REVMII,
54762306a36Sopenharmony_ci	[MV88E6XXX_PORT_STS_CMODE_MII]		= PHY_INTERFACE_MODE_MII,
54862306a36Sopenharmony_ci	[MV88E6XXX_PORT_STS_CMODE_GMII]		= PHY_INTERFACE_MODE_GMII,
54962306a36Sopenharmony_ci	[MV88E6XXX_PORT_STS_CMODE_RMII_PHY]	= PHY_INTERFACE_MODE_REVRMII,
55062306a36Sopenharmony_ci	[MV88E6XXX_PORT_STS_CMODE_RMII]		= PHY_INTERFACE_MODE_RMII,
55162306a36Sopenharmony_ci	[MV88E6XXX_PORT_STS_CMODE_100BASEX]	= PHY_INTERFACE_MODE_100BASEX,
55262306a36Sopenharmony_ci	[MV88E6XXX_PORT_STS_CMODE_1000BASEX]	= PHY_INTERFACE_MODE_1000BASEX,
55362306a36Sopenharmony_ci	[MV88E6XXX_PORT_STS_CMODE_SGMII]	= PHY_INTERFACE_MODE_SGMII,
55462306a36Sopenharmony_ci	/* higher interface modes are not needed here, since ports supporting
55562306a36Sopenharmony_ci	 * them are writable, and so the supported interfaces are filled in the
55662306a36Sopenharmony_ci	 * corresponding .phylink_set_interfaces() implementation below
55762306a36Sopenharmony_ci	 */
55862306a36Sopenharmony_ci};
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_cistatic void mv88e6xxx_translate_cmode(u8 cmode, unsigned long *supported)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	if (cmode < ARRAY_SIZE(mv88e6xxx_phy_interface_modes) &&
56362306a36Sopenharmony_ci	    mv88e6xxx_phy_interface_modes[cmode])
56462306a36Sopenharmony_ci		__set_bit(mv88e6xxx_phy_interface_modes[cmode], supported);
56562306a36Sopenharmony_ci	else if (cmode == MV88E6XXX_PORT_STS_CMODE_RGMII)
56662306a36Sopenharmony_ci		phy_interface_set_rgmii(supported);
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic void mv88e6250_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
57062306a36Sopenharmony_ci				       struct phylink_config *config)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	unsigned long *supported = config->supported_interfaces;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/* Translate the default cmode */
57562306a36Sopenharmony_ci	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100;
57862306a36Sopenharmony_ci}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cistatic void mv88e6351_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
58162306a36Sopenharmony_ci				       struct phylink_config *config)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	unsigned long *supported = config->supported_interfaces;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/* Translate the default cmode */
58662306a36Sopenharmony_ci	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
58962306a36Sopenharmony_ci				   MAC_1000FD;
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cistatic int mv88e6352_get_port4_serdes_cmode(struct mv88e6xxx_chip *chip)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	u16 reg, val;
59562306a36Sopenharmony_ci	int err;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	err = mv88e6xxx_port_read(chip, 4, MV88E6XXX_PORT_STS, &reg);
59862306a36Sopenharmony_ci	if (err)
59962306a36Sopenharmony_ci		return err;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	/* If PHY_DETECT is zero, then we are not in auto-media mode */
60262306a36Sopenharmony_ci	if (!(reg & MV88E6XXX_PORT_STS_PHY_DETECT))
60362306a36Sopenharmony_ci		return 0xf;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	val = reg & ~MV88E6XXX_PORT_STS_PHY_DETECT;
60662306a36Sopenharmony_ci	err = mv88e6xxx_port_write(chip, 4, MV88E6XXX_PORT_STS, val);
60762306a36Sopenharmony_ci	if (err)
60862306a36Sopenharmony_ci		return err;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	err = mv88e6xxx_port_read(chip, 4, MV88E6XXX_PORT_STS, &val);
61162306a36Sopenharmony_ci	if (err)
61262306a36Sopenharmony_ci		return err;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	/* Restore PHY_DETECT value */
61562306a36Sopenharmony_ci	err = mv88e6xxx_port_write(chip, 4, MV88E6XXX_PORT_STS, reg);
61662306a36Sopenharmony_ci	if (err)
61762306a36Sopenharmony_ci		return err;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	return val & MV88E6XXX_PORT_STS_CMODE_MASK;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic void mv88e6352_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
62362306a36Sopenharmony_ci				       struct phylink_config *config)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	unsigned long *supported = config->supported_interfaces;
62662306a36Sopenharmony_ci	int err, cmode;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/* Translate the default cmode */
62962306a36Sopenharmony_ci	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
63262306a36Sopenharmony_ci				   MAC_1000FD;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	/* Port 4 supports automedia if the serdes is associated with it. */
63562306a36Sopenharmony_ci	if (port == 4) {
63662306a36Sopenharmony_ci		err = mv88e6352_g2_scratch_port_has_serdes(chip, port);
63762306a36Sopenharmony_ci		if (err < 0)
63862306a36Sopenharmony_ci			dev_err(chip->dev, "p%d: failed to read scratch\n",
63962306a36Sopenharmony_ci				port);
64062306a36Sopenharmony_ci		if (err <= 0)
64162306a36Sopenharmony_ci			return;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci		cmode = mv88e6352_get_port4_serdes_cmode(chip);
64462306a36Sopenharmony_ci		if (cmode < 0)
64562306a36Sopenharmony_ci			dev_err(chip->dev, "p%d: failed to read serdes cmode\n",
64662306a36Sopenharmony_ci				port);
64762306a36Sopenharmony_ci		else
64862306a36Sopenharmony_ci			mv88e6xxx_translate_cmode(cmode, supported);
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_cistatic void mv88e6341_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
65362306a36Sopenharmony_ci				       struct phylink_config *config)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	unsigned long *supported = config->supported_interfaces;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	/* Translate the default cmode */
65862306a36Sopenharmony_ci	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	/* No ethtool bits for 200Mbps */
66162306a36Sopenharmony_ci	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
66262306a36Sopenharmony_ci				   MAC_1000FD;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	/* The C_Mode field is programmable on port 5 */
66562306a36Sopenharmony_ci	if (port == 5) {
66662306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_SGMII, supported);
66762306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
66862306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci		config->mac_capabilities |= MAC_2500FD;
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic void mv88e6390_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
67562306a36Sopenharmony_ci				       struct phylink_config *config)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	unsigned long *supported = config->supported_interfaces;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	/* Translate the default cmode */
68062306a36Sopenharmony_ci	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	/* No ethtool bits for 200Mbps */
68362306a36Sopenharmony_ci	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
68462306a36Sopenharmony_ci				   MAC_1000FD;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	/* The C_Mode field is programmable on ports 9 and 10 */
68762306a36Sopenharmony_ci	if (port == 9 || port == 10) {
68862306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_SGMII, supported);
68962306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
69062306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci		config->mac_capabilities |= MAC_2500FD;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic void mv88e6390x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
69762306a36Sopenharmony_ci					struct phylink_config *config)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	unsigned long *supported = config->supported_interfaces;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	mv88e6390_phylink_get_caps(chip, port, config);
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	/* For the 6x90X, ports 2-7 can be in automedia mode.
70462306a36Sopenharmony_ci	 * (Note that 6x90 doesn't support RXAUI nor XAUI).
70562306a36Sopenharmony_ci	 *
70662306a36Sopenharmony_ci	 * Port 2 can also support 1000BASE-X in automedia mode if port 9 is
70762306a36Sopenharmony_ci	 * configured for 1000BASE-X, SGMII or 2500BASE-X.
70862306a36Sopenharmony_ci	 * Port 3-4 can also support 1000BASE-X in automedia mode if port 9 is
70962306a36Sopenharmony_ci	 * configured for RXAUI, 1000BASE-X, SGMII or 2500BASE-X.
71062306a36Sopenharmony_ci	 *
71162306a36Sopenharmony_ci	 * Port 5 can also support 1000BASE-X in automedia mode if port 10 is
71262306a36Sopenharmony_ci	 * configured for 1000BASE-X, SGMII or 2500BASE-X.
71362306a36Sopenharmony_ci	 * Port 6-7 can also support 1000BASE-X in automedia mode if port 10 is
71462306a36Sopenharmony_ci	 * configured for RXAUI, 1000BASE-X, SGMII or 2500BASE-X.
71562306a36Sopenharmony_ci	 *
71662306a36Sopenharmony_ci	 * For now, be permissive (as the old code was) and allow 1000BASE-X
71762306a36Sopenharmony_ci	 * on ports 2..7.
71862306a36Sopenharmony_ci	 */
71962306a36Sopenharmony_ci	if (port >= 2 && port <= 7)
72062306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	/* The C_Mode field can also be programmed for 10G speeds */
72362306a36Sopenharmony_ci	if (port == 9 || port == 10) {
72462306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_XAUI, supported);
72562306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_RXAUI, supported);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci		config->mac_capabilities |= MAC_10000FD;
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
73262306a36Sopenharmony_ci					struct phylink_config *config)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	unsigned long *supported = config->supported_interfaces;
73562306a36Sopenharmony_ci	bool is_6191x =
73662306a36Sopenharmony_ci		chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X;
73762306a36Sopenharmony_ci	bool is_6361 =
73862306a36Sopenharmony_ci		chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
74362306a36Sopenharmony_ci				   MAC_1000FD;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	/* The C_Mode field can be programmed for ports 0, 9 and 10 */
74662306a36Sopenharmony_ci	if (port == 0 || port == 9 || port == 10) {
74762306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_SGMII, supported);
74862306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci		/* 6191X supports >1G modes only on port 10 */
75162306a36Sopenharmony_ci		if (!is_6191x || port == 10) {
75262306a36Sopenharmony_ci			__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
75362306a36Sopenharmony_ci			config->mac_capabilities |= MAC_2500FD;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci			/* 6361 only supports up to 2500BaseX */
75662306a36Sopenharmony_ci			if (!is_6361) {
75762306a36Sopenharmony_ci				__set_bit(PHY_INTERFACE_MODE_5GBASER, supported);
75862306a36Sopenharmony_ci				__set_bit(PHY_INTERFACE_MODE_10GBASER, supported);
75962306a36Sopenharmony_ci				__set_bit(PHY_INTERFACE_MODE_USXGMII, supported);
76062306a36Sopenharmony_ci				config->mac_capabilities |= MAC_5000FD |
76162306a36Sopenharmony_ci					MAC_10000FD;
76262306a36Sopenharmony_ci			}
76362306a36Sopenharmony_ci		}
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	if (port == 0) {
76762306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_RMII, supported);
76862306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_RGMII, supported);
76962306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_RGMII_ID, supported);
77062306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_RGMII_RXID, supported);
77162306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_RGMII_TXID, supported);
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_cistatic void mv88e6xxx_get_caps(struct dsa_switch *ds, int port,
77662306a36Sopenharmony_ci			       struct phylink_config *config)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
78162306a36Sopenharmony_ci	chip->info->ops->phylink_get_caps(chip, port, config);
78262306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	if (mv88e6xxx_phy_is_internal(chip, port)) {
78562306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_INTERNAL,
78662306a36Sopenharmony_ci			  config->supported_interfaces);
78762306a36Sopenharmony_ci		/* Internal ports with no phy-mode need GMII for PHYLIB */
78862306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_GMII,
78962306a36Sopenharmony_ci			  config->supported_interfaces);
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_cistatic struct phylink_pcs *mv88e6xxx_mac_select_pcs(struct dsa_switch *ds,
79462306a36Sopenharmony_ci						    int port,
79562306a36Sopenharmony_ci						    phy_interface_t interface)
79662306a36Sopenharmony_ci{
79762306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
79862306a36Sopenharmony_ci	struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	if (chip->info->ops->pcs_ops)
80162306a36Sopenharmony_ci		pcs = chip->info->ops->pcs_ops->pcs_select(chip, port,
80262306a36Sopenharmony_ci							   interface);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	return pcs;
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cistatic int mv88e6xxx_mac_prepare(struct dsa_switch *ds, int port,
80862306a36Sopenharmony_ci				 unsigned int mode, phy_interface_t interface)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
81162306a36Sopenharmony_ci	int err = 0;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	/* In inband mode, the link may come up at any time while the link
81462306a36Sopenharmony_ci	 * is not forced down. Force the link down while we reconfigure the
81562306a36Sopenharmony_ci	 * interface mode.
81662306a36Sopenharmony_ci	 */
81762306a36Sopenharmony_ci	if (mode == MLO_AN_INBAND &&
81862306a36Sopenharmony_ci	    chip->ports[port].interface != interface &&
81962306a36Sopenharmony_ci	    chip->info->ops->port_set_link) {
82062306a36Sopenharmony_ci		mv88e6xxx_reg_lock(chip);
82162306a36Sopenharmony_ci		err = chip->info->ops->port_set_link(chip, port,
82262306a36Sopenharmony_ci						     LINK_FORCED_DOWN);
82362306a36Sopenharmony_ci		mv88e6xxx_reg_unlock(chip);
82462306a36Sopenharmony_ci	}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	return err;
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_cistatic void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
83062306a36Sopenharmony_ci				 unsigned int mode,
83162306a36Sopenharmony_ci				 const struct phylink_link_state *state)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
83462306a36Sopenharmony_ci	int err = 0;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	if (mode != MLO_AN_PHY || !mv88e6xxx_phy_is_internal(chip, port)) {
83962306a36Sopenharmony_ci		err = mv88e6xxx_port_config_interface(chip, port,
84062306a36Sopenharmony_ci						      state->interface);
84162306a36Sopenharmony_ci		if (err && err != -EOPNOTSUPP)
84262306a36Sopenharmony_ci			goto err_unlock;
84362306a36Sopenharmony_ci	}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cierr_unlock:
84662306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if (err && err != -EOPNOTSUPP)
84962306a36Sopenharmony_ci		dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port);
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_cistatic int mv88e6xxx_mac_finish(struct dsa_switch *ds, int port,
85362306a36Sopenharmony_ci				unsigned int mode, phy_interface_t interface)
85462306a36Sopenharmony_ci{
85562306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
85662306a36Sopenharmony_ci	int err = 0;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	/* Undo the forced down state above after completing configuration
85962306a36Sopenharmony_ci	 * irrespective of its state on entry, which allows the link to come
86062306a36Sopenharmony_ci	 * up in the in-band case where there is no separate SERDES. Also
86162306a36Sopenharmony_ci	 * ensure that the link can come up if the PPU is in use and we are
86262306a36Sopenharmony_ci	 * in PHY mode (we treat the PPU as an effective in-band mechanism.)
86362306a36Sopenharmony_ci	 */
86462306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	if (chip->info->ops->port_set_link &&
86762306a36Sopenharmony_ci	    ((mode == MLO_AN_INBAND &&
86862306a36Sopenharmony_ci	      chip->ports[port].interface != interface) ||
86962306a36Sopenharmony_ci	     (mode == MLO_AN_PHY && mv88e6xxx_port_ppu_updates(chip, port))))
87062306a36Sopenharmony_ci		err = chip->info->ops->port_set_link(chip, port, LINK_UNFORCED);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	chip->ports[port].interface = interface;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	return err;
87762306a36Sopenharmony_ci}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_cistatic void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
88062306a36Sopenharmony_ci				    unsigned int mode,
88162306a36Sopenharmony_ci				    phy_interface_t interface)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
88462306a36Sopenharmony_ci	const struct mv88e6xxx_ops *ops;
88562306a36Sopenharmony_ci	int err = 0;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	ops = chip->info->ops;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
89062306a36Sopenharmony_ci	/* Force the link down if we know the port may not be automatically
89162306a36Sopenharmony_ci	 * updated by the switch or if we are using fixed-link mode.
89262306a36Sopenharmony_ci	 */
89362306a36Sopenharmony_ci	if ((!mv88e6xxx_port_ppu_updates(chip, port) ||
89462306a36Sopenharmony_ci	     mode == MLO_AN_FIXED) && ops->port_sync_link)
89562306a36Sopenharmony_ci		err = ops->port_sync_link(chip, port, mode, false);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	if (!err && ops->port_set_speed_duplex)
89862306a36Sopenharmony_ci		err = ops->port_set_speed_duplex(chip, port, SPEED_UNFORCED,
89962306a36Sopenharmony_ci						 DUPLEX_UNFORCED);
90062306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	if (err)
90362306a36Sopenharmony_ci		dev_err(chip->dev,
90462306a36Sopenharmony_ci			"p%d: failed to force MAC link down\n", port);
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
90862306a36Sopenharmony_ci				  unsigned int mode, phy_interface_t interface,
90962306a36Sopenharmony_ci				  struct phy_device *phydev,
91062306a36Sopenharmony_ci				  int speed, int duplex,
91162306a36Sopenharmony_ci				  bool tx_pause, bool rx_pause)
91262306a36Sopenharmony_ci{
91362306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
91462306a36Sopenharmony_ci	const struct mv88e6xxx_ops *ops;
91562306a36Sopenharmony_ci	int err = 0;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	ops = chip->info->ops;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
92062306a36Sopenharmony_ci	/* Configure and force the link up if we know that the port may not
92162306a36Sopenharmony_ci	 * automatically updated by the switch or if we are using fixed-link
92262306a36Sopenharmony_ci	 * mode.
92362306a36Sopenharmony_ci	 */
92462306a36Sopenharmony_ci	if (!mv88e6xxx_port_ppu_updates(chip, port) ||
92562306a36Sopenharmony_ci	    mode == MLO_AN_FIXED) {
92662306a36Sopenharmony_ci		if (ops->port_set_speed_duplex) {
92762306a36Sopenharmony_ci			err = ops->port_set_speed_duplex(chip, port,
92862306a36Sopenharmony_ci							 speed, duplex);
92962306a36Sopenharmony_ci			if (err && err != -EOPNOTSUPP)
93062306a36Sopenharmony_ci				goto error;
93162306a36Sopenharmony_ci		}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci		if (ops->port_sync_link)
93462306a36Sopenharmony_ci			err = ops->port_sync_link(chip, port, mode, true);
93562306a36Sopenharmony_ci	}
93662306a36Sopenharmony_cierror:
93762306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	if (err && err != -EOPNOTSUPP)
94062306a36Sopenharmony_ci		dev_err(ds->dev,
94162306a36Sopenharmony_ci			"p%d: failed to configure MAC link up\n", port);
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	if (!chip->info->ops->stats_snapshot)
94762306a36Sopenharmony_ci		return -EOPNOTSUPP;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	return chip->info->ops->stats_snapshot(chip, port);
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_cistatic struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
95362306a36Sopenharmony_ci	{ "in_good_octets",		8, 0x00, STATS_TYPE_BANK0, },
95462306a36Sopenharmony_ci	{ "in_bad_octets",		4, 0x02, STATS_TYPE_BANK0, },
95562306a36Sopenharmony_ci	{ "in_unicast",			4, 0x04, STATS_TYPE_BANK0, },
95662306a36Sopenharmony_ci	{ "in_broadcasts",		4, 0x06, STATS_TYPE_BANK0, },
95762306a36Sopenharmony_ci	{ "in_multicasts",		4, 0x07, STATS_TYPE_BANK0, },
95862306a36Sopenharmony_ci	{ "in_pause",			4, 0x16, STATS_TYPE_BANK0, },
95962306a36Sopenharmony_ci	{ "in_undersize",		4, 0x18, STATS_TYPE_BANK0, },
96062306a36Sopenharmony_ci	{ "in_fragments",		4, 0x19, STATS_TYPE_BANK0, },
96162306a36Sopenharmony_ci	{ "in_oversize",		4, 0x1a, STATS_TYPE_BANK0, },
96262306a36Sopenharmony_ci	{ "in_jabber",			4, 0x1b, STATS_TYPE_BANK0, },
96362306a36Sopenharmony_ci	{ "in_rx_error",		4, 0x1c, STATS_TYPE_BANK0, },
96462306a36Sopenharmony_ci	{ "in_fcs_error",		4, 0x1d, STATS_TYPE_BANK0, },
96562306a36Sopenharmony_ci	{ "out_octets",			8, 0x0e, STATS_TYPE_BANK0, },
96662306a36Sopenharmony_ci	{ "out_unicast",		4, 0x10, STATS_TYPE_BANK0, },
96762306a36Sopenharmony_ci	{ "out_broadcasts",		4, 0x13, STATS_TYPE_BANK0, },
96862306a36Sopenharmony_ci	{ "out_multicasts",		4, 0x12, STATS_TYPE_BANK0, },
96962306a36Sopenharmony_ci	{ "out_pause",			4, 0x15, STATS_TYPE_BANK0, },
97062306a36Sopenharmony_ci	{ "excessive",			4, 0x11, STATS_TYPE_BANK0, },
97162306a36Sopenharmony_ci	{ "collisions",			4, 0x1e, STATS_TYPE_BANK0, },
97262306a36Sopenharmony_ci	{ "deferred",			4, 0x05, STATS_TYPE_BANK0, },
97362306a36Sopenharmony_ci	{ "single",			4, 0x14, STATS_TYPE_BANK0, },
97462306a36Sopenharmony_ci	{ "multiple",			4, 0x17, STATS_TYPE_BANK0, },
97562306a36Sopenharmony_ci	{ "out_fcs_error",		4, 0x03, STATS_TYPE_BANK0, },
97662306a36Sopenharmony_ci	{ "late",			4, 0x1f, STATS_TYPE_BANK0, },
97762306a36Sopenharmony_ci	{ "hist_64bytes",		4, 0x08, STATS_TYPE_BANK0, },
97862306a36Sopenharmony_ci	{ "hist_65_127bytes",		4, 0x09, STATS_TYPE_BANK0, },
97962306a36Sopenharmony_ci	{ "hist_128_255bytes",		4, 0x0a, STATS_TYPE_BANK0, },
98062306a36Sopenharmony_ci	{ "hist_256_511bytes",		4, 0x0b, STATS_TYPE_BANK0, },
98162306a36Sopenharmony_ci	{ "hist_512_1023bytes",		4, 0x0c, STATS_TYPE_BANK0, },
98262306a36Sopenharmony_ci	{ "hist_1024_max_bytes",	4, 0x0d, STATS_TYPE_BANK0, },
98362306a36Sopenharmony_ci	{ "sw_in_discards",		4, 0x10, STATS_TYPE_PORT, },
98462306a36Sopenharmony_ci	{ "sw_in_filtered",		2, 0x12, STATS_TYPE_PORT, },
98562306a36Sopenharmony_ci	{ "sw_out_filtered",		2, 0x13, STATS_TYPE_PORT, },
98662306a36Sopenharmony_ci	{ "in_discards",		4, 0x00, STATS_TYPE_BANK1, },
98762306a36Sopenharmony_ci	{ "in_filtered",		4, 0x01, STATS_TYPE_BANK1, },
98862306a36Sopenharmony_ci	{ "in_accepted",		4, 0x02, STATS_TYPE_BANK1, },
98962306a36Sopenharmony_ci	{ "in_bad_accepted",		4, 0x03, STATS_TYPE_BANK1, },
99062306a36Sopenharmony_ci	{ "in_good_avb_class_a",	4, 0x04, STATS_TYPE_BANK1, },
99162306a36Sopenharmony_ci	{ "in_good_avb_class_b",	4, 0x05, STATS_TYPE_BANK1, },
99262306a36Sopenharmony_ci	{ "in_bad_avb_class_a",		4, 0x06, STATS_TYPE_BANK1, },
99362306a36Sopenharmony_ci	{ "in_bad_avb_class_b",		4, 0x07, STATS_TYPE_BANK1, },
99462306a36Sopenharmony_ci	{ "tcam_counter_0",		4, 0x08, STATS_TYPE_BANK1, },
99562306a36Sopenharmony_ci	{ "tcam_counter_1",		4, 0x09, STATS_TYPE_BANK1, },
99662306a36Sopenharmony_ci	{ "tcam_counter_2",		4, 0x0a, STATS_TYPE_BANK1, },
99762306a36Sopenharmony_ci	{ "tcam_counter_3",		4, 0x0b, STATS_TYPE_BANK1, },
99862306a36Sopenharmony_ci	{ "in_da_unknown",		4, 0x0e, STATS_TYPE_BANK1, },
99962306a36Sopenharmony_ci	{ "in_management",		4, 0x0f, STATS_TYPE_BANK1, },
100062306a36Sopenharmony_ci	{ "out_queue_0",		4, 0x10, STATS_TYPE_BANK1, },
100162306a36Sopenharmony_ci	{ "out_queue_1",		4, 0x11, STATS_TYPE_BANK1, },
100262306a36Sopenharmony_ci	{ "out_queue_2",		4, 0x12, STATS_TYPE_BANK1, },
100362306a36Sopenharmony_ci	{ "out_queue_3",		4, 0x13, STATS_TYPE_BANK1, },
100462306a36Sopenharmony_ci	{ "out_queue_4",		4, 0x14, STATS_TYPE_BANK1, },
100562306a36Sopenharmony_ci	{ "out_queue_5",		4, 0x15, STATS_TYPE_BANK1, },
100662306a36Sopenharmony_ci	{ "out_queue_6",		4, 0x16, STATS_TYPE_BANK1, },
100762306a36Sopenharmony_ci	{ "out_queue_7",		4, 0x17, STATS_TYPE_BANK1, },
100862306a36Sopenharmony_ci	{ "out_cut_through",		4, 0x18, STATS_TYPE_BANK1, },
100962306a36Sopenharmony_ci	{ "out_octets_a",		4, 0x1a, STATS_TYPE_BANK1, },
101062306a36Sopenharmony_ci	{ "out_octets_b",		4, 0x1b, STATS_TYPE_BANK1, },
101162306a36Sopenharmony_ci	{ "out_management",		4, 0x1f, STATS_TYPE_BANK1, },
101262306a36Sopenharmony_ci};
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_cistatic uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
101562306a36Sopenharmony_ci					    struct mv88e6xxx_hw_stat *s,
101662306a36Sopenharmony_ci					    int port, u16 bank1_select,
101762306a36Sopenharmony_ci					    u16 histogram)
101862306a36Sopenharmony_ci{
101962306a36Sopenharmony_ci	u32 low;
102062306a36Sopenharmony_ci	u32 high = 0;
102162306a36Sopenharmony_ci	u16 reg = 0;
102262306a36Sopenharmony_ci	int err;
102362306a36Sopenharmony_ci	u64 value;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	switch (s->type) {
102662306a36Sopenharmony_ci	case STATS_TYPE_PORT:
102762306a36Sopenharmony_ci		err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
102862306a36Sopenharmony_ci		if (err)
102962306a36Sopenharmony_ci			return U64_MAX;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci		low = reg;
103262306a36Sopenharmony_ci		if (s->size == 4) {
103362306a36Sopenharmony_ci			err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
103462306a36Sopenharmony_ci			if (err)
103562306a36Sopenharmony_ci				return U64_MAX;
103662306a36Sopenharmony_ci			low |= ((u32)reg) << 16;
103762306a36Sopenharmony_ci		}
103862306a36Sopenharmony_ci		break;
103962306a36Sopenharmony_ci	case STATS_TYPE_BANK1:
104062306a36Sopenharmony_ci		reg = bank1_select;
104162306a36Sopenharmony_ci		fallthrough;
104262306a36Sopenharmony_ci	case STATS_TYPE_BANK0:
104362306a36Sopenharmony_ci		reg |= s->reg | histogram;
104462306a36Sopenharmony_ci		mv88e6xxx_g1_stats_read(chip, reg, &low);
104562306a36Sopenharmony_ci		if (s->size == 8)
104662306a36Sopenharmony_ci			mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
104762306a36Sopenharmony_ci		break;
104862306a36Sopenharmony_ci	default:
104962306a36Sopenharmony_ci		return U64_MAX;
105062306a36Sopenharmony_ci	}
105162306a36Sopenharmony_ci	value = (((u64)high) << 32) | low;
105262306a36Sopenharmony_ci	return value;
105362306a36Sopenharmony_ci}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_cistatic int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
105662306a36Sopenharmony_ci				       uint8_t *data, int types)
105762306a36Sopenharmony_ci{
105862306a36Sopenharmony_ci	struct mv88e6xxx_hw_stat *stat;
105962306a36Sopenharmony_ci	int i, j;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
106262306a36Sopenharmony_ci		stat = &mv88e6xxx_hw_stats[i];
106362306a36Sopenharmony_ci		if (stat->type & types) {
106462306a36Sopenharmony_ci			memcpy(data + j * ETH_GSTRING_LEN, stat->string,
106562306a36Sopenharmony_ci			       ETH_GSTRING_LEN);
106662306a36Sopenharmony_ci			j++;
106762306a36Sopenharmony_ci		}
106862306a36Sopenharmony_ci	}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	return j;
107162306a36Sopenharmony_ci}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_cistatic int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
107462306a36Sopenharmony_ci				       uint8_t *data)
107562306a36Sopenharmony_ci{
107662306a36Sopenharmony_ci	return mv88e6xxx_stats_get_strings(chip, data,
107762306a36Sopenharmony_ci					   STATS_TYPE_BANK0 | STATS_TYPE_PORT);
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_cistatic int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip,
108162306a36Sopenharmony_ci				       uint8_t *data)
108262306a36Sopenharmony_ci{
108362306a36Sopenharmony_ci	return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0);
108462306a36Sopenharmony_ci}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_cistatic int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
108762306a36Sopenharmony_ci				       uint8_t *data)
108862306a36Sopenharmony_ci{
108962306a36Sopenharmony_ci	return mv88e6xxx_stats_get_strings(chip, data,
109062306a36Sopenharmony_ci					   STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
109162306a36Sopenharmony_ci}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_cistatic const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = {
109462306a36Sopenharmony_ci	"atu_member_violation",
109562306a36Sopenharmony_ci	"atu_miss_violation",
109662306a36Sopenharmony_ci	"atu_full_violation",
109762306a36Sopenharmony_ci	"vtu_member_violation",
109862306a36Sopenharmony_ci	"vtu_miss_violation",
109962306a36Sopenharmony_ci};
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_cistatic void mv88e6xxx_atu_vtu_get_strings(uint8_t *data)
110262306a36Sopenharmony_ci{
110362306a36Sopenharmony_ci	unsigned int i;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++)
110662306a36Sopenharmony_ci		strscpy(data + i * ETH_GSTRING_LEN,
110762306a36Sopenharmony_ci			mv88e6xxx_atu_vtu_stats_strings[i],
110862306a36Sopenharmony_ci			ETH_GSTRING_LEN);
110962306a36Sopenharmony_ci}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_cistatic void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
111262306a36Sopenharmony_ci				  u32 stringset, uint8_t *data)
111362306a36Sopenharmony_ci{
111462306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
111562306a36Sopenharmony_ci	int count = 0;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if (stringset != ETH_SS_STATS)
111862306a36Sopenharmony_ci		return;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	if (chip->info->ops->stats_get_strings)
112362306a36Sopenharmony_ci		count = chip->info->ops->stats_get_strings(chip, data);
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	if (chip->info->ops->serdes_get_strings) {
112662306a36Sopenharmony_ci		data += count * ETH_GSTRING_LEN;
112762306a36Sopenharmony_ci		count = chip->info->ops->serdes_get_strings(chip, port, data);
112862306a36Sopenharmony_ci	}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	data += count * ETH_GSTRING_LEN;
113162306a36Sopenharmony_ci	mv88e6xxx_atu_vtu_get_strings(data);
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
113462306a36Sopenharmony_ci}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_cistatic int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
113762306a36Sopenharmony_ci					  int types)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci	struct mv88e6xxx_hw_stat *stat;
114062306a36Sopenharmony_ci	int i, j;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
114362306a36Sopenharmony_ci		stat = &mv88e6xxx_hw_stats[i];
114462306a36Sopenharmony_ci		if (stat->type & types)
114562306a36Sopenharmony_ci			j++;
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci	return j;
114862306a36Sopenharmony_ci}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_cistatic int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
115362306a36Sopenharmony_ci					      STATS_TYPE_PORT);
115462306a36Sopenharmony_ci}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_cistatic int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip)
115762306a36Sopenharmony_ci{
115862306a36Sopenharmony_ci	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0);
115962306a36Sopenharmony_ci}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_cistatic int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
116262306a36Sopenharmony_ci{
116362306a36Sopenharmony_ci	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
116462306a36Sopenharmony_ci					      STATS_TYPE_BANK1);
116562306a36Sopenharmony_ci}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_cistatic int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
116862306a36Sopenharmony_ci{
116962306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
117062306a36Sopenharmony_ci	int serdes_count = 0;
117162306a36Sopenharmony_ci	int count = 0;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	if (sset != ETH_SS_STATS)
117462306a36Sopenharmony_ci		return 0;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
117762306a36Sopenharmony_ci	if (chip->info->ops->stats_get_sset_count)
117862306a36Sopenharmony_ci		count = chip->info->ops->stats_get_sset_count(chip);
117962306a36Sopenharmony_ci	if (count < 0)
118062306a36Sopenharmony_ci		goto out;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	if (chip->info->ops->serdes_get_sset_count)
118362306a36Sopenharmony_ci		serdes_count = chip->info->ops->serdes_get_sset_count(chip,
118462306a36Sopenharmony_ci								      port);
118562306a36Sopenharmony_ci	if (serdes_count < 0) {
118662306a36Sopenharmony_ci		count = serdes_count;
118762306a36Sopenharmony_ci		goto out;
118862306a36Sopenharmony_ci	}
118962306a36Sopenharmony_ci	count += serdes_count;
119062306a36Sopenharmony_ci	count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ciout:
119362306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	return count;
119662306a36Sopenharmony_ci}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_cistatic int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
119962306a36Sopenharmony_ci				     uint64_t *data, int types,
120062306a36Sopenharmony_ci				     u16 bank1_select, u16 histogram)
120162306a36Sopenharmony_ci{
120262306a36Sopenharmony_ci	struct mv88e6xxx_hw_stat *stat;
120362306a36Sopenharmony_ci	int i, j;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
120662306a36Sopenharmony_ci		stat = &mv88e6xxx_hw_stats[i];
120762306a36Sopenharmony_ci		if (stat->type & types) {
120862306a36Sopenharmony_ci			mv88e6xxx_reg_lock(chip);
120962306a36Sopenharmony_ci			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
121062306a36Sopenharmony_ci							      bank1_select,
121162306a36Sopenharmony_ci							      histogram);
121262306a36Sopenharmony_ci			mv88e6xxx_reg_unlock(chip);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci			j++;
121562306a36Sopenharmony_ci		}
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci	return j;
121862306a36Sopenharmony_ci}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_cistatic int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
122162306a36Sopenharmony_ci				     uint64_t *data)
122262306a36Sopenharmony_ci{
122362306a36Sopenharmony_ci	return mv88e6xxx_stats_get_stats(chip, port, data,
122462306a36Sopenharmony_ci					 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
122562306a36Sopenharmony_ci					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
122962306a36Sopenharmony_ci				     uint64_t *data)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0,
123262306a36Sopenharmony_ci					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_cistatic int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
123662306a36Sopenharmony_ci				     uint64_t *data)
123762306a36Sopenharmony_ci{
123862306a36Sopenharmony_ci	return mv88e6xxx_stats_get_stats(chip, port, data,
123962306a36Sopenharmony_ci					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
124062306a36Sopenharmony_ci					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
124162306a36Sopenharmony_ci					 MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
124262306a36Sopenharmony_ci}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_cistatic int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
124562306a36Sopenharmony_ci				     uint64_t *data)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	return mv88e6xxx_stats_get_stats(chip, port, data,
124862306a36Sopenharmony_ci					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
124962306a36Sopenharmony_ci					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
125062306a36Sopenharmony_ci					 0);
125162306a36Sopenharmony_ci}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_cistatic void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
125462306a36Sopenharmony_ci					uint64_t *data)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	*data++ = chip->ports[port].atu_member_violation;
125762306a36Sopenharmony_ci	*data++ = chip->ports[port].atu_miss_violation;
125862306a36Sopenharmony_ci	*data++ = chip->ports[port].atu_full_violation;
125962306a36Sopenharmony_ci	*data++ = chip->ports[port].vtu_member_violation;
126062306a36Sopenharmony_ci	*data++ = chip->ports[port].vtu_miss_violation;
126162306a36Sopenharmony_ci}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_cistatic void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
126462306a36Sopenharmony_ci				uint64_t *data)
126562306a36Sopenharmony_ci{
126662306a36Sopenharmony_ci	int count = 0;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	if (chip->info->ops->stats_get_stats)
126962306a36Sopenharmony_ci		count = chip->info->ops->stats_get_stats(chip, port, data);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
127262306a36Sopenharmony_ci	if (chip->info->ops->serdes_get_stats) {
127362306a36Sopenharmony_ci		data += count;
127462306a36Sopenharmony_ci		count = chip->info->ops->serdes_get_stats(chip, port, data);
127562306a36Sopenharmony_ci	}
127662306a36Sopenharmony_ci	data += count;
127762306a36Sopenharmony_ci	mv88e6xxx_atu_vtu_get_stats(chip, port, data);
127862306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
127962306a36Sopenharmony_ci}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_cistatic void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
128262306a36Sopenharmony_ci					uint64_t *data)
128362306a36Sopenharmony_ci{
128462306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
128562306a36Sopenharmony_ci	int ret;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	ret = mv88e6xxx_stats_snapshot(chip, port);
129062306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	if (ret < 0)
129362306a36Sopenharmony_ci		return;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	mv88e6xxx_get_stats(chip, port, data);
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_cistatic int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
130062306a36Sopenharmony_ci{
130162306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
130262306a36Sopenharmony_ci	int len;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	len = 32 * sizeof(u16);
130562306a36Sopenharmony_ci	if (chip->info->ops->serdes_get_regs_len)
130662306a36Sopenharmony_ci		len += chip->info->ops->serdes_get_regs_len(chip, port);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	return len;
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_cistatic void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
131262306a36Sopenharmony_ci			       struct ethtool_regs *regs, void *_p)
131362306a36Sopenharmony_ci{
131462306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
131562306a36Sopenharmony_ci	int err;
131662306a36Sopenharmony_ci	u16 reg;
131762306a36Sopenharmony_ci	u16 *p = _p;
131862306a36Sopenharmony_ci	int i;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	regs->version = chip->info->prod_num;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	memset(p, 0xff, 32 * sizeof(u16));
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	for (i = 0; i < 32; i++) {
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci		err = mv88e6xxx_port_read(chip, port, i, &reg);
132962306a36Sopenharmony_ci		if (!err)
133062306a36Sopenharmony_ci			p[i] = reg;
133162306a36Sopenharmony_ci	}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	if (chip->info->ops->serdes_get_regs)
133462306a36Sopenharmony_ci		chip->info->ops->serdes_get_regs(chip, port, &p[i]);
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
133762306a36Sopenharmony_ci}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_cistatic int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
134062306a36Sopenharmony_ci				 struct ethtool_eee *e)
134162306a36Sopenharmony_ci{
134262306a36Sopenharmony_ci	/* Nothing to do on the port's MAC */
134362306a36Sopenharmony_ci	return 0;
134462306a36Sopenharmony_ci}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_cistatic int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port,
134762306a36Sopenharmony_ci				 struct ethtool_eee *e)
134862306a36Sopenharmony_ci{
134962306a36Sopenharmony_ci	/* Nothing to do on the port's MAC */
135062306a36Sopenharmony_ci	return 0;
135162306a36Sopenharmony_ci}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci/* Mask of the local ports allowed to receive frames from a given fabric port */
135462306a36Sopenharmony_cistatic u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	struct dsa_switch *ds = chip->ds;
135762306a36Sopenharmony_ci	struct dsa_switch_tree *dst = ds->dst;
135862306a36Sopenharmony_ci	struct dsa_port *dp, *other_dp;
135962306a36Sopenharmony_ci	bool found = false;
136062306a36Sopenharmony_ci	u16 pvlan;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	/* dev is a physical switch */
136362306a36Sopenharmony_ci	if (dev <= dst->last_switch) {
136462306a36Sopenharmony_ci		list_for_each_entry(dp, &dst->ports, list) {
136562306a36Sopenharmony_ci			if (dp->ds->index == dev && dp->index == port) {
136662306a36Sopenharmony_ci				/* dp might be a DSA link or a user port, so it
136762306a36Sopenharmony_ci				 * might or might not have a bridge.
136862306a36Sopenharmony_ci				 * Use the "found" variable for both cases.
136962306a36Sopenharmony_ci				 */
137062306a36Sopenharmony_ci				found = true;
137162306a36Sopenharmony_ci				break;
137262306a36Sopenharmony_ci			}
137362306a36Sopenharmony_ci		}
137462306a36Sopenharmony_ci	/* dev is a virtual bridge */
137562306a36Sopenharmony_ci	} else {
137662306a36Sopenharmony_ci		list_for_each_entry(dp, &dst->ports, list) {
137762306a36Sopenharmony_ci			unsigned int bridge_num = dsa_port_bridge_num_get(dp);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci			if (!bridge_num)
138062306a36Sopenharmony_ci				continue;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci			if (bridge_num + dst->last_switch != dev)
138362306a36Sopenharmony_ci				continue;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci			found = true;
138662306a36Sopenharmony_ci			break;
138762306a36Sopenharmony_ci		}
138862306a36Sopenharmony_ci	}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	/* Prevent frames from unknown switch or virtual bridge */
139162306a36Sopenharmony_ci	if (!found)
139262306a36Sopenharmony_ci		return 0;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	/* Frames from DSA links and CPU ports can egress any local port */
139562306a36Sopenharmony_ci	if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA)
139662306a36Sopenharmony_ci		return mv88e6xxx_port_mask(chip);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	pvlan = 0;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	/* Frames from standalone user ports can only egress on the
140162306a36Sopenharmony_ci	 * upstream port.
140262306a36Sopenharmony_ci	 */
140362306a36Sopenharmony_ci	if (!dsa_port_bridge_dev_get(dp))
140462306a36Sopenharmony_ci		return BIT(dsa_switch_upstream_port(ds));
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	/* Frames from bridged user ports can egress any local DSA
140762306a36Sopenharmony_ci	 * links and CPU ports, as well as any local member of their
140862306a36Sopenharmony_ci	 * bridge group.
140962306a36Sopenharmony_ci	 */
141062306a36Sopenharmony_ci	dsa_switch_for_each_port(other_dp, ds)
141162306a36Sopenharmony_ci		if (other_dp->type == DSA_PORT_TYPE_CPU ||
141262306a36Sopenharmony_ci		    other_dp->type == DSA_PORT_TYPE_DSA ||
141362306a36Sopenharmony_ci		    dsa_port_bridge_same(dp, other_dp))
141462306a36Sopenharmony_ci			pvlan |= BIT(other_dp->index);
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	return pvlan;
141762306a36Sopenharmony_ci}
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port)
142062306a36Sopenharmony_ci{
142162306a36Sopenharmony_ci	u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	/* prevent frames from going back out of the port they came in on */
142462306a36Sopenharmony_ci	output_ports &= ~BIT(port);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
142762306a36Sopenharmony_ci}
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_cistatic void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
143062306a36Sopenharmony_ci					 u8 state)
143162306a36Sopenharmony_ci{
143262306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
143362306a36Sopenharmony_ci	int err;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
143662306a36Sopenharmony_ci	err = mv88e6xxx_port_set_state(chip, port, state);
143762306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	if (err)
144062306a36Sopenharmony_ci		dev_err(ds->dev, "p%d: failed to update state\n", port);
144162306a36Sopenharmony_ci}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_cistatic int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip)
144462306a36Sopenharmony_ci{
144562306a36Sopenharmony_ci	int err;
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	if (chip->info->ops->ieee_pri_map) {
144862306a36Sopenharmony_ci		err = chip->info->ops->ieee_pri_map(chip);
144962306a36Sopenharmony_ci		if (err)
145062306a36Sopenharmony_ci			return err;
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	if (chip->info->ops->ip_pri_map) {
145462306a36Sopenharmony_ci		err = chip->info->ops->ip_pri_map(chip);
145562306a36Sopenharmony_ci		if (err)
145662306a36Sopenharmony_ci			return err;
145762306a36Sopenharmony_ci	}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	return 0;
146062306a36Sopenharmony_ci}
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_cistatic int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
146362306a36Sopenharmony_ci{
146462306a36Sopenharmony_ci	struct dsa_switch *ds = chip->ds;
146562306a36Sopenharmony_ci	int target, port;
146662306a36Sopenharmony_ci	int err;
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	if (!chip->info->global2_addr)
146962306a36Sopenharmony_ci		return 0;
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	/* Initialize the routing port to the 32 possible target devices */
147262306a36Sopenharmony_ci	for (target = 0; target < 32; target++) {
147362306a36Sopenharmony_ci		port = dsa_routing_port(ds, target);
147462306a36Sopenharmony_ci		if (port == ds->num_ports)
147562306a36Sopenharmony_ci			port = 0x1f;
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci		err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
147862306a36Sopenharmony_ci		if (err)
147962306a36Sopenharmony_ci			return err;
148062306a36Sopenharmony_ci	}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	if (chip->info->ops->set_cascade_port) {
148362306a36Sopenharmony_ci		port = MV88E6XXX_CASCADE_PORT_MULTIPLE;
148462306a36Sopenharmony_ci		err = chip->info->ops->set_cascade_port(chip, port);
148562306a36Sopenharmony_ci		if (err)
148662306a36Sopenharmony_ci			return err;
148762306a36Sopenharmony_ci	}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index);
149062306a36Sopenharmony_ci	if (err)
149162306a36Sopenharmony_ci		return err;
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	return 0;
149462306a36Sopenharmony_ci}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_cistatic int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip)
149762306a36Sopenharmony_ci{
149862306a36Sopenharmony_ci	/* Clear all trunk masks and mapping */
149962306a36Sopenharmony_ci	if (chip->info->global2_addr)
150062306a36Sopenharmony_ci		return mv88e6xxx_g2_trunk_clear(chip);
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	return 0;
150362306a36Sopenharmony_ci}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_cistatic int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
150662306a36Sopenharmony_ci{
150762306a36Sopenharmony_ci	if (chip->info->ops->rmu_disable)
150862306a36Sopenharmony_ci		return chip->info->ops->rmu_disable(chip);
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	return 0;
151162306a36Sopenharmony_ci}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_cistatic int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
151462306a36Sopenharmony_ci{
151562306a36Sopenharmony_ci	if (chip->info->ops->pot_clear)
151662306a36Sopenharmony_ci		return chip->info->ops->pot_clear(chip);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	return 0;
151962306a36Sopenharmony_ci}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_cistatic int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip)
152262306a36Sopenharmony_ci{
152362306a36Sopenharmony_ci	if (chip->info->ops->mgmt_rsvd2cpu)
152462306a36Sopenharmony_ci		return chip->info->ops->mgmt_rsvd2cpu(chip);
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	return 0;
152762306a36Sopenharmony_ci}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_cistatic int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
153062306a36Sopenharmony_ci{
153162306a36Sopenharmony_ci	int err;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	err = mv88e6xxx_g1_atu_flush(chip, 0, true);
153462306a36Sopenharmony_ci	if (err)
153562306a36Sopenharmony_ci		return err;
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	/* The chips that have a "learn2all" bit in Global1, ATU
153862306a36Sopenharmony_ci	 * Control are precisely those whose port registers have a
153962306a36Sopenharmony_ci	 * Message Port bit in Port Control 1 and hence implement
154062306a36Sopenharmony_ci	 * ->port_setup_message_port.
154162306a36Sopenharmony_ci	 */
154262306a36Sopenharmony_ci	if (chip->info->ops->port_setup_message_port) {
154362306a36Sopenharmony_ci		err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
154462306a36Sopenharmony_ci		if (err)
154562306a36Sopenharmony_ci			return err;
154662306a36Sopenharmony_ci	}
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
154962306a36Sopenharmony_ci}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_cistatic int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip)
155262306a36Sopenharmony_ci{
155362306a36Sopenharmony_ci	int port;
155462306a36Sopenharmony_ci	int err;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	if (!chip->info->ops->irl_init_all)
155762306a36Sopenharmony_ci		return 0;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
156062306a36Sopenharmony_ci		/* Disable ingress rate limiting by resetting all per port
156162306a36Sopenharmony_ci		 * ingress rate limit resources to their initial state.
156262306a36Sopenharmony_ci		 */
156362306a36Sopenharmony_ci		err = chip->info->ops->irl_init_all(chip, port);
156462306a36Sopenharmony_ci		if (err)
156562306a36Sopenharmony_ci			return err;
156662306a36Sopenharmony_ci	}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	return 0;
156962306a36Sopenharmony_ci}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_cistatic int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip)
157262306a36Sopenharmony_ci{
157362306a36Sopenharmony_ci	if (chip->info->ops->set_switch_mac) {
157462306a36Sopenharmony_ci		u8 addr[ETH_ALEN];
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci		eth_random_addr(addr);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci		return chip->info->ops->set_switch_mac(chip, addr);
157962306a36Sopenharmony_ci	}
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	return 0;
158262306a36Sopenharmony_ci}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_cistatic int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
158562306a36Sopenharmony_ci{
158662306a36Sopenharmony_ci	struct dsa_switch_tree *dst = chip->ds->dst;
158762306a36Sopenharmony_ci	struct dsa_switch *ds;
158862306a36Sopenharmony_ci	struct dsa_port *dp;
158962306a36Sopenharmony_ci	u16 pvlan = 0;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	if (!mv88e6xxx_has_pvt(chip))
159262306a36Sopenharmony_ci		return 0;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	/* Skip the local source device, which uses in-chip port VLAN */
159562306a36Sopenharmony_ci	if (dev != chip->ds->index) {
159662306a36Sopenharmony_ci		pvlan = mv88e6xxx_port_vlan(chip, dev, port);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci		ds = dsa_switch_find(dst->index, dev);
159962306a36Sopenharmony_ci		dp = ds ? dsa_to_port(ds, port) : NULL;
160062306a36Sopenharmony_ci		if (dp && dp->lag) {
160162306a36Sopenharmony_ci			/* As the PVT is used to limit flooding of
160262306a36Sopenharmony_ci			 * FORWARD frames, which use the LAG ID as the
160362306a36Sopenharmony_ci			 * source port, we must translate dev/port to
160462306a36Sopenharmony_ci			 * the special "LAG device" in the PVT, using
160562306a36Sopenharmony_ci			 * the LAG ID (one-based) as the port number
160662306a36Sopenharmony_ci			 * (zero-based).
160762306a36Sopenharmony_ci			 */
160862306a36Sopenharmony_ci			dev = MV88E6XXX_G2_PVT_ADDR_DEV_TRUNK;
160962306a36Sopenharmony_ci			port = dsa_port_lag_id_get(dp) - 1;
161062306a36Sopenharmony_ci		}
161162306a36Sopenharmony_ci	}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
161462306a36Sopenharmony_ci}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_cistatic int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
161762306a36Sopenharmony_ci{
161862306a36Sopenharmony_ci	int dev, port;
161962306a36Sopenharmony_ci	int err;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	if (!mv88e6xxx_has_pvt(chip))
162262306a36Sopenharmony_ci		return 0;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
162562306a36Sopenharmony_ci	 * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
162662306a36Sopenharmony_ci	 */
162762306a36Sopenharmony_ci	err = mv88e6xxx_g2_misc_4_bit_port(chip);
162862306a36Sopenharmony_ci	if (err)
162962306a36Sopenharmony_ci		return err;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) {
163262306a36Sopenharmony_ci		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) {
163362306a36Sopenharmony_ci			err = mv88e6xxx_pvt_map(chip, dev, port);
163462306a36Sopenharmony_ci			if (err)
163562306a36Sopenharmony_ci				return err;
163662306a36Sopenharmony_ci		}
163762306a36Sopenharmony_ci	}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	return 0;
164062306a36Sopenharmony_ci}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_cistatic int mv88e6xxx_port_fast_age_fid(struct mv88e6xxx_chip *chip, int port,
164362306a36Sopenharmony_ci				       u16 fid)
164462306a36Sopenharmony_ci{
164562306a36Sopenharmony_ci	if (dsa_to_port(chip->ds, port)->lag)
164662306a36Sopenharmony_ci		/* Hardware is incapable of fast-aging a LAG through a
164762306a36Sopenharmony_ci		 * regular ATU move operation. Until we have something
164862306a36Sopenharmony_ci		 * more fancy in place this is a no-op.
164962306a36Sopenharmony_ci		 */
165062306a36Sopenharmony_ci		return -EOPNOTSUPP;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	return mv88e6xxx_g1_atu_remove(chip, fid, port, false);
165362306a36Sopenharmony_ci}
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_cistatic void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
165662306a36Sopenharmony_ci{
165762306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
165862306a36Sopenharmony_ci	int err;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
166162306a36Sopenharmony_ci	err = mv88e6xxx_port_fast_age_fid(chip, port, 0);
166262306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	if (err)
166562306a36Sopenharmony_ci		dev_err(chip->ds->dev, "p%d: failed to flush ATU: %d\n",
166662306a36Sopenharmony_ci			port, err);
166762306a36Sopenharmony_ci}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_cistatic int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)
167062306a36Sopenharmony_ci{
167162306a36Sopenharmony_ci	if (!mv88e6xxx_max_vid(chip))
167262306a36Sopenharmony_ci		return 0;
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	return mv88e6xxx_g1_vtu_flush(chip);
167562306a36Sopenharmony_ci}
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_cistatic int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
167862306a36Sopenharmony_ci			     struct mv88e6xxx_vtu_entry *entry)
167962306a36Sopenharmony_ci{
168062306a36Sopenharmony_ci	int err;
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	if (!chip->info->ops->vtu_getnext)
168362306a36Sopenharmony_ci		return -EOPNOTSUPP;
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	entry->vid = vid ? vid - 1 : mv88e6xxx_max_vid(chip);
168662306a36Sopenharmony_ci	entry->valid = false;
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	err = chip->info->ops->vtu_getnext(chip, entry);
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	if (entry->vid != vid)
169162306a36Sopenharmony_ci		entry->valid = false;
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	return err;
169462306a36Sopenharmony_ci}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ciint mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
169762306a36Sopenharmony_ci		       int (*cb)(struct mv88e6xxx_chip *chip,
169862306a36Sopenharmony_ci				 const struct mv88e6xxx_vtu_entry *entry,
169962306a36Sopenharmony_ci				 void *priv),
170062306a36Sopenharmony_ci		       void *priv)
170162306a36Sopenharmony_ci{
170262306a36Sopenharmony_ci	struct mv88e6xxx_vtu_entry entry = {
170362306a36Sopenharmony_ci		.vid = mv88e6xxx_max_vid(chip),
170462306a36Sopenharmony_ci		.valid = false,
170562306a36Sopenharmony_ci	};
170662306a36Sopenharmony_ci	int err;
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	if (!chip->info->ops->vtu_getnext)
170962306a36Sopenharmony_ci		return -EOPNOTSUPP;
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	do {
171262306a36Sopenharmony_ci		err = chip->info->ops->vtu_getnext(chip, &entry);
171362306a36Sopenharmony_ci		if (err)
171462306a36Sopenharmony_ci			return err;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci		if (!entry.valid)
171762306a36Sopenharmony_ci			break;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci		err = cb(chip, &entry, priv);
172062306a36Sopenharmony_ci		if (err)
172162306a36Sopenharmony_ci			return err;
172262306a36Sopenharmony_ci	} while (entry.vid < mv88e6xxx_max_vid(chip));
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	return 0;
172562306a36Sopenharmony_ci}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_cistatic int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
172862306a36Sopenharmony_ci				   struct mv88e6xxx_vtu_entry *entry)
172962306a36Sopenharmony_ci{
173062306a36Sopenharmony_ci	if (!chip->info->ops->vtu_loadpurge)
173162306a36Sopenharmony_ci		return -EOPNOTSUPP;
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	return chip->info->ops->vtu_loadpurge(chip, entry);
173462306a36Sopenharmony_ci}
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_cistatic int mv88e6xxx_fid_map_vlan(struct mv88e6xxx_chip *chip,
173762306a36Sopenharmony_ci				  const struct mv88e6xxx_vtu_entry *entry,
173862306a36Sopenharmony_ci				  void *_fid_bitmap)
173962306a36Sopenharmony_ci{
174062306a36Sopenharmony_ci	unsigned long *fid_bitmap = _fid_bitmap;
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	set_bit(entry->fid, fid_bitmap);
174362306a36Sopenharmony_ci	return 0;
174462306a36Sopenharmony_ci}
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ciint mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *fid_bitmap)
174762306a36Sopenharmony_ci{
174862306a36Sopenharmony_ci	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	/* Every FID has an associated VID, so walking the VTU
175162306a36Sopenharmony_ci	 * will discover the full set of FIDs in use.
175262306a36Sopenharmony_ci	 */
175362306a36Sopenharmony_ci	return mv88e6xxx_vtu_walk(chip, mv88e6xxx_fid_map_vlan, fid_bitmap);
175462306a36Sopenharmony_ci}
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_cistatic int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
175762306a36Sopenharmony_ci{
175862306a36Sopenharmony_ci	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
175962306a36Sopenharmony_ci	int err;
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	err = mv88e6xxx_fid_map(chip, fid_bitmap);
176262306a36Sopenharmony_ci	if (err)
176362306a36Sopenharmony_ci		return err;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	*fid = find_first_zero_bit(fid_bitmap, MV88E6XXX_N_FID);
176662306a36Sopenharmony_ci	if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
176762306a36Sopenharmony_ci		return -ENOSPC;
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	/* Clear the database */
177062306a36Sopenharmony_ci	return mv88e6xxx_g1_atu_flush(chip, *fid, true);
177162306a36Sopenharmony_ci}
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_cistatic int mv88e6xxx_stu_loadpurge(struct mv88e6xxx_chip *chip,
177462306a36Sopenharmony_ci				   struct mv88e6xxx_stu_entry *entry)
177562306a36Sopenharmony_ci{
177662306a36Sopenharmony_ci	if (!chip->info->ops->stu_loadpurge)
177762306a36Sopenharmony_ci		return -EOPNOTSUPP;
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	return chip->info->ops->stu_loadpurge(chip, entry);
178062306a36Sopenharmony_ci}
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_cistatic int mv88e6xxx_stu_setup(struct mv88e6xxx_chip *chip)
178362306a36Sopenharmony_ci{
178462306a36Sopenharmony_ci	struct mv88e6xxx_stu_entry stu = {
178562306a36Sopenharmony_ci		.valid = true,
178662306a36Sopenharmony_ci		.sid = 0
178762306a36Sopenharmony_ci	};
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	if (!mv88e6xxx_has_stu(chip))
179062306a36Sopenharmony_ci		return 0;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	/* Make sure that SID 0 is always valid. This is used by VTU
179362306a36Sopenharmony_ci	 * entries that do not make use of the STU, e.g. when creating
179462306a36Sopenharmony_ci	 * a VLAN upper on a port that is also part of a VLAN
179562306a36Sopenharmony_ci	 * filtering bridge.
179662306a36Sopenharmony_ci	 */
179762306a36Sopenharmony_ci	return mv88e6xxx_stu_loadpurge(chip, &stu);
179862306a36Sopenharmony_ci}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_cistatic int mv88e6xxx_sid_get(struct mv88e6xxx_chip *chip, u8 *sid)
180162306a36Sopenharmony_ci{
180262306a36Sopenharmony_ci	DECLARE_BITMAP(busy, MV88E6XXX_N_SID) = { 0 };
180362306a36Sopenharmony_ci	struct mv88e6xxx_mst *mst;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	__set_bit(0, busy);
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	list_for_each_entry(mst, &chip->msts, node)
180862306a36Sopenharmony_ci		__set_bit(mst->stu.sid, busy);
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	*sid = find_first_zero_bit(busy, MV88E6XXX_N_SID);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	return (*sid >= mv88e6xxx_max_sid(chip)) ? -ENOSPC : 0;
181362306a36Sopenharmony_ci}
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_cistatic int mv88e6xxx_mst_put(struct mv88e6xxx_chip *chip, u8 sid)
181662306a36Sopenharmony_ci{
181762306a36Sopenharmony_ci	struct mv88e6xxx_mst *mst, *tmp;
181862306a36Sopenharmony_ci	int err;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	if (!sid)
182162306a36Sopenharmony_ci		return 0;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	list_for_each_entry_safe(mst, tmp, &chip->msts, node) {
182462306a36Sopenharmony_ci		if (mst->stu.sid != sid)
182562306a36Sopenharmony_ci			continue;
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci		if (!refcount_dec_and_test(&mst->refcnt))
182862306a36Sopenharmony_ci			return 0;
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci		mst->stu.valid = false;
183162306a36Sopenharmony_ci		err = mv88e6xxx_stu_loadpurge(chip, &mst->stu);
183262306a36Sopenharmony_ci		if (err) {
183362306a36Sopenharmony_ci			refcount_set(&mst->refcnt, 1);
183462306a36Sopenharmony_ci			return err;
183562306a36Sopenharmony_ci		}
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci		list_del(&mst->node);
183862306a36Sopenharmony_ci		kfree(mst);
183962306a36Sopenharmony_ci		return 0;
184062306a36Sopenharmony_ci	}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	return -ENOENT;
184362306a36Sopenharmony_ci}
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_cistatic int mv88e6xxx_mst_get(struct mv88e6xxx_chip *chip, struct net_device *br,
184662306a36Sopenharmony_ci			     u16 msti, u8 *sid)
184762306a36Sopenharmony_ci{
184862306a36Sopenharmony_ci	struct mv88e6xxx_mst *mst;
184962306a36Sopenharmony_ci	int err, i;
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	if (!mv88e6xxx_has_stu(chip)) {
185262306a36Sopenharmony_ci		err = -EOPNOTSUPP;
185362306a36Sopenharmony_ci		goto err;
185462306a36Sopenharmony_ci	}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	if (!msti) {
185762306a36Sopenharmony_ci		*sid = 0;
185862306a36Sopenharmony_ci		return 0;
185962306a36Sopenharmony_ci	}
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	list_for_each_entry(mst, &chip->msts, node) {
186262306a36Sopenharmony_ci		if (mst->br == br && mst->msti == msti) {
186362306a36Sopenharmony_ci			refcount_inc(&mst->refcnt);
186462306a36Sopenharmony_ci			*sid = mst->stu.sid;
186562306a36Sopenharmony_ci			return 0;
186662306a36Sopenharmony_ci		}
186762306a36Sopenharmony_ci	}
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	err = mv88e6xxx_sid_get(chip, sid);
187062306a36Sopenharmony_ci	if (err)
187162306a36Sopenharmony_ci		goto err;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	mst = kzalloc(sizeof(*mst), GFP_KERNEL);
187462306a36Sopenharmony_ci	if (!mst) {
187562306a36Sopenharmony_ci		err = -ENOMEM;
187662306a36Sopenharmony_ci		goto err;
187762306a36Sopenharmony_ci	}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	INIT_LIST_HEAD(&mst->node);
188062306a36Sopenharmony_ci	refcount_set(&mst->refcnt, 1);
188162306a36Sopenharmony_ci	mst->br = br;
188262306a36Sopenharmony_ci	mst->msti = msti;
188362306a36Sopenharmony_ci	mst->stu.valid = true;
188462306a36Sopenharmony_ci	mst->stu.sid = *sid;
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	/* The bridge starts out all ports in the disabled state. But
188762306a36Sopenharmony_ci	 * a STU state of disabled means to go by the port-global
188862306a36Sopenharmony_ci	 * state. So we set all user port's initial state to blocking,
188962306a36Sopenharmony_ci	 * to match the bridge's behavior.
189062306a36Sopenharmony_ci	 */
189162306a36Sopenharmony_ci	for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
189262306a36Sopenharmony_ci		mst->stu.state[i] = dsa_is_user_port(chip->ds, i) ?
189362306a36Sopenharmony_ci			MV88E6XXX_PORT_CTL0_STATE_BLOCKING :
189462306a36Sopenharmony_ci			MV88E6XXX_PORT_CTL0_STATE_DISABLED;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	err = mv88e6xxx_stu_loadpurge(chip, &mst->stu);
189762306a36Sopenharmony_ci	if (err)
189862306a36Sopenharmony_ci		goto err_free;
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	list_add_tail(&mst->node, &chip->msts);
190162306a36Sopenharmony_ci	return 0;
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_cierr_free:
190462306a36Sopenharmony_ci	kfree(mst);
190562306a36Sopenharmony_cierr:
190662306a36Sopenharmony_ci	return err;
190762306a36Sopenharmony_ci}
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_cistatic int mv88e6xxx_port_mst_state_set(struct dsa_switch *ds, int port,
191062306a36Sopenharmony_ci					const struct switchdev_mst_state *st)
191162306a36Sopenharmony_ci{
191262306a36Sopenharmony_ci	struct dsa_port *dp = dsa_to_port(ds, port);
191362306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
191462306a36Sopenharmony_ci	struct mv88e6xxx_mst *mst;
191562306a36Sopenharmony_ci	u8 state;
191662306a36Sopenharmony_ci	int err;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	if (!mv88e6xxx_has_stu(chip))
191962306a36Sopenharmony_ci		return -EOPNOTSUPP;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	switch (st->state) {
192262306a36Sopenharmony_ci	case BR_STATE_DISABLED:
192362306a36Sopenharmony_ci	case BR_STATE_BLOCKING:
192462306a36Sopenharmony_ci	case BR_STATE_LISTENING:
192562306a36Sopenharmony_ci		state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING;
192662306a36Sopenharmony_ci		break;
192762306a36Sopenharmony_ci	case BR_STATE_LEARNING:
192862306a36Sopenharmony_ci		state = MV88E6XXX_PORT_CTL0_STATE_LEARNING;
192962306a36Sopenharmony_ci		break;
193062306a36Sopenharmony_ci	case BR_STATE_FORWARDING:
193162306a36Sopenharmony_ci		state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
193262306a36Sopenharmony_ci		break;
193362306a36Sopenharmony_ci	default:
193462306a36Sopenharmony_ci		return -EINVAL;
193562306a36Sopenharmony_ci	}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	list_for_each_entry(mst, &chip->msts, node) {
193862306a36Sopenharmony_ci		if (mst->br == dsa_port_bridge_dev_get(dp) &&
193962306a36Sopenharmony_ci		    mst->msti == st->msti) {
194062306a36Sopenharmony_ci			if (mst->stu.state[port] == state)
194162306a36Sopenharmony_ci				return 0;
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci			mst->stu.state[port] = state;
194462306a36Sopenharmony_ci			mv88e6xxx_reg_lock(chip);
194562306a36Sopenharmony_ci			err = mv88e6xxx_stu_loadpurge(chip, &mst->stu);
194662306a36Sopenharmony_ci			mv88e6xxx_reg_unlock(chip);
194762306a36Sopenharmony_ci			return err;
194862306a36Sopenharmony_ci		}
194962306a36Sopenharmony_ci	}
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	return -ENOENT;
195262306a36Sopenharmony_ci}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_cistatic int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
195562306a36Sopenharmony_ci					u16 vid)
195662306a36Sopenharmony_ci{
195762306a36Sopenharmony_ci	struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
195862306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
195962306a36Sopenharmony_ci	struct mv88e6xxx_vtu_entry vlan;
196062306a36Sopenharmony_ci	int err;
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	/* DSA and CPU ports have to be members of multiple vlans */
196362306a36Sopenharmony_ci	if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp))
196462306a36Sopenharmony_ci		return 0;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
196762306a36Sopenharmony_ci	if (err)
196862306a36Sopenharmony_ci		return err;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	if (!vlan.valid)
197162306a36Sopenharmony_ci		return 0;
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	dsa_switch_for_each_user_port(other_dp, ds) {
197462306a36Sopenharmony_ci		struct net_device *other_br;
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci		if (vlan.member[other_dp->index] ==
197762306a36Sopenharmony_ci		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
197862306a36Sopenharmony_ci			continue;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci		if (dsa_port_bridge_same(dp, other_dp))
198162306a36Sopenharmony_ci			break; /* same bridge, check next VLAN */
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci		other_br = dsa_port_bridge_dev_get(other_dp);
198462306a36Sopenharmony_ci		if (!other_br)
198562306a36Sopenharmony_ci			continue;
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci		dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
198862306a36Sopenharmony_ci			port, vlan.vid, other_dp->index, netdev_name(other_br));
198962306a36Sopenharmony_ci		return -EOPNOTSUPP;
199062306a36Sopenharmony_ci	}
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	return 0;
199362306a36Sopenharmony_ci}
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_cistatic int mv88e6xxx_port_commit_pvid(struct mv88e6xxx_chip *chip, int port)
199662306a36Sopenharmony_ci{
199762306a36Sopenharmony_ci	struct dsa_port *dp = dsa_to_port(chip->ds, port);
199862306a36Sopenharmony_ci	struct net_device *br = dsa_port_bridge_dev_get(dp);
199962306a36Sopenharmony_ci	struct mv88e6xxx_port *p = &chip->ports[port];
200062306a36Sopenharmony_ci	u16 pvid = MV88E6XXX_VID_STANDALONE;
200162306a36Sopenharmony_ci	bool drop_untagged = false;
200262306a36Sopenharmony_ci	int err;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	if (br) {
200562306a36Sopenharmony_ci		if (br_vlan_enabled(br)) {
200662306a36Sopenharmony_ci			pvid = p->bridge_pvid.vid;
200762306a36Sopenharmony_ci			drop_untagged = !p->bridge_pvid.valid;
200862306a36Sopenharmony_ci		} else {
200962306a36Sopenharmony_ci			pvid = MV88E6XXX_VID_BRIDGED;
201062306a36Sopenharmony_ci		}
201162306a36Sopenharmony_ci	}
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	err = mv88e6xxx_port_set_pvid(chip, port, pvid);
201462306a36Sopenharmony_ci	if (err)
201562306a36Sopenharmony_ci		return err;
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	return mv88e6xxx_port_drop_untagged(chip, port, drop_untagged);
201862306a36Sopenharmony_ci}
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
202162306a36Sopenharmony_ci					 bool vlan_filtering,
202262306a36Sopenharmony_ci					 struct netlink_ext_ack *extack)
202362306a36Sopenharmony_ci{
202462306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
202562306a36Sopenharmony_ci	u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
202662306a36Sopenharmony_ci		MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
202762306a36Sopenharmony_ci	int err;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	if (!mv88e6xxx_max_vid(chip))
203062306a36Sopenharmony_ci		return -EOPNOTSUPP;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
203562306a36Sopenharmony_ci	if (err)
203662306a36Sopenharmony_ci		goto unlock;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	err = mv88e6xxx_port_commit_pvid(chip, port);
203962306a36Sopenharmony_ci	if (err)
204062306a36Sopenharmony_ci		goto unlock;
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ciunlock:
204362306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	return err;
204662306a36Sopenharmony_ci}
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_cistatic int
204962306a36Sopenharmony_cimv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
205062306a36Sopenharmony_ci			    const struct switchdev_obj_port_vlan *vlan)
205162306a36Sopenharmony_ci{
205262306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
205362306a36Sopenharmony_ci	int err;
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	if (!mv88e6xxx_max_vid(chip))
205662306a36Sopenharmony_ci		return -EOPNOTSUPP;
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	/* If the requested port doesn't belong to the same bridge as the VLAN
205962306a36Sopenharmony_ci	 * members, do not support it (yet) and fallback to software VLAN.
206062306a36Sopenharmony_ci	 */
206162306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
206262306a36Sopenharmony_ci	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid);
206362306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	return err;
206662306a36Sopenharmony_ci}
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_cistatic int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
206962306a36Sopenharmony_ci					const unsigned char *addr, u16 vid,
207062306a36Sopenharmony_ci					u8 state)
207162306a36Sopenharmony_ci{
207262306a36Sopenharmony_ci	struct mv88e6xxx_atu_entry entry;
207362306a36Sopenharmony_ci	struct mv88e6xxx_vtu_entry vlan;
207462306a36Sopenharmony_ci	u16 fid;
207562306a36Sopenharmony_ci	int err;
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	/* Ports have two private address databases: one for when the port is
207862306a36Sopenharmony_ci	 * standalone and one for when the port is under a bridge and the
207962306a36Sopenharmony_ci	 * 802.1Q mode is disabled. When the port is standalone, DSA wants its
208062306a36Sopenharmony_ci	 * address database to remain 100% empty, so we never load an ATU entry
208162306a36Sopenharmony_ci	 * into a standalone port's database. Therefore, translate the null
208262306a36Sopenharmony_ci	 * VLAN ID into the port's database used for VLAN-unaware bridging.
208362306a36Sopenharmony_ci	 */
208462306a36Sopenharmony_ci	if (vid == 0) {
208562306a36Sopenharmony_ci		fid = MV88E6XXX_FID_BRIDGED;
208662306a36Sopenharmony_ci	} else {
208762306a36Sopenharmony_ci		err = mv88e6xxx_vtu_get(chip, vid, &vlan);
208862306a36Sopenharmony_ci		if (err)
208962306a36Sopenharmony_ci			return err;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci		/* switchdev expects -EOPNOTSUPP to honor software VLANs */
209262306a36Sopenharmony_ci		if (!vlan.valid)
209362306a36Sopenharmony_ci			return -EOPNOTSUPP;
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci		fid = vlan.fid;
209662306a36Sopenharmony_ci	}
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	entry.state = 0;
209962306a36Sopenharmony_ci	ether_addr_copy(entry.mac, addr);
210062306a36Sopenharmony_ci	eth_addr_dec(entry.mac);
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry);
210362306a36Sopenharmony_ci	if (err)
210462306a36Sopenharmony_ci		return err;
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	/* Initialize a fresh ATU entry if it isn't found */
210762306a36Sopenharmony_ci	if (!entry.state || !ether_addr_equal(entry.mac, addr)) {
210862306a36Sopenharmony_ci		memset(&entry, 0, sizeof(entry));
210962306a36Sopenharmony_ci		ether_addr_copy(entry.mac, addr);
211062306a36Sopenharmony_ci	}
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	/* Purge the ATU entry only if no port is using it anymore */
211362306a36Sopenharmony_ci	if (!state) {
211462306a36Sopenharmony_ci		entry.portvec &= ~BIT(port);
211562306a36Sopenharmony_ci		if (!entry.portvec)
211662306a36Sopenharmony_ci			entry.state = 0;
211762306a36Sopenharmony_ci	} else {
211862306a36Sopenharmony_ci		if (state == MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC)
211962306a36Sopenharmony_ci			entry.portvec = BIT(port);
212062306a36Sopenharmony_ci		else
212162306a36Sopenharmony_ci			entry.portvec |= BIT(port);
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci		entry.state = state;
212462306a36Sopenharmony_ci	}
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry);
212762306a36Sopenharmony_ci}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_cistatic int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port,
213062306a36Sopenharmony_ci				  const struct mv88e6xxx_policy *policy)
213162306a36Sopenharmony_ci{
213262306a36Sopenharmony_ci	enum mv88e6xxx_policy_mapping mapping = policy->mapping;
213362306a36Sopenharmony_ci	enum mv88e6xxx_policy_action action = policy->action;
213462306a36Sopenharmony_ci	const u8 *addr = policy->addr;
213562306a36Sopenharmony_ci	u16 vid = policy->vid;
213662306a36Sopenharmony_ci	u8 state;
213762306a36Sopenharmony_ci	int err;
213862306a36Sopenharmony_ci	int id;
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	if (!chip->info->ops->port_set_policy)
214162306a36Sopenharmony_ci		return -EOPNOTSUPP;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	switch (mapping) {
214462306a36Sopenharmony_ci	case MV88E6XXX_POLICY_MAPPING_DA:
214562306a36Sopenharmony_ci	case MV88E6XXX_POLICY_MAPPING_SA:
214662306a36Sopenharmony_ci		if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
214762306a36Sopenharmony_ci			state = 0; /* Dissociate the port and address */
214862306a36Sopenharmony_ci		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
214962306a36Sopenharmony_ci			 is_multicast_ether_addr(addr))
215062306a36Sopenharmony_ci			state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY;
215162306a36Sopenharmony_ci		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
215262306a36Sopenharmony_ci			 is_unicast_ether_addr(addr))
215362306a36Sopenharmony_ci			state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY;
215462306a36Sopenharmony_ci		else
215562306a36Sopenharmony_ci			return -EOPNOTSUPP;
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci		err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
215862306a36Sopenharmony_ci						   state);
215962306a36Sopenharmony_ci		if (err)
216062306a36Sopenharmony_ci			return err;
216162306a36Sopenharmony_ci		break;
216262306a36Sopenharmony_ci	default:
216362306a36Sopenharmony_ci		return -EOPNOTSUPP;
216462306a36Sopenharmony_ci	}
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	/* Skip the port's policy clearing if the mapping is still in use */
216762306a36Sopenharmony_ci	if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
216862306a36Sopenharmony_ci		idr_for_each_entry(&chip->policies, policy, id)
216962306a36Sopenharmony_ci			if (policy->port == port &&
217062306a36Sopenharmony_ci			    policy->mapping == mapping &&
217162306a36Sopenharmony_ci			    policy->action != action)
217262306a36Sopenharmony_ci				return 0;
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	return chip->info->ops->port_set_policy(chip, port, mapping, action);
217562306a36Sopenharmony_ci}
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_cistatic int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port,
217862306a36Sopenharmony_ci				   struct ethtool_rx_flow_spec *fs)
217962306a36Sopenharmony_ci{
218062306a36Sopenharmony_ci	struct ethhdr *mac_entry = &fs->h_u.ether_spec;
218162306a36Sopenharmony_ci	struct ethhdr *mac_mask = &fs->m_u.ether_spec;
218262306a36Sopenharmony_ci	enum mv88e6xxx_policy_mapping mapping;
218362306a36Sopenharmony_ci	enum mv88e6xxx_policy_action action;
218462306a36Sopenharmony_ci	struct mv88e6xxx_policy *policy;
218562306a36Sopenharmony_ci	u16 vid = 0;
218662306a36Sopenharmony_ci	u8 *addr;
218762306a36Sopenharmony_ci	int err;
218862306a36Sopenharmony_ci	int id;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	if (fs->location != RX_CLS_LOC_ANY)
219162306a36Sopenharmony_ci		return -EINVAL;
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	if (fs->ring_cookie == RX_CLS_FLOW_DISC)
219462306a36Sopenharmony_ci		action = MV88E6XXX_POLICY_ACTION_DISCARD;
219562306a36Sopenharmony_ci	else
219662306a36Sopenharmony_ci		return -EOPNOTSUPP;
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci	switch (fs->flow_type & ~FLOW_EXT) {
219962306a36Sopenharmony_ci	case ETHER_FLOW:
220062306a36Sopenharmony_ci		if (!is_zero_ether_addr(mac_mask->h_dest) &&
220162306a36Sopenharmony_ci		    is_zero_ether_addr(mac_mask->h_source)) {
220262306a36Sopenharmony_ci			mapping = MV88E6XXX_POLICY_MAPPING_DA;
220362306a36Sopenharmony_ci			addr = mac_entry->h_dest;
220462306a36Sopenharmony_ci		} else if (is_zero_ether_addr(mac_mask->h_dest) &&
220562306a36Sopenharmony_ci		    !is_zero_ether_addr(mac_mask->h_source)) {
220662306a36Sopenharmony_ci			mapping = MV88E6XXX_POLICY_MAPPING_SA;
220762306a36Sopenharmony_ci			addr = mac_entry->h_source;
220862306a36Sopenharmony_ci		} else {
220962306a36Sopenharmony_ci			/* Cannot support DA and SA mapping in the same rule */
221062306a36Sopenharmony_ci			return -EOPNOTSUPP;
221162306a36Sopenharmony_ci		}
221262306a36Sopenharmony_ci		break;
221362306a36Sopenharmony_ci	default:
221462306a36Sopenharmony_ci		return -EOPNOTSUPP;
221562306a36Sopenharmony_ci	}
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci	if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) {
221862306a36Sopenharmony_ci		if (fs->m_ext.vlan_tci != htons(0xffff))
221962306a36Sopenharmony_ci			return -EOPNOTSUPP;
222062306a36Sopenharmony_ci		vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK;
222162306a36Sopenharmony_ci	}
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci	idr_for_each_entry(&chip->policies, policy, id) {
222462306a36Sopenharmony_ci		if (policy->port == port && policy->mapping == mapping &&
222562306a36Sopenharmony_ci		    policy->action == action && policy->vid == vid &&
222662306a36Sopenharmony_ci		    ether_addr_equal(policy->addr, addr))
222762306a36Sopenharmony_ci			return -EEXIST;
222862306a36Sopenharmony_ci	}
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL);
223162306a36Sopenharmony_ci	if (!policy)
223262306a36Sopenharmony_ci		return -ENOMEM;
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	fs->location = 0;
223562306a36Sopenharmony_ci	err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff,
223662306a36Sopenharmony_ci			    GFP_KERNEL);
223762306a36Sopenharmony_ci	if (err) {
223862306a36Sopenharmony_ci		devm_kfree(chip->dev, policy);
223962306a36Sopenharmony_ci		return err;
224062306a36Sopenharmony_ci	}
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	memcpy(&policy->fs, fs, sizeof(*fs));
224362306a36Sopenharmony_ci	ether_addr_copy(policy->addr, addr);
224462306a36Sopenharmony_ci	policy->mapping = mapping;
224562306a36Sopenharmony_ci	policy->action = action;
224662306a36Sopenharmony_ci	policy->port = port;
224762306a36Sopenharmony_ci	policy->vid = vid;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci	err = mv88e6xxx_policy_apply(chip, port, policy);
225062306a36Sopenharmony_ci	if (err) {
225162306a36Sopenharmony_ci		idr_remove(&chip->policies, fs->location);
225262306a36Sopenharmony_ci		devm_kfree(chip->dev, policy);
225362306a36Sopenharmony_ci		return err;
225462306a36Sopenharmony_ci	}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	return 0;
225762306a36Sopenharmony_ci}
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_cistatic int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,
226062306a36Sopenharmony_ci			       struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
226162306a36Sopenharmony_ci{
226262306a36Sopenharmony_ci	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
226362306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
226462306a36Sopenharmony_ci	struct mv88e6xxx_policy *policy;
226562306a36Sopenharmony_ci	int err;
226662306a36Sopenharmony_ci	int id;
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	switch (rxnfc->cmd) {
227162306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLCNT:
227262306a36Sopenharmony_ci		rxnfc->data = 0;
227362306a36Sopenharmony_ci		rxnfc->data |= RX_CLS_LOC_SPECIAL;
227462306a36Sopenharmony_ci		rxnfc->rule_cnt = 0;
227562306a36Sopenharmony_ci		idr_for_each_entry(&chip->policies, policy, id)
227662306a36Sopenharmony_ci			if (policy->port == port)
227762306a36Sopenharmony_ci				rxnfc->rule_cnt++;
227862306a36Sopenharmony_ci		err = 0;
227962306a36Sopenharmony_ci		break;
228062306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRULE:
228162306a36Sopenharmony_ci		err = -ENOENT;
228262306a36Sopenharmony_ci		policy = idr_find(&chip->policies, fs->location);
228362306a36Sopenharmony_ci		if (policy) {
228462306a36Sopenharmony_ci			memcpy(fs, &policy->fs, sizeof(*fs));
228562306a36Sopenharmony_ci			err = 0;
228662306a36Sopenharmony_ci		}
228762306a36Sopenharmony_ci		break;
228862306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLALL:
228962306a36Sopenharmony_ci		rxnfc->data = 0;
229062306a36Sopenharmony_ci		rxnfc->rule_cnt = 0;
229162306a36Sopenharmony_ci		idr_for_each_entry(&chip->policies, policy, id)
229262306a36Sopenharmony_ci			if (policy->port == port)
229362306a36Sopenharmony_ci				rule_locs[rxnfc->rule_cnt++] = id;
229462306a36Sopenharmony_ci		err = 0;
229562306a36Sopenharmony_ci		break;
229662306a36Sopenharmony_ci	default:
229762306a36Sopenharmony_ci		err = -EOPNOTSUPP;
229862306a36Sopenharmony_ci		break;
229962306a36Sopenharmony_ci	}
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	return err;
230462306a36Sopenharmony_ci}
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_cistatic int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port,
230762306a36Sopenharmony_ci			       struct ethtool_rxnfc *rxnfc)
230862306a36Sopenharmony_ci{
230962306a36Sopenharmony_ci	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
231062306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
231162306a36Sopenharmony_ci	struct mv88e6xxx_policy *policy;
231262306a36Sopenharmony_ci	int err;
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	switch (rxnfc->cmd) {
231762306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLINS:
231862306a36Sopenharmony_ci		err = mv88e6xxx_policy_insert(chip, port, fs);
231962306a36Sopenharmony_ci		break;
232062306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLDEL:
232162306a36Sopenharmony_ci		err = -ENOENT;
232262306a36Sopenharmony_ci		policy = idr_remove(&chip->policies, fs->location);
232362306a36Sopenharmony_ci		if (policy) {
232462306a36Sopenharmony_ci			policy->action = MV88E6XXX_POLICY_ACTION_NORMAL;
232562306a36Sopenharmony_ci			err = mv88e6xxx_policy_apply(chip, port, policy);
232662306a36Sopenharmony_ci			devm_kfree(chip->dev, policy);
232762306a36Sopenharmony_ci		}
232862306a36Sopenharmony_ci		break;
232962306a36Sopenharmony_ci	default:
233062306a36Sopenharmony_ci		err = -EOPNOTSUPP;
233162306a36Sopenharmony_ci		break;
233262306a36Sopenharmony_ci	}
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci	return err;
233762306a36Sopenharmony_ci}
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_cistatic int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
234062306a36Sopenharmony_ci					u16 vid)
234162306a36Sopenharmony_ci{
234262306a36Sopenharmony_ci	u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
234362306a36Sopenharmony_ci	u8 broadcast[ETH_ALEN];
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	eth_broadcast_addr(broadcast);
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci	return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
234862306a36Sopenharmony_ci}
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_cistatic int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
235162306a36Sopenharmony_ci{
235262306a36Sopenharmony_ci	int port;
235362306a36Sopenharmony_ci	int err;
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
235662306a36Sopenharmony_ci		struct dsa_port *dp = dsa_to_port(chip->ds, port);
235762306a36Sopenharmony_ci		struct net_device *brport;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci		if (dsa_is_unused_port(chip->ds, port))
236062306a36Sopenharmony_ci			continue;
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci		brport = dsa_port_to_bridge_port(dp);
236362306a36Sopenharmony_ci		if (brport && !br_port_flag_is_set(brport, BR_BCAST_FLOOD))
236462306a36Sopenharmony_ci			/* Skip bridged user ports where broadcast
236562306a36Sopenharmony_ci			 * flooding is disabled.
236662306a36Sopenharmony_ci			 */
236762306a36Sopenharmony_ci			continue;
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci		err = mv88e6xxx_port_add_broadcast(chip, port, vid);
237062306a36Sopenharmony_ci		if (err)
237162306a36Sopenharmony_ci			return err;
237262306a36Sopenharmony_ci	}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	return 0;
237562306a36Sopenharmony_ci}
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_cistruct mv88e6xxx_port_broadcast_sync_ctx {
237862306a36Sopenharmony_ci	int port;
237962306a36Sopenharmony_ci	bool flood;
238062306a36Sopenharmony_ci};
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_cistatic int
238362306a36Sopenharmony_cimv88e6xxx_port_broadcast_sync_vlan(struct mv88e6xxx_chip *chip,
238462306a36Sopenharmony_ci				   const struct mv88e6xxx_vtu_entry *vlan,
238562306a36Sopenharmony_ci				   void *_ctx)
238662306a36Sopenharmony_ci{
238762306a36Sopenharmony_ci	struct mv88e6xxx_port_broadcast_sync_ctx *ctx = _ctx;
238862306a36Sopenharmony_ci	u8 broadcast[ETH_ALEN];
238962306a36Sopenharmony_ci	u8 state;
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci	if (ctx->flood)
239262306a36Sopenharmony_ci		state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
239362306a36Sopenharmony_ci	else
239462306a36Sopenharmony_ci		state = MV88E6XXX_G1_ATU_DATA_STATE_MC_UNUSED;
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci	eth_broadcast_addr(broadcast);
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	return mv88e6xxx_port_db_load_purge(chip, ctx->port, broadcast,
239962306a36Sopenharmony_ci					    vlan->vid, state);
240062306a36Sopenharmony_ci}
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_cistatic int mv88e6xxx_port_broadcast_sync(struct mv88e6xxx_chip *chip, int port,
240362306a36Sopenharmony_ci					 bool flood)
240462306a36Sopenharmony_ci{
240562306a36Sopenharmony_ci	struct mv88e6xxx_port_broadcast_sync_ctx ctx = {
240662306a36Sopenharmony_ci		.port = port,
240762306a36Sopenharmony_ci		.flood = flood,
240862306a36Sopenharmony_ci	};
240962306a36Sopenharmony_ci	struct mv88e6xxx_vtu_entry vid0 = {
241062306a36Sopenharmony_ci		.vid = 0,
241162306a36Sopenharmony_ci	};
241262306a36Sopenharmony_ci	int err;
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	/* Update the port's private database... */
241562306a36Sopenharmony_ci	err = mv88e6xxx_port_broadcast_sync_vlan(chip, &vid0, &ctx);
241662306a36Sopenharmony_ci	if (err)
241762306a36Sopenharmony_ci		return err;
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	/* ...and the database for all VLANs. */
242062306a36Sopenharmony_ci	return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_broadcast_sync_vlan,
242162306a36Sopenharmony_ci				  &ctx);
242262306a36Sopenharmony_ci}
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port,
242562306a36Sopenharmony_ci				    u16 vid, u8 member, bool warn)
242662306a36Sopenharmony_ci{
242762306a36Sopenharmony_ci	const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
242862306a36Sopenharmony_ci	struct mv88e6xxx_vtu_entry vlan;
242962306a36Sopenharmony_ci	int i, err;
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
243262306a36Sopenharmony_ci	if (err)
243362306a36Sopenharmony_ci		return err;
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	if (!vlan.valid) {
243662306a36Sopenharmony_ci		memset(&vlan, 0, sizeof(vlan));
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci		if (vid == MV88E6XXX_VID_STANDALONE)
243962306a36Sopenharmony_ci			vlan.policy = true;
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci		err = mv88e6xxx_atu_new(chip, &vlan.fid);
244262306a36Sopenharmony_ci		if (err)
244362306a36Sopenharmony_ci			return err;
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
244662306a36Sopenharmony_ci			if (i == port)
244762306a36Sopenharmony_ci				vlan.member[i] = member;
244862306a36Sopenharmony_ci			else
244962306a36Sopenharmony_ci				vlan.member[i] = non_member;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci		vlan.vid = vid;
245262306a36Sopenharmony_ci		vlan.valid = true;
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
245562306a36Sopenharmony_ci		if (err)
245662306a36Sopenharmony_ci			return err;
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci		err = mv88e6xxx_broadcast_setup(chip, vlan.vid);
245962306a36Sopenharmony_ci		if (err)
246062306a36Sopenharmony_ci			return err;
246162306a36Sopenharmony_ci	} else if (vlan.member[port] != member) {
246262306a36Sopenharmony_ci		vlan.member[port] = member;
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
246562306a36Sopenharmony_ci		if (err)
246662306a36Sopenharmony_ci			return err;
246762306a36Sopenharmony_ci	} else if (warn) {
246862306a36Sopenharmony_ci		dev_info(chip->dev, "p%d: already a member of VLAN %d\n",
246962306a36Sopenharmony_ci			 port, vid);
247062306a36Sopenharmony_ci	}
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	return 0;
247362306a36Sopenharmony_ci}
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
247662306a36Sopenharmony_ci				   const struct switchdev_obj_port_vlan *vlan,
247762306a36Sopenharmony_ci				   struct netlink_ext_ack *extack)
247862306a36Sopenharmony_ci{
247962306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
248062306a36Sopenharmony_ci	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
248162306a36Sopenharmony_ci	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
248262306a36Sopenharmony_ci	struct mv88e6xxx_port *p = &chip->ports[port];
248362306a36Sopenharmony_ci	bool warn;
248462306a36Sopenharmony_ci	u8 member;
248562306a36Sopenharmony_ci	int err;
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci	if (!vlan->vid)
248862306a36Sopenharmony_ci		return 0;
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci	err = mv88e6xxx_port_vlan_prepare(ds, port, vlan);
249162306a36Sopenharmony_ci	if (err)
249262306a36Sopenharmony_ci		return err;
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
249562306a36Sopenharmony_ci		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED;
249662306a36Sopenharmony_ci	else if (untagged)
249762306a36Sopenharmony_ci		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED;
249862306a36Sopenharmony_ci	else
249962306a36Sopenharmony_ci		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	/* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port
250262306a36Sopenharmony_ci	 * and then the CPU port. Do not warn for duplicates for the CPU port.
250362306a36Sopenharmony_ci	 */
250462306a36Sopenharmony_ci	warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port);
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	err = mv88e6xxx_port_vlan_join(chip, port, vlan->vid, member, warn);
250962306a36Sopenharmony_ci	if (err) {
251062306a36Sopenharmony_ci		dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
251162306a36Sopenharmony_ci			vlan->vid, untagged ? 'u' : 't');
251262306a36Sopenharmony_ci		goto out;
251362306a36Sopenharmony_ci	}
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	if (pvid) {
251662306a36Sopenharmony_ci		p->bridge_pvid.vid = vlan->vid;
251762306a36Sopenharmony_ci		p->bridge_pvid.valid = true;
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci		err = mv88e6xxx_port_commit_pvid(chip, port);
252062306a36Sopenharmony_ci		if (err)
252162306a36Sopenharmony_ci			goto out;
252262306a36Sopenharmony_ci	} else if (vlan->vid && p->bridge_pvid.vid == vlan->vid) {
252362306a36Sopenharmony_ci		/* The old pvid was reinstalled as a non-pvid VLAN */
252462306a36Sopenharmony_ci		p->bridge_pvid.valid = false;
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci		err = mv88e6xxx_port_commit_pvid(chip, port);
252762306a36Sopenharmony_ci		if (err)
252862306a36Sopenharmony_ci			goto out;
252962306a36Sopenharmony_ci	}
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ciout:
253262306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci	return err;
253562306a36Sopenharmony_ci}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip,
253862306a36Sopenharmony_ci				     int port, u16 vid)
253962306a36Sopenharmony_ci{
254062306a36Sopenharmony_ci	struct mv88e6xxx_vtu_entry vlan;
254162306a36Sopenharmony_ci	int i, err;
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	if (!vid)
254462306a36Sopenharmony_ci		return 0;
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_ci	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
254762306a36Sopenharmony_ci	if (err)
254862306a36Sopenharmony_ci		return err;
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	/* If the VLAN doesn't exist in hardware or the port isn't a member,
255162306a36Sopenharmony_ci	 * tell switchdev that this VLAN is likely handled in software.
255262306a36Sopenharmony_ci	 */
255362306a36Sopenharmony_ci	if (!vlan.valid ||
255462306a36Sopenharmony_ci	    vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
255562306a36Sopenharmony_ci		return -EOPNOTSUPP;
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_ci	vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci	/* keep the VLAN unless all ports are excluded */
256062306a36Sopenharmony_ci	vlan.valid = false;
256162306a36Sopenharmony_ci	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
256262306a36Sopenharmony_ci		if (vlan.member[i] !=
256362306a36Sopenharmony_ci		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
256462306a36Sopenharmony_ci			vlan.valid = true;
256562306a36Sopenharmony_ci			break;
256662306a36Sopenharmony_ci		}
256762306a36Sopenharmony_ci	}
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
257062306a36Sopenharmony_ci	if (err)
257162306a36Sopenharmony_ci		return err;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	if (!vlan.valid) {
257462306a36Sopenharmony_ci		err = mv88e6xxx_mst_put(chip, vlan.sid);
257562306a36Sopenharmony_ci		if (err)
257662306a36Sopenharmony_ci			return err;
257762306a36Sopenharmony_ci	}
257862306a36Sopenharmony_ci
257962306a36Sopenharmony_ci	return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
258062306a36Sopenharmony_ci}
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
258362306a36Sopenharmony_ci				   const struct switchdev_obj_port_vlan *vlan)
258462306a36Sopenharmony_ci{
258562306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
258662306a36Sopenharmony_ci	struct mv88e6xxx_port *p = &chip->ports[port];
258762306a36Sopenharmony_ci	int err = 0;
258862306a36Sopenharmony_ci	u16 pvid;
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	if (!mv88e6xxx_max_vid(chip))
259162306a36Sopenharmony_ci		return -EOPNOTSUPP;
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	/* The ATU removal procedure needs the FID to be mapped in the VTU,
259462306a36Sopenharmony_ci	 * but FDB deletion runs concurrently with VLAN deletion. Flush the DSA
259562306a36Sopenharmony_ci	 * switchdev workqueue to ensure that all FDB entries are deleted
259662306a36Sopenharmony_ci	 * before we remove the VLAN.
259762306a36Sopenharmony_ci	 */
259862306a36Sopenharmony_ci	dsa_flush_workqueue();
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
260362306a36Sopenharmony_ci	if (err)
260462306a36Sopenharmony_ci		goto unlock;
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci	err = mv88e6xxx_port_vlan_leave(chip, port, vlan->vid);
260762306a36Sopenharmony_ci	if (err)
260862306a36Sopenharmony_ci		goto unlock;
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	if (vlan->vid == pvid) {
261162306a36Sopenharmony_ci		p->bridge_pvid.valid = false;
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci		err = mv88e6xxx_port_commit_pvid(chip, port);
261462306a36Sopenharmony_ci		if (err)
261562306a36Sopenharmony_ci			goto unlock;
261662306a36Sopenharmony_ci	}
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ciunlock:
261962306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	return err;
262262306a36Sopenharmony_ci}
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_fast_age(struct dsa_switch *ds, int port, u16 vid)
262562306a36Sopenharmony_ci{
262662306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
262762306a36Sopenharmony_ci	struct mv88e6xxx_vtu_entry vlan;
262862306a36Sopenharmony_ci	int err;
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
263362306a36Sopenharmony_ci	if (err)
263462306a36Sopenharmony_ci		goto unlock;
263562306a36Sopenharmony_ci
263662306a36Sopenharmony_ci	err = mv88e6xxx_port_fast_age_fid(chip, port, vlan.fid);
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ciunlock:
263962306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
264062306a36Sopenharmony_ci
264162306a36Sopenharmony_ci	return err;
264262306a36Sopenharmony_ci}
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_cistatic int mv88e6xxx_vlan_msti_set(struct dsa_switch *ds,
264562306a36Sopenharmony_ci				   struct dsa_bridge bridge,
264662306a36Sopenharmony_ci				   const struct switchdev_vlan_msti *msti)
264762306a36Sopenharmony_ci{
264862306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
264962306a36Sopenharmony_ci	struct mv88e6xxx_vtu_entry vlan;
265062306a36Sopenharmony_ci	u8 old_sid, new_sid;
265162306a36Sopenharmony_ci	int err;
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	if (!mv88e6xxx_has_stu(chip))
265462306a36Sopenharmony_ci		return -EOPNOTSUPP;
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_ci	err = mv88e6xxx_vtu_get(chip, msti->vid, &vlan);
265962306a36Sopenharmony_ci	if (err)
266062306a36Sopenharmony_ci		goto unlock;
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	if (!vlan.valid) {
266362306a36Sopenharmony_ci		err = -EINVAL;
266462306a36Sopenharmony_ci		goto unlock;
266562306a36Sopenharmony_ci	}
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	old_sid = vlan.sid;
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci	err = mv88e6xxx_mst_get(chip, bridge.dev, msti->msti, &new_sid);
267062306a36Sopenharmony_ci	if (err)
267162306a36Sopenharmony_ci		goto unlock;
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci	if (new_sid != old_sid) {
267462306a36Sopenharmony_ci		vlan.sid = new_sid;
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_ci		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
267762306a36Sopenharmony_ci		if (err) {
267862306a36Sopenharmony_ci			mv88e6xxx_mst_put(chip, new_sid);
267962306a36Sopenharmony_ci			goto unlock;
268062306a36Sopenharmony_ci		}
268162306a36Sopenharmony_ci	}
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci	err = mv88e6xxx_mst_put(chip, old_sid);
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ciunlock:
268662306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
268762306a36Sopenharmony_ci	return err;
268862306a36Sopenharmony_ci}
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_cistatic int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
269162306a36Sopenharmony_ci				  const unsigned char *addr, u16 vid,
269262306a36Sopenharmony_ci				  struct dsa_db db)
269362306a36Sopenharmony_ci{
269462306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
269562306a36Sopenharmony_ci	int err;
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
269862306a36Sopenharmony_ci	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
269962306a36Sopenharmony_ci					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
270062306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci	return err;
270362306a36Sopenharmony_ci}
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_cistatic int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
270662306a36Sopenharmony_ci				  const unsigned char *addr, u16 vid,
270762306a36Sopenharmony_ci				  struct dsa_db db)
270862306a36Sopenharmony_ci{
270962306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
271062306a36Sopenharmony_ci	int err;
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
271362306a36Sopenharmony_ci	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
271462306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci	return err;
271762306a36Sopenharmony_ci}
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_cistatic int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
272062306a36Sopenharmony_ci				      u16 fid, u16 vid, int port,
272162306a36Sopenharmony_ci				      dsa_fdb_dump_cb_t *cb, void *data)
272262306a36Sopenharmony_ci{
272362306a36Sopenharmony_ci	struct mv88e6xxx_atu_entry addr;
272462306a36Sopenharmony_ci	bool is_static;
272562306a36Sopenharmony_ci	int err;
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	addr.state = 0;
272862306a36Sopenharmony_ci	eth_broadcast_addr(addr.mac);
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci	do {
273162306a36Sopenharmony_ci		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
273262306a36Sopenharmony_ci		if (err)
273362306a36Sopenharmony_ci			return err;
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci		if (!addr.state)
273662306a36Sopenharmony_ci			break;
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ci		if (addr.trunk || (addr.portvec & BIT(port)) == 0)
273962306a36Sopenharmony_ci			continue;
274062306a36Sopenharmony_ci
274162306a36Sopenharmony_ci		if (!is_unicast_ether_addr(addr.mac))
274262306a36Sopenharmony_ci			continue;
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci		is_static = (addr.state ==
274562306a36Sopenharmony_ci			     MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
274662306a36Sopenharmony_ci		err = cb(addr.mac, vid, is_static, data);
274762306a36Sopenharmony_ci		if (err)
274862306a36Sopenharmony_ci			return err;
274962306a36Sopenharmony_ci	} while (!is_broadcast_ether_addr(addr.mac));
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	return err;
275262306a36Sopenharmony_ci}
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_cistruct mv88e6xxx_port_db_dump_vlan_ctx {
275562306a36Sopenharmony_ci	int port;
275662306a36Sopenharmony_ci	dsa_fdb_dump_cb_t *cb;
275762306a36Sopenharmony_ci	void *data;
275862306a36Sopenharmony_ci};
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_cistatic int mv88e6xxx_port_db_dump_vlan(struct mv88e6xxx_chip *chip,
276162306a36Sopenharmony_ci				       const struct mv88e6xxx_vtu_entry *entry,
276262306a36Sopenharmony_ci				       void *_data)
276362306a36Sopenharmony_ci{
276462306a36Sopenharmony_ci	struct mv88e6xxx_port_db_dump_vlan_ctx *ctx = _data;
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci	return mv88e6xxx_port_db_dump_fid(chip, entry->fid, entry->vid,
276762306a36Sopenharmony_ci					  ctx->port, ctx->cb, ctx->data);
276862306a36Sopenharmony_ci}
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_cistatic int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
277162306a36Sopenharmony_ci				  dsa_fdb_dump_cb_t *cb, void *data)
277262306a36Sopenharmony_ci{
277362306a36Sopenharmony_ci	struct mv88e6xxx_port_db_dump_vlan_ctx ctx = {
277462306a36Sopenharmony_ci		.port = port,
277562306a36Sopenharmony_ci		.cb = cb,
277662306a36Sopenharmony_ci		.data = data,
277762306a36Sopenharmony_ci	};
277862306a36Sopenharmony_ci	u16 fid;
277962306a36Sopenharmony_ci	int err;
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci	/* Dump port's default Filtering Information Database (VLAN ID 0) */
278262306a36Sopenharmony_ci	err = mv88e6xxx_port_get_fid(chip, port, &fid);
278362306a36Sopenharmony_ci	if (err)
278462306a36Sopenharmony_ci		return err;
278562306a36Sopenharmony_ci
278662306a36Sopenharmony_ci	err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data);
278762306a36Sopenharmony_ci	if (err)
278862306a36Sopenharmony_ci		return err;
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_db_dump_vlan, &ctx);
279162306a36Sopenharmony_ci}
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_cistatic int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
279462306a36Sopenharmony_ci				   dsa_fdb_dump_cb_t *cb, void *data)
279562306a36Sopenharmony_ci{
279662306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
279762306a36Sopenharmony_ci	int err;
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
280062306a36Sopenharmony_ci	err = mv88e6xxx_port_db_dump(chip, port, cb, data);
280162306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	return err;
280462306a36Sopenharmony_ci}
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_cistatic int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
280762306a36Sopenharmony_ci				struct dsa_bridge bridge)
280862306a36Sopenharmony_ci{
280962306a36Sopenharmony_ci	struct dsa_switch *ds = chip->ds;
281062306a36Sopenharmony_ci	struct dsa_switch_tree *dst = ds->dst;
281162306a36Sopenharmony_ci	struct dsa_port *dp;
281262306a36Sopenharmony_ci	int err;
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci	list_for_each_entry(dp, &dst->ports, list) {
281562306a36Sopenharmony_ci		if (dsa_port_offloads_bridge(dp, &bridge)) {
281662306a36Sopenharmony_ci			if (dp->ds == ds) {
281762306a36Sopenharmony_ci				/* This is a local bridge group member,
281862306a36Sopenharmony_ci				 * remap its Port VLAN Map.
281962306a36Sopenharmony_ci				 */
282062306a36Sopenharmony_ci				err = mv88e6xxx_port_vlan_map(chip, dp->index);
282162306a36Sopenharmony_ci				if (err)
282262306a36Sopenharmony_ci					return err;
282362306a36Sopenharmony_ci			} else {
282462306a36Sopenharmony_ci				/* This is an external bridge group member,
282562306a36Sopenharmony_ci				 * remap its cross-chip Port VLAN Table entry.
282662306a36Sopenharmony_ci				 */
282762306a36Sopenharmony_ci				err = mv88e6xxx_pvt_map(chip, dp->ds->index,
282862306a36Sopenharmony_ci							dp->index);
282962306a36Sopenharmony_ci				if (err)
283062306a36Sopenharmony_ci					return err;
283162306a36Sopenharmony_ci			}
283262306a36Sopenharmony_ci		}
283362306a36Sopenharmony_ci	}
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci	return 0;
283662306a36Sopenharmony_ci}
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ci/* Treat the software bridge as a virtual single-port switch behind the
283962306a36Sopenharmony_ci * CPU and map in the PVT. First dst->last_switch elements are taken by
284062306a36Sopenharmony_ci * physical switches, so start from beyond that range.
284162306a36Sopenharmony_ci */
284262306a36Sopenharmony_cistatic int mv88e6xxx_map_virtual_bridge_to_pvt(struct dsa_switch *ds,
284362306a36Sopenharmony_ci					       unsigned int bridge_num)
284462306a36Sopenharmony_ci{
284562306a36Sopenharmony_ci	u8 dev = bridge_num + ds->dst->last_switch;
284662306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	return mv88e6xxx_pvt_map(chip, dev, 0);
284962306a36Sopenharmony_ci}
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_cistatic int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
285262306a36Sopenharmony_ci				      struct dsa_bridge bridge,
285362306a36Sopenharmony_ci				      bool *tx_fwd_offload,
285462306a36Sopenharmony_ci				      struct netlink_ext_ack *extack)
285562306a36Sopenharmony_ci{
285662306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
285762306a36Sopenharmony_ci	int err;
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci	err = mv88e6xxx_bridge_map(chip, bridge);
286262306a36Sopenharmony_ci	if (err)
286362306a36Sopenharmony_ci		goto unlock;
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	err = mv88e6xxx_port_set_map_da(chip, port, true);
286662306a36Sopenharmony_ci	if (err)
286762306a36Sopenharmony_ci		goto unlock;
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci	err = mv88e6xxx_port_commit_pvid(chip, port);
287062306a36Sopenharmony_ci	if (err)
287162306a36Sopenharmony_ci		goto unlock;
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	if (mv88e6xxx_has_pvt(chip)) {
287462306a36Sopenharmony_ci		err = mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num);
287562306a36Sopenharmony_ci		if (err)
287662306a36Sopenharmony_ci			goto unlock;
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_ci		*tx_fwd_offload = true;
287962306a36Sopenharmony_ci	}
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ciunlock:
288262306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	return err;
288562306a36Sopenharmony_ci}
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_cistatic void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
288862306a36Sopenharmony_ci					struct dsa_bridge bridge)
288962306a36Sopenharmony_ci{
289062306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
289162306a36Sopenharmony_ci	int err;
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_ci	if (bridge.tx_fwd_offload &&
289662306a36Sopenharmony_ci	    mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num))
289762306a36Sopenharmony_ci		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci	if (mv88e6xxx_bridge_map(chip, bridge) ||
290062306a36Sopenharmony_ci	    mv88e6xxx_port_vlan_map(chip, port))
290162306a36Sopenharmony_ci		dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci	err = mv88e6xxx_port_set_map_da(chip, port, false);
290462306a36Sopenharmony_ci	if (err)
290562306a36Sopenharmony_ci		dev_err(ds->dev,
290662306a36Sopenharmony_ci			"port %d failed to restore map-DA: %pe\n",
290762306a36Sopenharmony_ci			port, ERR_PTR(err));
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_ci	err = mv88e6xxx_port_commit_pvid(chip, port);
291062306a36Sopenharmony_ci	if (err)
291162306a36Sopenharmony_ci		dev_err(ds->dev,
291262306a36Sopenharmony_ci			"port %d failed to restore standalone pvid: %pe\n",
291362306a36Sopenharmony_ci			port, ERR_PTR(err));
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
291662306a36Sopenharmony_ci}
291762306a36Sopenharmony_ci
291862306a36Sopenharmony_cistatic int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds,
291962306a36Sopenharmony_ci					   int tree_index, int sw_index,
292062306a36Sopenharmony_ci					   int port, struct dsa_bridge bridge,
292162306a36Sopenharmony_ci					   struct netlink_ext_ack *extack)
292262306a36Sopenharmony_ci{
292362306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
292462306a36Sopenharmony_ci	int err;
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci	if (tree_index != ds->dst->index)
292762306a36Sopenharmony_ci		return 0;
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
293062306a36Sopenharmony_ci	err = mv88e6xxx_pvt_map(chip, sw_index, port);
293162306a36Sopenharmony_ci	err = err ? : mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num);
293262306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci	return err;
293562306a36Sopenharmony_ci}
293662306a36Sopenharmony_ci
293762306a36Sopenharmony_cistatic void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds,
293862306a36Sopenharmony_ci					     int tree_index, int sw_index,
293962306a36Sopenharmony_ci					     int port, struct dsa_bridge bridge)
294062306a36Sopenharmony_ci{
294162306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ci	if (tree_index != ds->dst->index)
294462306a36Sopenharmony_ci		return;
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
294762306a36Sopenharmony_ci	if (mv88e6xxx_pvt_map(chip, sw_index, port) ||
294862306a36Sopenharmony_ci	    mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num))
294962306a36Sopenharmony_ci		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
295062306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
295162306a36Sopenharmony_ci}
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_cistatic int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
295462306a36Sopenharmony_ci{
295562306a36Sopenharmony_ci	if (chip->info->ops->reset)
295662306a36Sopenharmony_ci		return chip->info->ops->reset(chip);
295762306a36Sopenharmony_ci
295862306a36Sopenharmony_ci	return 0;
295962306a36Sopenharmony_ci}
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_cistatic void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
296262306a36Sopenharmony_ci{
296362306a36Sopenharmony_ci	struct gpio_desc *gpiod = chip->reset;
296462306a36Sopenharmony_ci
296562306a36Sopenharmony_ci	/* If there is a GPIO connected to the reset pin, toggle it */
296662306a36Sopenharmony_ci	if (gpiod) {
296762306a36Sopenharmony_ci		/* If the switch has just been reset and not yet completed
296862306a36Sopenharmony_ci		 * loading EEPROM, the reset may interrupt the I2C transaction
296962306a36Sopenharmony_ci		 * mid-byte, causing the first EEPROM read after the reset
297062306a36Sopenharmony_ci		 * from the wrong location resulting in the switch booting
297162306a36Sopenharmony_ci		 * to wrong mode and inoperable.
297262306a36Sopenharmony_ci		 */
297362306a36Sopenharmony_ci		if (chip->info->ops->get_eeprom)
297462306a36Sopenharmony_ci			mv88e6xxx_g2_eeprom_wait(chip);
297562306a36Sopenharmony_ci
297662306a36Sopenharmony_ci		gpiod_set_value_cansleep(gpiod, 1);
297762306a36Sopenharmony_ci		usleep_range(10000, 20000);
297862306a36Sopenharmony_ci		gpiod_set_value_cansleep(gpiod, 0);
297962306a36Sopenharmony_ci		usleep_range(10000, 20000);
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_ci		if (chip->info->ops->get_eeprom)
298262306a36Sopenharmony_ci			mv88e6xxx_g2_eeprom_wait(chip);
298362306a36Sopenharmony_ci	}
298462306a36Sopenharmony_ci}
298562306a36Sopenharmony_ci
298662306a36Sopenharmony_cistatic int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
298762306a36Sopenharmony_ci{
298862306a36Sopenharmony_ci	int i, err;
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci	/* Set all ports to the Disabled state */
299162306a36Sopenharmony_ci	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
299262306a36Sopenharmony_ci		err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED);
299362306a36Sopenharmony_ci		if (err)
299462306a36Sopenharmony_ci			return err;
299562306a36Sopenharmony_ci	}
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci	/* Wait for transmit queues to drain,
299862306a36Sopenharmony_ci	 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
299962306a36Sopenharmony_ci	 */
300062306a36Sopenharmony_ci	usleep_range(2000, 4000);
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_ci	return 0;
300362306a36Sopenharmony_ci}
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_cistatic int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
300662306a36Sopenharmony_ci{
300762306a36Sopenharmony_ci	int err;
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci	err = mv88e6xxx_disable_ports(chip);
301062306a36Sopenharmony_ci	if (err)
301162306a36Sopenharmony_ci		return err;
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ci	mv88e6xxx_hardware_reset(chip);
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ci	return mv88e6xxx_software_reset(chip);
301662306a36Sopenharmony_ci}
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_cistatic int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
301962306a36Sopenharmony_ci				   enum mv88e6xxx_frame_mode frame,
302062306a36Sopenharmony_ci				   enum mv88e6xxx_egress_mode egress, u16 etype)
302162306a36Sopenharmony_ci{
302262306a36Sopenharmony_ci	int err;
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci	if (!chip->info->ops->port_set_frame_mode)
302562306a36Sopenharmony_ci		return -EOPNOTSUPP;
302662306a36Sopenharmony_ci
302762306a36Sopenharmony_ci	err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
302862306a36Sopenharmony_ci	if (err)
302962306a36Sopenharmony_ci		return err;
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	err = chip->info->ops->port_set_frame_mode(chip, port, frame);
303262306a36Sopenharmony_ci	if (err)
303362306a36Sopenharmony_ci		return err;
303462306a36Sopenharmony_ci
303562306a36Sopenharmony_ci	if (chip->info->ops->port_set_ether_type)
303662306a36Sopenharmony_ci		return chip->info->ops->port_set_ether_type(chip, port, etype);
303762306a36Sopenharmony_ci
303862306a36Sopenharmony_ci	return 0;
303962306a36Sopenharmony_ci}
304062306a36Sopenharmony_ci
304162306a36Sopenharmony_cistatic int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
304262306a36Sopenharmony_ci{
304362306a36Sopenharmony_ci	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
304462306a36Sopenharmony_ci				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
304562306a36Sopenharmony_ci				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
304662306a36Sopenharmony_ci}
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_cistatic int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
304962306a36Sopenharmony_ci{
305062306a36Sopenharmony_ci	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
305162306a36Sopenharmony_ci				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
305262306a36Sopenharmony_ci				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
305362306a36Sopenharmony_ci}
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_cistatic int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
305662306a36Sopenharmony_ci{
305762306a36Sopenharmony_ci	return mv88e6xxx_set_port_mode(chip, port,
305862306a36Sopenharmony_ci				       MV88E6XXX_FRAME_MODE_ETHERTYPE,
305962306a36Sopenharmony_ci				       MV88E6XXX_EGRESS_MODE_ETHERTYPE,
306062306a36Sopenharmony_ci				       ETH_P_EDSA);
306162306a36Sopenharmony_ci}
306262306a36Sopenharmony_ci
306362306a36Sopenharmony_cistatic int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port)
306462306a36Sopenharmony_ci{
306562306a36Sopenharmony_ci	if (dsa_is_dsa_port(chip->ds, port))
306662306a36Sopenharmony_ci		return mv88e6xxx_set_port_mode_dsa(chip, port);
306762306a36Sopenharmony_ci
306862306a36Sopenharmony_ci	if (dsa_is_user_port(chip->ds, port))
306962306a36Sopenharmony_ci		return mv88e6xxx_set_port_mode_normal(chip, port);
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci	/* Setup CPU port mode depending on its supported tag format */
307262306a36Sopenharmony_ci	if (chip->tag_protocol == DSA_TAG_PROTO_DSA)
307362306a36Sopenharmony_ci		return mv88e6xxx_set_port_mode_dsa(chip, port);
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ci	if (chip->tag_protocol == DSA_TAG_PROTO_EDSA)
307662306a36Sopenharmony_ci		return mv88e6xxx_set_port_mode_edsa(chip, port);
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci	return -EINVAL;
307962306a36Sopenharmony_ci}
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_cistatic int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
308262306a36Sopenharmony_ci{
308362306a36Sopenharmony_ci	bool message = dsa_is_dsa_port(chip->ds, port);
308462306a36Sopenharmony_ci
308562306a36Sopenharmony_ci	return mv88e6xxx_port_set_message_port(chip, port, message);
308662306a36Sopenharmony_ci}
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_cistatic int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
308962306a36Sopenharmony_ci{
309062306a36Sopenharmony_ci	int err;
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci	if (chip->info->ops->port_set_ucast_flood) {
309362306a36Sopenharmony_ci		err = chip->info->ops->port_set_ucast_flood(chip, port, true);
309462306a36Sopenharmony_ci		if (err)
309562306a36Sopenharmony_ci			return err;
309662306a36Sopenharmony_ci	}
309762306a36Sopenharmony_ci	if (chip->info->ops->port_set_mcast_flood) {
309862306a36Sopenharmony_ci		err = chip->info->ops->port_set_mcast_flood(chip, port, true);
309962306a36Sopenharmony_ci		if (err)
310062306a36Sopenharmony_ci			return err;
310162306a36Sopenharmony_ci	}
310262306a36Sopenharmony_ci
310362306a36Sopenharmony_ci	return 0;
310462306a36Sopenharmony_ci}
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_cistatic int mv88e6xxx_set_egress_port(struct mv88e6xxx_chip *chip,
310762306a36Sopenharmony_ci				     enum mv88e6xxx_egress_direction direction,
310862306a36Sopenharmony_ci				     int port)
310962306a36Sopenharmony_ci{
311062306a36Sopenharmony_ci	int err;
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_ci	if (!chip->info->ops->set_egress_port)
311362306a36Sopenharmony_ci		return -EOPNOTSUPP;
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci	err = chip->info->ops->set_egress_port(chip, direction, port);
311662306a36Sopenharmony_ci	if (err)
311762306a36Sopenharmony_ci		return err;
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	if (direction == MV88E6XXX_EGRESS_DIR_INGRESS)
312062306a36Sopenharmony_ci		chip->ingress_dest_port = port;
312162306a36Sopenharmony_ci	else
312262306a36Sopenharmony_ci		chip->egress_dest_port = port;
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_ci	return 0;
312562306a36Sopenharmony_ci}
312662306a36Sopenharmony_ci
312762306a36Sopenharmony_cistatic int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
312862306a36Sopenharmony_ci{
312962306a36Sopenharmony_ci	struct dsa_switch *ds = chip->ds;
313062306a36Sopenharmony_ci	int upstream_port;
313162306a36Sopenharmony_ci	int err;
313262306a36Sopenharmony_ci
313362306a36Sopenharmony_ci	upstream_port = dsa_upstream_port(ds, port);
313462306a36Sopenharmony_ci	if (chip->info->ops->port_set_upstream_port) {
313562306a36Sopenharmony_ci		err = chip->info->ops->port_set_upstream_port(chip, port,
313662306a36Sopenharmony_ci							      upstream_port);
313762306a36Sopenharmony_ci		if (err)
313862306a36Sopenharmony_ci			return err;
313962306a36Sopenharmony_ci	}
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ci	if (port == upstream_port) {
314262306a36Sopenharmony_ci		if (chip->info->ops->set_cpu_port) {
314362306a36Sopenharmony_ci			err = chip->info->ops->set_cpu_port(chip,
314462306a36Sopenharmony_ci							    upstream_port);
314562306a36Sopenharmony_ci			if (err)
314662306a36Sopenharmony_ci				return err;
314762306a36Sopenharmony_ci		}
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci		err = mv88e6xxx_set_egress_port(chip,
315062306a36Sopenharmony_ci						MV88E6XXX_EGRESS_DIR_INGRESS,
315162306a36Sopenharmony_ci						upstream_port);
315262306a36Sopenharmony_ci		if (err && err != -EOPNOTSUPP)
315362306a36Sopenharmony_ci			return err;
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_ci		err = mv88e6xxx_set_egress_port(chip,
315662306a36Sopenharmony_ci						MV88E6XXX_EGRESS_DIR_EGRESS,
315762306a36Sopenharmony_ci						upstream_port);
315862306a36Sopenharmony_ci		if (err && err != -EOPNOTSUPP)
315962306a36Sopenharmony_ci			return err;
316062306a36Sopenharmony_ci	}
316162306a36Sopenharmony_ci
316262306a36Sopenharmony_ci	return 0;
316362306a36Sopenharmony_ci}
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_cistatic int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
316662306a36Sopenharmony_ci{
316762306a36Sopenharmony_ci	struct device_node *phy_handle = NULL;
316862306a36Sopenharmony_ci	struct dsa_switch *ds = chip->ds;
316962306a36Sopenharmony_ci	struct dsa_port *dp;
317062306a36Sopenharmony_ci	int tx_amp;
317162306a36Sopenharmony_ci	int err;
317262306a36Sopenharmony_ci	u16 reg;
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci	chip->ports[port].chip = chip;
317562306a36Sopenharmony_ci	chip->ports[port].port = port;
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci	err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
317862306a36Sopenharmony_ci				       SPEED_UNFORCED, DUPLEX_UNFORCED,
317962306a36Sopenharmony_ci				       PAUSE_ON, PHY_INTERFACE_MODE_NA);
318062306a36Sopenharmony_ci	if (err)
318162306a36Sopenharmony_ci		return err;
318262306a36Sopenharmony_ci
318362306a36Sopenharmony_ci	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
318462306a36Sopenharmony_ci	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
318562306a36Sopenharmony_ci	 * tunneling, determine priority by looking at 802.1p and IP
318662306a36Sopenharmony_ci	 * priority fields (IP prio has precedence), and set STP state
318762306a36Sopenharmony_ci	 * to Forwarding.
318862306a36Sopenharmony_ci	 *
318962306a36Sopenharmony_ci	 * If this is the CPU link, use DSA or EDSA tagging depending
319062306a36Sopenharmony_ci	 * on which tagging mode was configured.
319162306a36Sopenharmony_ci	 *
319262306a36Sopenharmony_ci	 * If this is a link to another switch, use DSA tagging mode.
319362306a36Sopenharmony_ci	 *
319462306a36Sopenharmony_ci	 * If this is the upstream port for this switch, enable
319562306a36Sopenharmony_ci	 * forwarding of unknown unicasts and multicasts.
319662306a36Sopenharmony_ci	 */
319762306a36Sopenharmony_ci	reg = MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
319862306a36Sopenharmony_ci		MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
319962306a36Sopenharmony_ci	/* Forward any IPv4 IGMP or IPv6 MLD frames received
320062306a36Sopenharmony_ci	 * by a USER port to the CPU port to allow snooping.
320162306a36Sopenharmony_ci	 */
320262306a36Sopenharmony_ci	if (dsa_is_user_port(ds, port))
320362306a36Sopenharmony_ci		reg |= MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP;
320462306a36Sopenharmony_ci
320562306a36Sopenharmony_ci	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
320662306a36Sopenharmony_ci	if (err)
320762306a36Sopenharmony_ci		return err;
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	err = mv88e6xxx_setup_port_mode(chip, port);
321062306a36Sopenharmony_ci	if (err)
321162306a36Sopenharmony_ci		return err;
321262306a36Sopenharmony_ci
321362306a36Sopenharmony_ci	err = mv88e6xxx_setup_egress_floods(chip, port);
321462306a36Sopenharmony_ci	if (err)
321562306a36Sopenharmony_ci		return err;
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci	/* Port Control 2: don't force a good FCS, set the MTU size to
321862306a36Sopenharmony_ci	 * 10222 bytes, disable 802.1q tags checking, don't discard
321962306a36Sopenharmony_ci	 * tagged or untagged frames on this port, skip destination
322062306a36Sopenharmony_ci	 * address lookup on user ports, disable ARP mirroring and don't
322162306a36Sopenharmony_ci	 * send a copy of all transmitted/received frames on this port
322262306a36Sopenharmony_ci	 * to the CPU.
322362306a36Sopenharmony_ci	 */
322462306a36Sopenharmony_ci	err = mv88e6xxx_port_set_map_da(chip, port, !dsa_is_user_port(ds, port));
322562306a36Sopenharmony_ci	if (err)
322662306a36Sopenharmony_ci		return err;
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci	err = mv88e6xxx_setup_upstream_port(chip, port);
322962306a36Sopenharmony_ci	if (err)
323062306a36Sopenharmony_ci		return err;
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci	/* On chips that support it, set all downstream DSA ports'
323362306a36Sopenharmony_ci	 * VLAN policy to TRAP. In combination with loading
323462306a36Sopenharmony_ci	 * MV88E6XXX_VID_STANDALONE as a policy entry in the VTU, this
323562306a36Sopenharmony_ci	 * provides a better isolation barrier between standalone
323662306a36Sopenharmony_ci	 * ports, as the ATU is bypassed on any intermediate switches
323762306a36Sopenharmony_ci	 * between the incoming port and the CPU.
323862306a36Sopenharmony_ci	 */
323962306a36Sopenharmony_ci	if (dsa_is_downstream_port(ds, port) &&
324062306a36Sopenharmony_ci	    chip->info->ops->port_set_policy) {
324162306a36Sopenharmony_ci		err = chip->info->ops->port_set_policy(chip, port,
324262306a36Sopenharmony_ci						MV88E6XXX_POLICY_MAPPING_VTU,
324362306a36Sopenharmony_ci						MV88E6XXX_POLICY_ACTION_TRAP);
324462306a36Sopenharmony_ci		if (err)
324562306a36Sopenharmony_ci			return err;
324662306a36Sopenharmony_ci	}
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci	/* User ports start out in standalone mode and 802.1Q is
324962306a36Sopenharmony_ci	 * therefore disabled. On DSA ports, all valid VIDs are always
325062306a36Sopenharmony_ci	 * loaded in the VTU - therefore, enable 802.1Q in order to take
325162306a36Sopenharmony_ci	 * advantage of VLAN policy on chips that supports it.
325262306a36Sopenharmony_ci	 */
325362306a36Sopenharmony_ci	err = mv88e6xxx_port_set_8021q_mode(chip, port,
325462306a36Sopenharmony_ci				dsa_is_user_port(ds, port) ?
325562306a36Sopenharmony_ci				MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED :
325662306a36Sopenharmony_ci				MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE);
325762306a36Sopenharmony_ci	if (err)
325862306a36Sopenharmony_ci		return err;
325962306a36Sopenharmony_ci
326062306a36Sopenharmony_ci	/* Bind MV88E6XXX_VID_STANDALONE to MV88E6XXX_FID_STANDALONE by
326162306a36Sopenharmony_ci	 * virtue of the fact that mv88e6xxx_atu_new() will pick it as
326262306a36Sopenharmony_ci	 * the first free FID. This will be used as the private PVID for
326362306a36Sopenharmony_ci	 * unbridged ports. Shared (DSA and CPU) ports must also be
326462306a36Sopenharmony_ci	 * members of this VID, in order to trap all frames assigned to
326562306a36Sopenharmony_ci	 * it to the CPU.
326662306a36Sopenharmony_ci	 */
326762306a36Sopenharmony_ci	err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_STANDALONE,
326862306a36Sopenharmony_ci				       MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED,
326962306a36Sopenharmony_ci				       false);
327062306a36Sopenharmony_ci	if (err)
327162306a36Sopenharmony_ci		return err;
327262306a36Sopenharmony_ci
327362306a36Sopenharmony_ci	/* Associate MV88E6XXX_VID_BRIDGED with MV88E6XXX_FID_BRIDGED in the
327462306a36Sopenharmony_ci	 * ATU by virtue of the fact that mv88e6xxx_atu_new() will pick it as
327562306a36Sopenharmony_ci	 * the first free FID after MV88E6XXX_FID_STANDALONE. This will be used
327662306a36Sopenharmony_ci	 * as the private PVID on ports under a VLAN-unaware bridge.
327762306a36Sopenharmony_ci	 * Shared (DSA and CPU) ports must also be members of it, to translate
327862306a36Sopenharmony_ci	 * the VID from the DSA tag into MV88E6XXX_FID_BRIDGED, instead of
327962306a36Sopenharmony_ci	 * relying on their port default FID.
328062306a36Sopenharmony_ci	 */
328162306a36Sopenharmony_ci	err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_BRIDGED,
328262306a36Sopenharmony_ci				       MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED,
328362306a36Sopenharmony_ci				       false);
328462306a36Sopenharmony_ci	if (err)
328562306a36Sopenharmony_ci		return err;
328662306a36Sopenharmony_ci
328762306a36Sopenharmony_ci	if (chip->info->ops->port_set_jumbo_size) {
328862306a36Sopenharmony_ci		err = chip->info->ops->port_set_jumbo_size(chip, port, 10218);
328962306a36Sopenharmony_ci		if (err)
329062306a36Sopenharmony_ci			return err;
329162306a36Sopenharmony_ci	}
329262306a36Sopenharmony_ci
329362306a36Sopenharmony_ci	/* Port Association Vector: disable automatic address learning
329462306a36Sopenharmony_ci	 * on all user ports since they start out in standalone
329562306a36Sopenharmony_ci	 * mode. When joining a bridge, learning will be configured to
329662306a36Sopenharmony_ci	 * match the bridge port settings. Enable learning on all
329762306a36Sopenharmony_ci	 * DSA/CPU ports. NOTE: FROM_CPU frames always bypass the
329862306a36Sopenharmony_ci	 * learning process.
329962306a36Sopenharmony_ci	 *
330062306a36Sopenharmony_ci	 * Disable HoldAt1, IntOnAgeOut, LockedPort, IgnoreWrongData,
330162306a36Sopenharmony_ci	 * and RefreshLocked. I.e. setup standard automatic learning.
330262306a36Sopenharmony_ci	 */
330362306a36Sopenharmony_ci	if (dsa_is_user_port(ds, port))
330462306a36Sopenharmony_ci		reg = 0;
330562306a36Sopenharmony_ci	else
330662306a36Sopenharmony_ci		reg = 1 << port;
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
330962306a36Sopenharmony_ci				   reg);
331062306a36Sopenharmony_ci	if (err)
331162306a36Sopenharmony_ci		return err;
331262306a36Sopenharmony_ci
331362306a36Sopenharmony_ci	/* Egress rate control 2: disable egress rate control. */
331462306a36Sopenharmony_ci	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2,
331562306a36Sopenharmony_ci				   0x0000);
331662306a36Sopenharmony_ci	if (err)
331762306a36Sopenharmony_ci		return err;
331862306a36Sopenharmony_ci
331962306a36Sopenharmony_ci	if (chip->info->ops->port_pause_limit) {
332062306a36Sopenharmony_ci		err = chip->info->ops->port_pause_limit(chip, port, 0, 0);
332162306a36Sopenharmony_ci		if (err)
332262306a36Sopenharmony_ci			return err;
332362306a36Sopenharmony_ci	}
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci	if (chip->info->ops->port_disable_learn_limit) {
332662306a36Sopenharmony_ci		err = chip->info->ops->port_disable_learn_limit(chip, port);
332762306a36Sopenharmony_ci		if (err)
332862306a36Sopenharmony_ci			return err;
332962306a36Sopenharmony_ci	}
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_ci	if (chip->info->ops->port_disable_pri_override) {
333262306a36Sopenharmony_ci		err = chip->info->ops->port_disable_pri_override(chip, port);
333362306a36Sopenharmony_ci		if (err)
333462306a36Sopenharmony_ci			return err;
333562306a36Sopenharmony_ci	}
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ci	if (chip->info->ops->port_tag_remap) {
333862306a36Sopenharmony_ci		err = chip->info->ops->port_tag_remap(chip, port);
333962306a36Sopenharmony_ci		if (err)
334062306a36Sopenharmony_ci			return err;
334162306a36Sopenharmony_ci	}
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_ci	if (chip->info->ops->port_egress_rate_limiting) {
334462306a36Sopenharmony_ci		err = chip->info->ops->port_egress_rate_limiting(chip, port);
334562306a36Sopenharmony_ci		if (err)
334662306a36Sopenharmony_ci			return err;
334762306a36Sopenharmony_ci	}
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci	if (chip->info->ops->port_setup_message_port) {
335062306a36Sopenharmony_ci		err = chip->info->ops->port_setup_message_port(chip, port);
335162306a36Sopenharmony_ci		if (err)
335262306a36Sopenharmony_ci			return err;
335362306a36Sopenharmony_ci	}
335462306a36Sopenharmony_ci
335562306a36Sopenharmony_ci	if (chip->info->ops->serdes_set_tx_amplitude) {
335662306a36Sopenharmony_ci		dp = dsa_to_port(ds, port);
335762306a36Sopenharmony_ci		if (dp)
335862306a36Sopenharmony_ci			phy_handle = of_parse_phandle(dp->dn, "phy-handle", 0);
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci		if (phy_handle && !of_property_read_u32(phy_handle,
336162306a36Sopenharmony_ci							"tx-p2p-microvolt",
336262306a36Sopenharmony_ci							&tx_amp))
336362306a36Sopenharmony_ci			err = chip->info->ops->serdes_set_tx_amplitude(chip,
336462306a36Sopenharmony_ci								port, tx_amp);
336562306a36Sopenharmony_ci		if (phy_handle) {
336662306a36Sopenharmony_ci			of_node_put(phy_handle);
336762306a36Sopenharmony_ci			if (err)
336862306a36Sopenharmony_ci				return err;
336962306a36Sopenharmony_ci		}
337062306a36Sopenharmony_ci	}
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ci	/* Port based VLAN map: give each port the same default address
337362306a36Sopenharmony_ci	 * database, and allow bidirectional communication between the
337462306a36Sopenharmony_ci	 * CPU and DSA port(s), and the other ports.
337562306a36Sopenharmony_ci	 */
337662306a36Sopenharmony_ci	err = mv88e6xxx_port_set_fid(chip, port, MV88E6XXX_FID_STANDALONE);
337762306a36Sopenharmony_ci	if (err)
337862306a36Sopenharmony_ci		return err;
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci	err = mv88e6xxx_port_vlan_map(chip, port);
338162306a36Sopenharmony_ci	if (err)
338262306a36Sopenharmony_ci		return err;
338362306a36Sopenharmony_ci
338462306a36Sopenharmony_ci	/* Default VLAN ID and priority: don't set a default VLAN
338562306a36Sopenharmony_ci	 * ID, and set the default packet priority to zero.
338662306a36Sopenharmony_ci	 */
338762306a36Sopenharmony_ci	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0);
338862306a36Sopenharmony_ci}
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_cistatic int mv88e6xxx_get_max_mtu(struct dsa_switch *ds, int port)
339162306a36Sopenharmony_ci{
339262306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
339362306a36Sopenharmony_ci
339462306a36Sopenharmony_ci	if (chip->info->ops->port_set_jumbo_size)
339562306a36Sopenharmony_ci		return 10240 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN;
339662306a36Sopenharmony_ci	else if (chip->info->ops->set_max_frame_size)
339762306a36Sopenharmony_ci		return 1632 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN;
339862306a36Sopenharmony_ci	return ETH_DATA_LEN;
339962306a36Sopenharmony_ci}
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_cistatic int mv88e6xxx_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
340262306a36Sopenharmony_ci{
340362306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
340462306a36Sopenharmony_ci	int ret = 0;
340562306a36Sopenharmony_ci
340662306a36Sopenharmony_ci	/* For families where we don't know how to alter the MTU,
340762306a36Sopenharmony_ci	 * just accept any value up to ETH_DATA_LEN
340862306a36Sopenharmony_ci	 */
340962306a36Sopenharmony_ci	if (!chip->info->ops->port_set_jumbo_size &&
341062306a36Sopenharmony_ci	    !chip->info->ops->set_max_frame_size) {
341162306a36Sopenharmony_ci		if (new_mtu > ETH_DATA_LEN)
341262306a36Sopenharmony_ci			return -EINVAL;
341362306a36Sopenharmony_ci
341462306a36Sopenharmony_ci		return 0;
341562306a36Sopenharmony_ci	}
341662306a36Sopenharmony_ci
341762306a36Sopenharmony_ci	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
341862306a36Sopenharmony_ci		new_mtu += EDSA_HLEN;
341962306a36Sopenharmony_ci
342062306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
342162306a36Sopenharmony_ci	if (chip->info->ops->port_set_jumbo_size)
342262306a36Sopenharmony_ci		ret = chip->info->ops->port_set_jumbo_size(chip, port, new_mtu);
342362306a36Sopenharmony_ci	else if (chip->info->ops->set_max_frame_size)
342462306a36Sopenharmony_ci		ret = chip->info->ops->set_max_frame_size(chip, new_mtu);
342562306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_ci	return ret;
342862306a36Sopenharmony_ci}
342962306a36Sopenharmony_ci
343062306a36Sopenharmony_cistatic int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
343162306a36Sopenharmony_ci				     unsigned int ageing_time)
343262306a36Sopenharmony_ci{
343362306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
343462306a36Sopenharmony_ci	int err;
343562306a36Sopenharmony_ci
343662306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
343762306a36Sopenharmony_ci	err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
343862306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci	return err;
344162306a36Sopenharmony_ci}
344262306a36Sopenharmony_ci
344362306a36Sopenharmony_cistatic int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
344462306a36Sopenharmony_ci{
344562306a36Sopenharmony_ci	int err;
344662306a36Sopenharmony_ci
344762306a36Sopenharmony_ci	/* Initialize the statistics unit */
344862306a36Sopenharmony_ci	if (chip->info->ops->stats_set_histogram) {
344962306a36Sopenharmony_ci		err = chip->info->ops->stats_set_histogram(chip);
345062306a36Sopenharmony_ci		if (err)
345162306a36Sopenharmony_ci			return err;
345262306a36Sopenharmony_ci	}
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ci	return mv88e6xxx_g1_stats_clear(chip);
345562306a36Sopenharmony_ci}
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci/* Check if the errata has already been applied. */
345862306a36Sopenharmony_cistatic bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
345962306a36Sopenharmony_ci{
346062306a36Sopenharmony_ci	int port;
346162306a36Sopenharmony_ci	int err;
346262306a36Sopenharmony_ci	u16 val;
346362306a36Sopenharmony_ci
346462306a36Sopenharmony_ci	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
346562306a36Sopenharmony_ci		err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val);
346662306a36Sopenharmony_ci		if (err) {
346762306a36Sopenharmony_ci			dev_err(chip->dev,
346862306a36Sopenharmony_ci				"Error reading hidden register: %d\n", err);
346962306a36Sopenharmony_ci			return false;
347062306a36Sopenharmony_ci		}
347162306a36Sopenharmony_ci		if (val != 0x01c0)
347262306a36Sopenharmony_ci			return false;
347362306a36Sopenharmony_ci	}
347462306a36Sopenharmony_ci
347562306a36Sopenharmony_ci	return true;
347662306a36Sopenharmony_ci}
347762306a36Sopenharmony_ci
347862306a36Sopenharmony_ci/* The 6390 copper ports have an errata which require poking magic
347962306a36Sopenharmony_ci * values into undocumented hidden registers and then performing a
348062306a36Sopenharmony_ci * software reset.
348162306a36Sopenharmony_ci */
348262306a36Sopenharmony_cistatic int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
348362306a36Sopenharmony_ci{
348462306a36Sopenharmony_ci	int port;
348562306a36Sopenharmony_ci	int err;
348662306a36Sopenharmony_ci
348762306a36Sopenharmony_ci	if (mv88e6390_setup_errata_applied(chip))
348862306a36Sopenharmony_ci		return 0;
348962306a36Sopenharmony_ci
349062306a36Sopenharmony_ci	/* Set the ports into blocking mode */
349162306a36Sopenharmony_ci	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
349262306a36Sopenharmony_ci		err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED);
349362306a36Sopenharmony_ci		if (err)
349462306a36Sopenharmony_ci			return err;
349562306a36Sopenharmony_ci	}
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
349862306a36Sopenharmony_ci		err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0);
349962306a36Sopenharmony_ci		if (err)
350062306a36Sopenharmony_ci			return err;
350162306a36Sopenharmony_ci	}
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_ci	return mv88e6xxx_software_reset(chip);
350462306a36Sopenharmony_ci}
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_ci/* prod_id for switch families which do not have a PHY model number */
350762306a36Sopenharmony_cistatic const u16 family_prod_id_table[] = {
350862306a36Sopenharmony_ci	[MV88E6XXX_FAMILY_6341] = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
350962306a36Sopenharmony_ci	[MV88E6XXX_FAMILY_6390] = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
351062306a36Sopenharmony_ci	[MV88E6XXX_FAMILY_6393] = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
351162306a36Sopenharmony_ci};
351262306a36Sopenharmony_ci
351362306a36Sopenharmony_cistatic int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
351462306a36Sopenharmony_ci{
351562306a36Sopenharmony_ci	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
351662306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = mdio_bus->chip;
351762306a36Sopenharmony_ci	u16 prod_id;
351862306a36Sopenharmony_ci	u16 val;
351962306a36Sopenharmony_ci	int err;
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci	if (!chip->info->ops->phy_read)
352262306a36Sopenharmony_ci		return -EOPNOTSUPP;
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
352562306a36Sopenharmony_ci	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
352662306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
352762306a36Sopenharmony_ci
352862306a36Sopenharmony_ci	/* Some internal PHYs don't have a model number. */
352962306a36Sopenharmony_ci	if (reg == MII_PHYSID2 && !(val & 0x3f0) &&
353062306a36Sopenharmony_ci	    chip->info->family < ARRAY_SIZE(family_prod_id_table)) {
353162306a36Sopenharmony_ci		prod_id = family_prod_id_table[chip->info->family];
353262306a36Sopenharmony_ci		if (prod_id)
353362306a36Sopenharmony_ci			val |= prod_id >> 4;
353462306a36Sopenharmony_ci	}
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_ci	return err ? err : val;
353762306a36Sopenharmony_ci}
353862306a36Sopenharmony_ci
353962306a36Sopenharmony_cistatic int mv88e6xxx_mdio_read_c45(struct mii_bus *bus, int phy, int devad,
354062306a36Sopenharmony_ci				   int reg)
354162306a36Sopenharmony_ci{
354262306a36Sopenharmony_ci	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
354362306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = mdio_bus->chip;
354462306a36Sopenharmony_ci	u16 val;
354562306a36Sopenharmony_ci	int err;
354662306a36Sopenharmony_ci
354762306a36Sopenharmony_ci	if (!chip->info->ops->phy_read_c45)
354862306a36Sopenharmony_ci		return 0xffff;
354962306a36Sopenharmony_ci
355062306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
355162306a36Sopenharmony_ci	err = chip->info->ops->phy_read_c45(chip, bus, phy, devad, reg, &val);
355262306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
355362306a36Sopenharmony_ci
355462306a36Sopenharmony_ci	return err ? err : val;
355562306a36Sopenharmony_ci}
355662306a36Sopenharmony_ci
355762306a36Sopenharmony_cistatic int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
355862306a36Sopenharmony_ci{
355962306a36Sopenharmony_ci	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
356062306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = mdio_bus->chip;
356162306a36Sopenharmony_ci	int err;
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci	if (!chip->info->ops->phy_write)
356462306a36Sopenharmony_ci		return -EOPNOTSUPP;
356562306a36Sopenharmony_ci
356662306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
356762306a36Sopenharmony_ci	err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
356862306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci	return err;
357162306a36Sopenharmony_ci}
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_cistatic int mv88e6xxx_mdio_write_c45(struct mii_bus *bus, int phy, int devad,
357462306a36Sopenharmony_ci				    int reg, u16 val)
357562306a36Sopenharmony_ci{
357662306a36Sopenharmony_ci	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
357762306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = mdio_bus->chip;
357862306a36Sopenharmony_ci	int err;
357962306a36Sopenharmony_ci
358062306a36Sopenharmony_ci	if (!chip->info->ops->phy_write_c45)
358162306a36Sopenharmony_ci		return -EOPNOTSUPP;
358262306a36Sopenharmony_ci
358362306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
358462306a36Sopenharmony_ci	err = chip->info->ops->phy_write_c45(chip, bus, phy, devad, reg, val);
358562306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
358662306a36Sopenharmony_ci
358762306a36Sopenharmony_ci	return err;
358862306a36Sopenharmony_ci}
358962306a36Sopenharmony_ci
359062306a36Sopenharmony_cistatic int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
359162306a36Sopenharmony_ci				   struct device_node *np,
359262306a36Sopenharmony_ci				   bool external)
359362306a36Sopenharmony_ci{
359462306a36Sopenharmony_ci	static int index;
359562306a36Sopenharmony_ci	struct mv88e6xxx_mdio_bus *mdio_bus;
359662306a36Sopenharmony_ci	struct mii_bus *bus;
359762306a36Sopenharmony_ci	int err;
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_ci	if (external) {
360062306a36Sopenharmony_ci		mv88e6xxx_reg_lock(chip);
360162306a36Sopenharmony_ci		err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
360262306a36Sopenharmony_ci		mv88e6xxx_reg_unlock(chip);
360362306a36Sopenharmony_ci
360462306a36Sopenharmony_ci		if (err)
360562306a36Sopenharmony_ci			return err;
360662306a36Sopenharmony_ci	}
360762306a36Sopenharmony_ci
360862306a36Sopenharmony_ci	bus = mdiobus_alloc_size(sizeof(*mdio_bus));
360962306a36Sopenharmony_ci	if (!bus)
361062306a36Sopenharmony_ci		return -ENOMEM;
361162306a36Sopenharmony_ci
361262306a36Sopenharmony_ci	mdio_bus = bus->priv;
361362306a36Sopenharmony_ci	mdio_bus->bus = bus;
361462306a36Sopenharmony_ci	mdio_bus->chip = chip;
361562306a36Sopenharmony_ci	INIT_LIST_HEAD(&mdio_bus->list);
361662306a36Sopenharmony_ci	mdio_bus->external = external;
361762306a36Sopenharmony_ci
361862306a36Sopenharmony_ci	if (np) {
361962306a36Sopenharmony_ci		bus->name = np->full_name;
362062306a36Sopenharmony_ci		snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np);
362162306a36Sopenharmony_ci	} else {
362262306a36Sopenharmony_ci		bus->name = "mv88e6xxx SMI";
362362306a36Sopenharmony_ci		snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
362462306a36Sopenharmony_ci	}
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_ci	bus->read = mv88e6xxx_mdio_read;
362762306a36Sopenharmony_ci	bus->write = mv88e6xxx_mdio_write;
362862306a36Sopenharmony_ci	bus->read_c45 = mv88e6xxx_mdio_read_c45;
362962306a36Sopenharmony_ci	bus->write_c45 = mv88e6xxx_mdio_write_c45;
363062306a36Sopenharmony_ci	bus->parent = chip->dev;
363162306a36Sopenharmony_ci	bus->phy_mask = ~GENMASK(chip->info->phy_base_addr +
363262306a36Sopenharmony_ci				 mv88e6xxx_num_ports(chip) - 1,
363362306a36Sopenharmony_ci				 chip->info->phy_base_addr);
363462306a36Sopenharmony_ci
363562306a36Sopenharmony_ci	if (!external) {
363662306a36Sopenharmony_ci		err = mv88e6xxx_g2_irq_mdio_setup(chip, bus);
363762306a36Sopenharmony_ci		if (err)
363862306a36Sopenharmony_ci			goto out;
363962306a36Sopenharmony_ci	}
364062306a36Sopenharmony_ci
364162306a36Sopenharmony_ci	err = of_mdiobus_register(bus, np);
364262306a36Sopenharmony_ci	if (err) {
364362306a36Sopenharmony_ci		dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
364462306a36Sopenharmony_ci		mv88e6xxx_g2_irq_mdio_free(chip, bus);
364562306a36Sopenharmony_ci		goto out;
364662306a36Sopenharmony_ci	}
364762306a36Sopenharmony_ci
364862306a36Sopenharmony_ci	if (external)
364962306a36Sopenharmony_ci		list_add_tail(&mdio_bus->list, &chip->mdios);
365062306a36Sopenharmony_ci	else
365162306a36Sopenharmony_ci		list_add(&mdio_bus->list, &chip->mdios);
365262306a36Sopenharmony_ci
365362306a36Sopenharmony_ci	return 0;
365462306a36Sopenharmony_ci
365562306a36Sopenharmony_ciout:
365662306a36Sopenharmony_ci	mdiobus_free(bus);
365762306a36Sopenharmony_ci	return err;
365862306a36Sopenharmony_ci}
365962306a36Sopenharmony_ci
366062306a36Sopenharmony_cistatic void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
366162306a36Sopenharmony_ci
366262306a36Sopenharmony_ci{
366362306a36Sopenharmony_ci	struct mv88e6xxx_mdio_bus *mdio_bus, *p;
366462306a36Sopenharmony_ci	struct mii_bus *bus;
366562306a36Sopenharmony_ci
366662306a36Sopenharmony_ci	list_for_each_entry_safe(mdio_bus, p, &chip->mdios, list) {
366762306a36Sopenharmony_ci		bus = mdio_bus->bus;
366862306a36Sopenharmony_ci
366962306a36Sopenharmony_ci		if (!mdio_bus->external)
367062306a36Sopenharmony_ci			mv88e6xxx_g2_irq_mdio_free(chip, bus);
367162306a36Sopenharmony_ci
367262306a36Sopenharmony_ci		mdiobus_unregister(bus);
367362306a36Sopenharmony_ci		mdiobus_free(bus);
367462306a36Sopenharmony_ci	}
367562306a36Sopenharmony_ci}
367662306a36Sopenharmony_ci
367762306a36Sopenharmony_cistatic int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip)
367862306a36Sopenharmony_ci{
367962306a36Sopenharmony_ci	struct device_node *np = chip->dev->of_node;
368062306a36Sopenharmony_ci	struct device_node *child;
368162306a36Sopenharmony_ci	int err;
368262306a36Sopenharmony_ci
368362306a36Sopenharmony_ci	/* Always register one mdio bus for the internal/default mdio
368462306a36Sopenharmony_ci	 * bus. This maybe represented in the device tree, but is
368562306a36Sopenharmony_ci	 * optional.
368662306a36Sopenharmony_ci	 */
368762306a36Sopenharmony_ci	child = of_get_child_by_name(np, "mdio");
368862306a36Sopenharmony_ci	err = mv88e6xxx_mdio_register(chip, child, false);
368962306a36Sopenharmony_ci	of_node_put(child);
369062306a36Sopenharmony_ci	if (err)
369162306a36Sopenharmony_ci		return err;
369262306a36Sopenharmony_ci
369362306a36Sopenharmony_ci	/* Walk the device tree, and see if there are any other nodes
369462306a36Sopenharmony_ci	 * which say they are compatible with the external mdio
369562306a36Sopenharmony_ci	 * bus.
369662306a36Sopenharmony_ci	 */
369762306a36Sopenharmony_ci	for_each_available_child_of_node(np, child) {
369862306a36Sopenharmony_ci		if (of_device_is_compatible(
369962306a36Sopenharmony_ci			    child, "marvell,mv88e6xxx-mdio-external")) {
370062306a36Sopenharmony_ci			err = mv88e6xxx_mdio_register(chip, child, true);
370162306a36Sopenharmony_ci			if (err) {
370262306a36Sopenharmony_ci				mv88e6xxx_mdios_unregister(chip);
370362306a36Sopenharmony_ci				of_node_put(child);
370462306a36Sopenharmony_ci				return err;
370562306a36Sopenharmony_ci			}
370662306a36Sopenharmony_ci		}
370762306a36Sopenharmony_ci	}
370862306a36Sopenharmony_ci
370962306a36Sopenharmony_ci	return 0;
371062306a36Sopenharmony_ci}
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_cistatic void mv88e6xxx_teardown(struct dsa_switch *ds)
371362306a36Sopenharmony_ci{
371462306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
371562306a36Sopenharmony_ci
371662306a36Sopenharmony_ci	mv88e6xxx_teardown_devlink_params(ds);
371762306a36Sopenharmony_ci	dsa_devlink_resources_unregister(ds);
371862306a36Sopenharmony_ci	mv88e6xxx_teardown_devlink_regions_global(ds);
371962306a36Sopenharmony_ci	mv88e6xxx_mdios_unregister(chip);
372062306a36Sopenharmony_ci}
372162306a36Sopenharmony_ci
372262306a36Sopenharmony_cistatic int mv88e6xxx_setup(struct dsa_switch *ds)
372362306a36Sopenharmony_ci{
372462306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
372562306a36Sopenharmony_ci	u8 cmode;
372662306a36Sopenharmony_ci	int err;
372762306a36Sopenharmony_ci	int i;
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci	err = mv88e6xxx_mdios_register(chip);
373062306a36Sopenharmony_ci	if (err)
373162306a36Sopenharmony_ci		return err;
373262306a36Sopenharmony_ci
373362306a36Sopenharmony_ci	chip->ds = ds;
373462306a36Sopenharmony_ci	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_ci	/* Since virtual bridges are mapped in the PVT, the number we support
373762306a36Sopenharmony_ci	 * depends on the physical switch topology. We need to let DSA figure
373862306a36Sopenharmony_ci	 * that out and therefore we cannot set this at dsa_register_switch()
373962306a36Sopenharmony_ci	 * time.
374062306a36Sopenharmony_ci	 */
374162306a36Sopenharmony_ci	if (mv88e6xxx_has_pvt(chip))
374262306a36Sopenharmony_ci		ds->max_num_bridges = MV88E6XXX_MAX_PVT_SWITCHES -
374362306a36Sopenharmony_ci				      ds->dst->last_switch - 1;
374462306a36Sopenharmony_ci
374562306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
374662306a36Sopenharmony_ci
374762306a36Sopenharmony_ci	if (chip->info->ops->setup_errata) {
374862306a36Sopenharmony_ci		err = chip->info->ops->setup_errata(chip);
374962306a36Sopenharmony_ci		if (err)
375062306a36Sopenharmony_ci			goto unlock;
375162306a36Sopenharmony_ci	}
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci	/* Cache the cmode of each port. */
375462306a36Sopenharmony_ci	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
375562306a36Sopenharmony_ci		if (chip->info->ops->port_get_cmode) {
375662306a36Sopenharmony_ci			err = chip->info->ops->port_get_cmode(chip, i, &cmode);
375762306a36Sopenharmony_ci			if (err)
375862306a36Sopenharmony_ci				goto unlock;
375962306a36Sopenharmony_ci
376062306a36Sopenharmony_ci			chip->ports[i].cmode = cmode;
376162306a36Sopenharmony_ci		}
376262306a36Sopenharmony_ci	}
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ci	err = mv88e6xxx_vtu_setup(chip);
376562306a36Sopenharmony_ci	if (err)
376662306a36Sopenharmony_ci		goto unlock;
376762306a36Sopenharmony_ci
376862306a36Sopenharmony_ci	/* Must be called after mv88e6xxx_vtu_setup (which flushes the
376962306a36Sopenharmony_ci	 * VTU, thereby also flushing the STU).
377062306a36Sopenharmony_ci	 */
377162306a36Sopenharmony_ci	err = mv88e6xxx_stu_setup(chip);
377262306a36Sopenharmony_ci	if (err)
377362306a36Sopenharmony_ci		goto unlock;
377462306a36Sopenharmony_ci
377562306a36Sopenharmony_ci	/* Setup Switch Port Registers */
377662306a36Sopenharmony_ci	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
377762306a36Sopenharmony_ci		if (dsa_is_unused_port(ds, i))
377862306a36Sopenharmony_ci			continue;
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_ci		/* Prevent the use of an invalid port. */
378162306a36Sopenharmony_ci		if (mv88e6xxx_is_invalid_port(chip, i)) {
378262306a36Sopenharmony_ci			dev_err(chip->dev, "port %d is invalid\n", i);
378362306a36Sopenharmony_ci			err = -EINVAL;
378462306a36Sopenharmony_ci			goto unlock;
378562306a36Sopenharmony_ci		}
378662306a36Sopenharmony_ci
378762306a36Sopenharmony_ci		err = mv88e6xxx_setup_port(chip, i);
378862306a36Sopenharmony_ci		if (err)
378962306a36Sopenharmony_ci			goto unlock;
379062306a36Sopenharmony_ci	}
379162306a36Sopenharmony_ci
379262306a36Sopenharmony_ci	err = mv88e6xxx_irl_setup(chip);
379362306a36Sopenharmony_ci	if (err)
379462306a36Sopenharmony_ci		goto unlock;
379562306a36Sopenharmony_ci
379662306a36Sopenharmony_ci	err = mv88e6xxx_mac_setup(chip);
379762306a36Sopenharmony_ci	if (err)
379862306a36Sopenharmony_ci		goto unlock;
379962306a36Sopenharmony_ci
380062306a36Sopenharmony_ci	err = mv88e6xxx_phy_setup(chip);
380162306a36Sopenharmony_ci	if (err)
380262306a36Sopenharmony_ci		goto unlock;
380362306a36Sopenharmony_ci
380462306a36Sopenharmony_ci	err = mv88e6xxx_pvt_setup(chip);
380562306a36Sopenharmony_ci	if (err)
380662306a36Sopenharmony_ci		goto unlock;
380762306a36Sopenharmony_ci
380862306a36Sopenharmony_ci	err = mv88e6xxx_atu_setup(chip);
380962306a36Sopenharmony_ci	if (err)
381062306a36Sopenharmony_ci		goto unlock;
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_ci	err = mv88e6xxx_broadcast_setup(chip, 0);
381362306a36Sopenharmony_ci	if (err)
381462306a36Sopenharmony_ci		goto unlock;
381562306a36Sopenharmony_ci
381662306a36Sopenharmony_ci	err = mv88e6xxx_pot_setup(chip);
381762306a36Sopenharmony_ci	if (err)
381862306a36Sopenharmony_ci		goto unlock;
381962306a36Sopenharmony_ci
382062306a36Sopenharmony_ci	err = mv88e6xxx_rmu_setup(chip);
382162306a36Sopenharmony_ci	if (err)
382262306a36Sopenharmony_ci		goto unlock;
382362306a36Sopenharmony_ci
382462306a36Sopenharmony_ci	err = mv88e6xxx_rsvd2cpu_setup(chip);
382562306a36Sopenharmony_ci	if (err)
382662306a36Sopenharmony_ci		goto unlock;
382762306a36Sopenharmony_ci
382862306a36Sopenharmony_ci	err = mv88e6xxx_trunk_setup(chip);
382962306a36Sopenharmony_ci	if (err)
383062306a36Sopenharmony_ci		goto unlock;
383162306a36Sopenharmony_ci
383262306a36Sopenharmony_ci	err = mv88e6xxx_devmap_setup(chip);
383362306a36Sopenharmony_ci	if (err)
383462306a36Sopenharmony_ci		goto unlock;
383562306a36Sopenharmony_ci
383662306a36Sopenharmony_ci	err = mv88e6xxx_pri_setup(chip);
383762306a36Sopenharmony_ci	if (err)
383862306a36Sopenharmony_ci		goto unlock;
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ci	/* Setup PTP Hardware Clock and timestamping */
384162306a36Sopenharmony_ci	if (chip->info->ptp_support) {
384262306a36Sopenharmony_ci		err = mv88e6xxx_ptp_setup(chip);
384362306a36Sopenharmony_ci		if (err)
384462306a36Sopenharmony_ci			goto unlock;
384562306a36Sopenharmony_ci
384662306a36Sopenharmony_ci		err = mv88e6xxx_hwtstamp_setup(chip);
384762306a36Sopenharmony_ci		if (err)
384862306a36Sopenharmony_ci			goto unlock;
384962306a36Sopenharmony_ci	}
385062306a36Sopenharmony_ci
385162306a36Sopenharmony_ci	err = mv88e6xxx_stats_setup(chip);
385262306a36Sopenharmony_ci	if (err)
385362306a36Sopenharmony_ci		goto unlock;
385462306a36Sopenharmony_ci
385562306a36Sopenharmony_ciunlock:
385662306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
385762306a36Sopenharmony_ci
385862306a36Sopenharmony_ci	if (err)
385962306a36Sopenharmony_ci		goto out_mdios;
386062306a36Sopenharmony_ci
386162306a36Sopenharmony_ci	/* Have to be called without holding the register lock, since
386262306a36Sopenharmony_ci	 * they take the devlink lock, and we later take the locks in
386362306a36Sopenharmony_ci	 * the reverse order when getting/setting parameters or
386462306a36Sopenharmony_ci	 * resource occupancy.
386562306a36Sopenharmony_ci	 */
386662306a36Sopenharmony_ci	err = mv88e6xxx_setup_devlink_resources(ds);
386762306a36Sopenharmony_ci	if (err)
386862306a36Sopenharmony_ci		goto out_mdios;
386962306a36Sopenharmony_ci
387062306a36Sopenharmony_ci	err = mv88e6xxx_setup_devlink_params(ds);
387162306a36Sopenharmony_ci	if (err)
387262306a36Sopenharmony_ci		goto out_resources;
387362306a36Sopenharmony_ci
387462306a36Sopenharmony_ci	err = mv88e6xxx_setup_devlink_regions_global(ds);
387562306a36Sopenharmony_ci	if (err)
387662306a36Sopenharmony_ci		goto out_params;
387762306a36Sopenharmony_ci
387862306a36Sopenharmony_ci	return 0;
387962306a36Sopenharmony_ci
388062306a36Sopenharmony_ciout_params:
388162306a36Sopenharmony_ci	mv88e6xxx_teardown_devlink_params(ds);
388262306a36Sopenharmony_ciout_resources:
388362306a36Sopenharmony_ci	dsa_devlink_resources_unregister(ds);
388462306a36Sopenharmony_ciout_mdios:
388562306a36Sopenharmony_ci	mv88e6xxx_mdios_unregister(chip);
388662306a36Sopenharmony_ci
388762306a36Sopenharmony_ci	return err;
388862306a36Sopenharmony_ci}
388962306a36Sopenharmony_ci
389062306a36Sopenharmony_cistatic int mv88e6xxx_port_setup(struct dsa_switch *ds, int port)
389162306a36Sopenharmony_ci{
389262306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
389362306a36Sopenharmony_ci	int err;
389462306a36Sopenharmony_ci
389562306a36Sopenharmony_ci	if (chip->info->ops->pcs_ops &&
389662306a36Sopenharmony_ci	    chip->info->ops->pcs_ops->pcs_init) {
389762306a36Sopenharmony_ci		err = chip->info->ops->pcs_ops->pcs_init(chip, port);
389862306a36Sopenharmony_ci		if (err)
389962306a36Sopenharmony_ci			return err;
390062306a36Sopenharmony_ci	}
390162306a36Sopenharmony_ci
390262306a36Sopenharmony_ci	return mv88e6xxx_setup_devlink_regions_port(ds, port);
390362306a36Sopenharmony_ci}
390462306a36Sopenharmony_ci
390562306a36Sopenharmony_cistatic void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port)
390662306a36Sopenharmony_ci{
390762306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
390862306a36Sopenharmony_ci
390962306a36Sopenharmony_ci	mv88e6xxx_teardown_devlink_regions_port(ds, port);
391062306a36Sopenharmony_ci
391162306a36Sopenharmony_ci	if (chip->info->ops->pcs_ops &&
391262306a36Sopenharmony_ci	    chip->info->ops->pcs_ops->pcs_teardown)
391362306a36Sopenharmony_ci		chip->info->ops->pcs_ops->pcs_teardown(chip, port);
391462306a36Sopenharmony_ci}
391562306a36Sopenharmony_ci
391662306a36Sopenharmony_cistatic int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
391762306a36Sopenharmony_ci{
391862306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
391962306a36Sopenharmony_ci
392062306a36Sopenharmony_ci	return chip->eeprom_len;
392162306a36Sopenharmony_ci}
392262306a36Sopenharmony_ci
392362306a36Sopenharmony_cistatic int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
392462306a36Sopenharmony_ci				struct ethtool_eeprom *eeprom, u8 *data)
392562306a36Sopenharmony_ci{
392662306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
392762306a36Sopenharmony_ci	int err;
392862306a36Sopenharmony_ci
392962306a36Sopenharmony_ci	if (!chip->info->ops->get_eeprom)
393062306a36Sopenharmony_ci		return -EOPNOTSUPP;
393162306a36Sopenharmony_ci
393262306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
393362306a36Sopenharmony_ci	err = chip->info->ops->get_eeprom(chip, eeprom, data);
393462306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_ci	if (err)
393762306a36Sopenharmony_ci		return err;
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ci	eeprom->magic = 0xc3ec4951;
394062306a36Sopenharmony_ci
394162306a36Sopenharmony_ci	return 0;
394262306a36Sopenharmony_ci}
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_cistatic int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
394562306a36Sopenharmony_ci				struct ethtool_eeprom *eeprom, u8 *data)
394662306a36Sopenharmony_ci{
394762306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
394862306a36Sopenharmony_ci	int err;
394962306a36Sopenharmony_ci
395062306a36Sopenharmony_ci	if (!chip->info->ops->set_eeprom)
395162306a36Sopenharmony_ci		return -EOPNOTSUPP;
395262306a36Sopenharmony_ci
395362306a36Sopenharmony_ci	if (eeprom->magic != 0xc3ec4951)
395462306a36Sopenharmony_ci		return -EINVAL;
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
395762306a36Sopenharmony_ci	err = chip->info->ops->set_eeprom(chip, eeprom, data);
395862306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
395962306a36Sopenharmony_ci
396062306a36Sopenharmony_ci	return err;
396162306a36Sopenharmony_ci}
396262306a36Sopenharmony_ci
396362306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6085_ops = {
396462306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6097 */
396562306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
396662306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
396762306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
396862306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
396962306a36Sopenharmony_ci	.phy_read = mv88e6185_phy_ppu_read,
397062306a36Sopenharmony_ci	.phy_write = mv88e6185_phy_ppu_write,
397162306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
397262306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
397362306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
397462306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
397562306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
397662306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
397762306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
397862306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
397962306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
398062306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
398162306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
398262306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
398362306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
398462306a36Sopenharmony_ci	.port_get_cmode = mv88e6185_port_get_cmode,
398562306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
398662306a36Sopenharmony_ci	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
398762306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
398862306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
398962306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
399062306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
399162306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
399262306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
399362306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
399462306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
399562306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
399662306a36Sopenharmony_ci	.ppu_enable = mv88e6185_g1_ppu_enable,
399762306a36Sopenharmony_ci	.ppu_disable = mv88e6185_g1_ppu_disable,
399862306a36Sopenharmony_ci	.reset = mv88e6185_g1_reset,
399962306a36Sopenharmony_ci	.rmu_disable = mv88e6085_g1_rmu_disable,
400062306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
400162306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
400262306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
400362306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
400462306a36Sopenharmony_ci	.phylink_get_caps = mv88e6185_phylink_get_caps,
400562306a36Sopenharmony_ci	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
400662306a36Sopenharmony_ci};
400762306a36Sopenharmony_ci
400862306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6095_ops = {
400962306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6095 */
401062306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
401162306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
401262306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
401362306a36Sopenharmony_ci	.phy_read = mv88e6185_phy_ppu_read,
401462306a36Sopenharmony_ci	.phy_write = mv88e6185_phy_ppu_write,
401562306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
401662306a36Sopenharmony_ci	.port_sync_link = mv88e6185_port_sync_link,
401762306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
401862306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
401962306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6185_port_set_forward_unknown,
402062306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6185_port_set_default_forward,
402162306a36Sopenharmony_ci	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
402262306a36Sopenharmony_ci	.port_get_cmode = mv88e6185_port_get_cmode,
402362306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
402462306a36Sopenharmony_ci	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
402562306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
402662306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
402762306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
402862306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
402962306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
403062306a36Sopenharmony_ci	.ppu_enable = mv88e6185_g1_ppu_enable,
403162306a36Sopenharmony_ci	.ppu_disable = mv88e6185_g1_ppu_disable,
403262306a36Sopenharmony_ci	.reset = mv88e6185_g1_reset,
403362306a36Sopenharmony_ci	.vtu_getnext = mv88e6185_g1_vtu_getnext,
403462306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
403562306a36Sopenharmony_ci	.phylink_get_caps = mv88e6095_phylink_get_caps,
403662306a36Sopenharmony_ci	.pcs_ops = &mv88e6185_pcs_ops,
403762306a36Sopenharmony_ci	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
403862306a36Sopenharmony_ci};
403962306a36Sopenharmony_ci
404062306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6097_ops = {
404162306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6097 */
404262306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
404362306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
404462306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
404562306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
404662306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
404762306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
404862306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
404962306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
405062306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
405162306a36Sopenharmony_ci	.port_sync_link = mv88e6185_port_sync_link,
405262306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
405362306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
405462306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
405562306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
405662306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
405762306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
405862306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
405962306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
406062306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
406162306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
406262306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
406362306a36Sopenharmony_ci	.port_get_cmode = mv88e6185_port_get_cmode,
406462306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
406562306a36Sopenharmony_ci	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
406662306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
406762306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
406862306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
406962306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
407062306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
407162306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
407262306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
407362306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
407462306a36Sopenharmony_ci	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
407562306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
407662306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
407762306a36Sopenharmony_ci	.rmu_disable = mv88e6085_g1_rmu_disable,
407862306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
407962306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
408062306a36Sopenharmony_ci	.phylink_get_caps = mv88e6095_phylink_get_caps,
408162306a36Sopenharmony_ci	.pcs_ops = &mv88e6185_pcs_ops,
408262306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
408362306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
408462306a36Sopenharmony_ci	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
408562306a36Sopenharmony_ci};
408662306a36Sopenharmony_ci
408762306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6123_ops = {
408862306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6165 */
408962306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
409062306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
409162306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
409262306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
409362306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
409462306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
409562306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
409662306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
409762306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
409862306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
409962306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
410062306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
410162306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
410262306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
410362306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
410462306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
410562306a36Sopenharmony_ci	.port_get_cmode = mv88e6185_port_get_cmode,
410662306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
410762306a36Sopenharmony_ci	.stats_snapshot = mv88e6320_g1_stats_snapshot,
410862306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
410962306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
411062306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
411162306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
411262306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
411362306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
411462306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
411562306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
411662306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
411762306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
411862306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
411962306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
412062306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
412162306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
412262306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
412362306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
412462306a36Sopenharmony_ci	.phylink_get_caps = mv88e6185_phylink_get_caps,
412562306a36Sopenharmony_ci	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
412662306a36Sopenharmony_ci};
412762306a36Sopenharmony_ci
412862306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6131_ops = {
412962306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6185 */
413062306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
413162306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
413262306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
413362306a36Sopenharmony_ci	.phy_read = mv88e6185_phy_ppu_read,
413462306a36Sopenharmony_ci	.phy_write = mv88e6185_phy_ppu_write,
413562306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
413662306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
413762306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
413862306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
413962306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
414062306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6185_port_set_forward_unknown,
414162306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6185_port_set_default_forward,
414262306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
414362306a36Sopenharmony_ci	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
414462306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
414562306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
414662306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
414762306a36Sopenharmony_ci	.port_set_pause = mv88e6185_port_set_pause,
414862306a36Sopenharmony_ci	.port_get_cmode = mv88e6185_port_get_cmode,
414962306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
415062306a36Sopenharmony_ci	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
415162306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
415262306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
415362306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
415462306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
415562306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
415662306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
415762306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
415862306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
415962306a36Sopenharmony_ci	.ppu_enable = mv88e6185_g1_ppu_enable,
416062306a36Sopenharmony_ci	.set_cascade_port = mv88e6185_g1_set_cascade_port,
416162306a36Sopenharmony_ci	.ppu_disable = mv88e6185_g1_ppu_disable,
416262306a36Sopenharmony_ci	.reset = mv88e6185_g1_reset,
416362306a36Sopenharmony_ci	.vtu_getnext = mv88e6185_g1_vtu_getnext,
416462306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
416562306a36Sopenharmony_ci	.phylink_get_caps = mv88e6185_phylink_get_caps,
416662306a36Sopenharmony_ci};
416762306a36Sopenharmony_ci
416862306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6141_ops = {
416962306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6341 */
417062306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
417162306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
417262306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
417362306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
417462306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
417562306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
417662306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
417762306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
417862306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
417962306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
418062306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
418162306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
418262306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
418362306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
418462306a36Sopenharmony_ci	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
418562306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
418662306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
418762306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
418862306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
418962306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
419062306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
419162306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
419262306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
419362306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
419462306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
419562306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
419662306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
419762306a36Sopenharmony_ci	.port_set_cmode = mv88e6341_port_set_cmode,
419862306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
419962306a36Sopenharmony_ci	.stats_snapshot = mv88e6390_g1_stats_snapshot,
420062306a36Sopenharmony_ci	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
420162306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
420262306a36Sopenharmony_ci	.stats_get_strings = mv88e6320_stats_get_strings,
420362306a36Sopenharmony_ci	.stats_get_stats = mv88e6390_stats_get_stats,
420462306a36Sopenharmony_ci	.set_cpu_port = mv88e6390_g1_set_cpu_port,
420562306a36Sopenharmony_ci	.set_egress_port = mv88e6390_g1_set_egress_port,
420662306a36Sopenharmony_ci	.watchdog_ops = &mv88e6390_watchdog_ops,
420762306a36Sopenharmony_ci	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
420862306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
420962306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
421062306a36Sopenharmony_ci	.rmu_disable = mv88e6390_g1_rmu_disable,
421162306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
421262306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
421362306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
421462306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
421562306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
421662306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
421762306a36Sopenharmony_ci	.serdes_get_lane = mv88e6341_serdes_get_lane,
421862306a36Sopenharmony_ci	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
421962306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
422062306a36Sopenharmony_ci	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
422162306a36Sopenharmony_ci	.serdes_get_strings = mv88e6390_serdes_get_strings,
422262306a36Sopenharmony_ci	.serdes_get_stats = mv88e6390_serdes_get_stats,
422362306a36Sopenharmony_ci	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
422462306a36Sopenharmony_ci	.serdes_get_regs = mv88e6390_serdes_get_regs,
422562306a36Sopenharmony_ci	.phylink_get_caps = mv88e6341_phylink_get_caps,
422662306a36Sopenharmony_ci	.pcs_ops = &mv88e6390_pcs_ops,
422762306a36Sopenharmony_ci};
422862306a36Sopenharmony_ci
422962306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6161_ops = {
423062306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6165 */
423162306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
423262306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
423362306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
423462306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
423562306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
423662306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
423762306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
423862306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
423962306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
424062306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
424162306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
424262306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
424362306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
424462306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
424562306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
424662306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
424762306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
424862306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
424962306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
425062306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
425162306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
425262306a36Sopenharmony_ci	.port_get_cmode = mv88e6185_port_get_cmode,
425362306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
425462306a36Sopenharmony_ci	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
425562306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
425662306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
425762306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
425862306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
425962306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
426062306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
426162306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
426262306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
426362306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
426462306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
426562306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
426662306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
426762306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
426862306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
426962306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
427062306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
427162306a36Sopenharmony_ci	.avb_ops = &mv88e6165_avb_ops,
427262306a36Sopenharmony_ci	.ptp_ops = &mv88e6165_ptp_ops,
427362306a36Sopenharmony_ci	.phylink_get_caps = mv88e6185_phylink_get_caps,
427462306a36Sopenharmony_ci	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
427562306a36Sopenharmony_ci};
427662306a36Sopenharmony_ci
427762306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6165_ops = {
427862306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6165 */
427962306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
428062306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
428162306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
428262306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
428362306a36Sopenharmony_ci	.phy_read = mv88e6165_phy_read,
428462306a36Sopenharmony_ci	.phy_write = mv88e6165_phy_write,
428562306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
428662306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
428762306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
428862306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
428962306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
429062306a36Sopenharmony_ci	.port_get_cmode = mv88e6185_port_get_cmode,
429162306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
429262306a36Sopenharmony_ci	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
429362306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
429462306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
429562306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
429662306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
429762306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
429862306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
429962306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
430062306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
430162306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
430262306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
430362306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
430462306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
430562306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
430662306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
430762306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
430862306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
430962306a36Sopenharmony_ci	.avb_ops = &mv88e6165_avb_ops,
431062306a36Sopenharmony_ci	.ptp_ops = &mv88e6165_ptp_ops,
431162306a36Sopenharmony_ci	.phylink_get_caps = mv88e6185_phylink_get_caps,
431262306a36Sopenharmony_ci};
431362306a36Sopenharmony_ci
431462306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6171_ops = {
431562306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6351 */
431662306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
431762306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
431862306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
431962306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
432062306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
432162306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
432262306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
432362306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
432462306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
432562306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
432662306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
432762306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
432862306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
432962306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
433062306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
433162306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
433262306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
433362306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
433462306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
433562306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
433662306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
433762306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
433862306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
433962306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
434062306a36Sopenharmony_ci	.stats_snapshot = mv88e6320_g1_stats_snapshot,
434162306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
434262306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
434362306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
434462306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
434562306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
434662306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
434762306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
434862306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
434962306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
435062306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
435162306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
435262306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
435362306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
435462306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
435562306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
435662306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
435762306a36Sopenharmony_ci	.phylink_get_caps = mv88e6351_phylink_get_caps,
435862306a36Sopenharmony_ci};
435962306a36Sopenharmony_ci
436062306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6172_ops = {
436162306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6352 */
436262306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
436362306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
436462306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
436562306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
436662306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
436762306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
436862306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
436962306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
437062306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
437162306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
437262306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
437362306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
437462306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
437562306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
437662306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
437762306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
437862306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
437962306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
438062306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
438162306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
438262306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
438362306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
438462306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
438562306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
438662306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
438762306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
438862306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
438962306a36Sopenharmony_ci	.stats_snapshot = mv88e6320_g1_stats_snapshot,
439062306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
439162306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
439262306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
439362306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
439462306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
439562306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
439662306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
439762306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
439862306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
439962306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
440062306a36Sopenharmony_ci	.rmu_disable = mv88e6352_g1_rmu_disable,
440162306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
440262306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
440362306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
440462306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
440562306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
440662306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
440762306a36Sopenharmony_ci	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
440862306a36Sopenharmony_ci	.serdes_get_regs = mv88e6352_serdes_get_regs,
440962306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
441062306a36Sopenharmony_ci	.phylink_get_caps = mv88e6352_phylink_get_caps,
441162306a36Sopenharmony_ci	.pcs_ops = &mv88e6352_pcs_ops,
441262306a36Sopenharmony_ci};
441362306a36Sopenharmony_ci
441462306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6175_ops = {
441562306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6351 */
441662306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
441762306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
441862306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
441962306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
442062306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
442162306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
442262306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
442362306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
442462306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
442562306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
442662306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
442762306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
442862306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
442962306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
443062306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
443162306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
443262306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
443362306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
443462306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
443562306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
443662306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
443762306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
443862306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
443962306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
444062306a36Sopenharmony_ci	.stats_snapshot = mv88e6320_g1_stats_snapshot,
444162306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
444262306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
444362306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
444462306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
444562306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
444662306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
444762306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
444862306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
444962306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
445062306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
445162306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
445262306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
445362306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
445462306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
445562306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
445662306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
445762306a36Sopenharmony_ci	.phylink_get_caps = mv88e6351_phylink_get_caps,
445862306a36Sopenharmony_ci};
445962306a36Sopenharmony_ci
446062306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6176_ops = {
446162306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6352 */
446262306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
446362306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
446462306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
446562306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
446662306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
446762306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
446862306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
446962306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
447062306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
447162306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
447262306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
447362306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
447462306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
447562306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
447662306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
447762306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
447862306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
447962306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
448062306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
448162306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
448262306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
448362306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
448462306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
448562306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
448662306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
448762306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
448862306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
448962306a36Sopenharmony_ci	.stats_snapshot = mv88e6320_g1_stats_snapshot,
449062306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
449162306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
449262306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
449362306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
449462306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
449562306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
449662306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
449762306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
449862306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
449962306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
450062306a36Sopenharmony_ci	.rmu_disable = mv88e6352_g1_rmu_disable,
450162306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
450262306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
450362306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
450462306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
450562306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
450662306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
450762306a36Sopenharmony_ci	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
450862306a36Sopenharmony_ci	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
450962306a36Sopenharmony_ci	.serdes_get_regs = mv88e6352_serdes_get_regs,
451062306a36Sopenharmony_ci	.serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude,
451162306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
451262306a36Sopenharmony_ci	.phylink_get_caps = mv88e6352_phylink_get_caps,
451362306a36Sopenharmony_ci	.pcs_ops = &mv88e6352_pcs_ops,
451462306a36Sopenharmony_ci};
451562306a36Sopenharmony_ci
451662306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6185_ops = {
451762306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6185 */
451862306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
451962306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
452062306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
452162306a36Sopenharmony_ci	.phy_read = mv88e6185_phy_ppu_read,
452262306a36Sopenharmony_ci	.phy_write = mv88e6185_phy_ppu_write,
452362306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
452462306a36Sopenharmony_ci	.port_sync_link = mv88e6185_port_sync_link,
452562306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
452662306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
452762306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6185_port_set_forward_unknown,
452862306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6185_port_set_default_forward,
452962306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
453062306a36Sopenharmony_ci	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
453162306a36Sopenharmony_ci	.port_set_pause = mv88e6185_port_set_pause,
453262306a36Sopenharmony_ci	.port_get_cmode = mv88e6185_port_get_cmode,
453362306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
453462306a36Sopenharmony_ci	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
453562306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
453662306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
453762306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
453862306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
453962306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
454062306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
454162306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
454262306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
454362306a36Sopenharmony_ci	.set_cascade_port = mv88e6185_g1_set_cascade_port,
454462306a36Sopenharmony_ci	.ppu_enable = mv88e6185_g1_ppu_enable,
454562306a36Sopenharmony_ci	.ppu_disable = mv88e6185_g1_ppu_disable,
454662306a36Sopenharmony_ci	.reset = mv88e6185_g1_reset,
454762306a36Sopenharmony_ci	.vtu_getnext = mv88e6185_g1_vtu_getnext,
454862306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
454962306a36Sopenharmony_ci	.phylink_get_caps = mv88e6185_phylink_get_caps,
455062306a36Sopenharmony_ci	.pcs_ops = &mv88e6185_pcs_ops,
455162306a36Sopenharmony_ci	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
455262306a36Sopenharmony_ci};
455362306a36Sopenharmony_ci
455462306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6190_ops = {
455562306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6390 */
455662306a36Sopenharmony_ci	.setup_errata = mv88e6390_setup_errata,
455762306a36Sopenharmony_ci	.irl_init_all = mv88e6390_g2_irl_init_all,
455862306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
455962306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
456062306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
456162306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
456262306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
456362306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
456462306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
456562306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
456662306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
456762306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
456862306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
456962306a36Sopenharmony_ci	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
457062306a36Sopenharmony_ci	.port_tag_remap = mv88e6390_port_tag_remap,
457162306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
457262306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
457362306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
457462306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
457562306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
457662306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
457762306a36Sopenharmony_ci	.port_pause_limit = mv88e6390_port_pause_limit,
457862306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
457962306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
458062306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
458162306a36Sopenharmony_ci	.port_set_cmode = mv88e6390_port_set_cmode,
458262306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
458362306a36Sopenharmony_ci	.stats_snapshot = mv88e6390_g1_stats_snapshot,
458462306a36Sopenharmony_ci	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
458562306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
458662306a36Sopenharmony_ci	.stats_get_strings = mv88e6320_stats_get_strings,
458762306a36Sopenharmony_ci	.stats_get_stats = mv88e6390_stats_get_stats,
458862306a36Sopenharmony_ci	.set_cpu_port = mv88e6390_g1_set_cpu_port,
458962306a36Sopenharmony_ci	.set_egress_port = mv88e6390_g1_set_egress_port,
459062306a36Sopenharmony_ci	.watchdog_ops = &mv88e6390_watchdog_ops,
459162306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
459262306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
459362306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
459462306a36Sopenharmony_ci	.rmu_disable = mv88e6390_g1_rmu_disable,
459562306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
459662306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
459762306a36Sopenharmony_ci	.vtu_getnext = mv88e6390_g1_vtu_getnext,
459862306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
459962306a36Sopenharmony_ci	.stu_getnext = mv88e6390_g1_stu_getnext,
460062306a36Sopenharmony_ci	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
460162306a36Sopenharmony_ci	.serdes_get_lane = mv88e6390_serdes_get_lane,
460262306a36Sopenharmony_ci	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
460362306a36Sopenharmony_ci	.serdes_get_strings = mv88e6390_serdes_get_strings,
460462306a36Sopenharmony_ci	.serdes_get_stats = mv88e6390_serdes_get_stats,
460562306a36Sopenharmony_ci	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
460662306a36Sopenharmony_ci	.serdes_get_regs = mv88e6390_serdes_get_regs,
460762306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
460862306a36Sopenharmony_ci	.phylink_get_caps = mv88e6390_phylink_get_caps,
460962306a36Sopenharmony_ci	.pcs_ops = &mv88e6390_pcs_ops,
461062306a36Sopenharmony_ci};
461162306a36Sopenharmony_ci
461262306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6190x_ops = {
461362306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6390 */
461462306a36Sopenharmony_ci	.setup_errata = mv88e6390_setup_errata,
461562306a36Sopenharmony_ci	.irl_init_all = mv88e6390_g2_irl_init_all,
461662306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
461762306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
461862306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
461962306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
462062306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
462162306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
462262306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
462362306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
462462306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
462562306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
462662306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
462762306a36Sopenharmony_ci	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
462862306a36Sopenharmony_ci	.port_tag_remap = mv88e6390_port_tag_remap,
462962306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
463062306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
463162306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
463262306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
463362306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
463462306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
463562306a36Sopenharmony_ci	.port_pause_limit = mv88e6390_port_pause_limit,
463662306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
463762306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
463862306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
463962306a36Sopenharmony_ci	.port_set_cmode = mv88e6390x_port_set_cmode,
464062306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
464162306a36Sopenharmony_ci	.stats_snapshot = mv88e6390_g1_stats_snapshot,
464262306a36Sopenharmony_ci	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
464362306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
464462306a36Sopenharmony_ci	.stats_get_strings = mv88e6320_stats_get_strings,
464562306a36Sopenharmony_ci	.stats_get_stats = mv88e6390_stats_get_stats,
464662306a36Sopenharmony_ci	.set_cpu_port = mv88e6390_g1_set_cpu_port,
464762306a36Sopenharmony_ci	.set_egress_port = mv88e6390_g1_set_egress_port,
464862306a36Sopenharmony_ci	.watchdog_ops = &mv88e6390_watchdog_ops,
464962306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
465062306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
465162306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
465262306a36Sopenharmony_ci	.rmu_disable = mv88e6390_g1_rmu_disable,
465362306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
465462306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
465562306a36Sopenharmony_ci	.vtu_getnext = mv88e6390_g1_vtu_getnext,
465662306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
465762306a36Sopenharmony_ci	.stu_getnext = mv88e6390_g1_stu_getnext,
465862306a36Sopenharmony_ci	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
465962306a36Sopenharmony_ci	.serdes_get_lane = mv88e6390x_serdes_get_lane,
466062306a36Sopenharmony_ci	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
466162306a36Sopenharmony_ci	.serdes_get_strings = mv88e6390_serdes_get_strings,
466262306a36Sopenharmony_ci	.serdes_get_stats = mv88e6390_serdes_get_stats,
466362306a36Sopenharmony_ci	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
466462306a36Sopenharmony_ci	.serdes_get_regs = mv88e6390_serdes_get_regs,
466562306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
466662306a36Sopenharmony_ci	.phylink_get_caps = mv88e6390x_phylink_get_caps,
466762306a36Sopenharmony_ci	.pcs_ops = &mv88e6390_pcs_ops,
466862306a36Sopenharmony_ci};
466962306a36Sopenharmony_ci
467062306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6191_ops = {
467162306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6390 */
467262306a36Sopenharmony_ci	.setup_errata = mv88e6390_setup_errata,
467362306a36Sopenharmony_ci	.irl_init_all = mv88e6390_g2_irl_init_all,
467462306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
467562306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
467662306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
467762306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
467862306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
467962306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
468062306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
468162306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
468262306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
468362306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
468462306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
468562306a36Sopenharmony_ci	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
468662306a36Sopenharmony_ci	.port_tag_remap = mv88e6390_port_tag_remap,
468762306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
468862306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
468962306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
469062306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
469162306a36Sopenharmony_ci	.port_pause_limit = mv88e6390_port_pause_limit,
469262306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
469362306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
469462306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
469562306a36Sopenharmony_ci	.port_set_cmode = mv88e6390_port_set_cmode,
469662306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
469762306a36Sopenharmony_ci	.stats_snapshot = mv88e6390_g1_stats_snapshot,
469862306a36Sopenharmony_ci	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
469962306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
470062306a36Sopenharmony_ci	.stats_get_strings = mv88e6320_stats_get_strings,
470162306a36Sopenharmony_ci	.stats_get_stats = mv88e6390_stats_get_stats,
470262306a36Sopenharmony_ci	.set_cpu_port = mv88e6390_g1_set_cpu_port,
470362306a36Sopenharmony_ci	.set_egress_port = mv88e6390_g1_set_egress_port,
470462306a36Sopenharmony_ci	.watchdog_ops = &mv88e6390_watchdog_ops,
470562306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
470662306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
470762306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
470862306a36Sopenharmony_ci	.rmu_disable = mv88e6390_g1_rmu_disable,
470962306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
471062306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
471162306a36Sopenharmony_ci	.vtu_getnext = mv88e6390_g1_vtu_getnext,
471262306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
471362306a36Sopenharmony_ci	.stu_getnext = mv88e6390_g1_stu_getnext,
471462306a36Sopenharmony_ci	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
471562306a36Sopenharmony_ci	.serdes_get_lane = mv88e6390_serdes_get_lane,
471662306a36Sopenharmony_ci	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
471762306a36Sopenharmony_ci	.serdes_get_strings = mv88e6390_serdes_get_strings,
471862306a36Sopenharmony_ci	.serdes_get_stats = mv88e6390_serdes_get_stats,
471962306a36Sopenharmony_ci	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
472062306a36Sopenharmony_ci	.serdes_get_regs = mv88e6390_serdes_get_regs,
472162306a36Sopenharmony_ci	.avb_ops = &mv88e6390_avb_ops,
472262306a36Sopenharmony_ci	.ptp_ops = &mv88e6352_ptp_ops,
472362306a36Sopenharmony_ci	.phylink_get_caps = mv88e6390_phylink_get_caps,
472462306a36Sopenharmony_ci	.pcs_ops = &mv88e6390_pcs_ops,
472562306a36Sopenharmony_ci};
472662306a36Sopenharmony_ci
472762306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6240_ops = {
472862306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6352 */
472962306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
473062306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
473162306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
473262306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
473362306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
473462306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
473562306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
473662306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
473762306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
473862306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
473962306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
474062306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
474162306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
474262306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
474362306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
474462306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
474562306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
474662306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
474762306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
474862306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
474962306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
475062306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
475162306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
475262306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
475362306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
475462306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
475562306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
475662306a36Sopenharmony_ci	.stats_snapshot = mv88e6320_g1_stats_snapshot,
475762306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
475862306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
475962306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
476062306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
476162306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
476262306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
476362306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
476462306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
476562306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
476662306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
476762306a36Sopenharmony_ci	.rmu_disable = mv88e6352_g1_rmu_disable,
476862306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
476962306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
477062306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
477162306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
477262306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
477362306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
477462306a36Sopenharmony_ci	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
477562306a36Sopenharmony_ci	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
477662306a36Sopenharmony_ci	.serdes_get_regs = mv88e6352_serdes_get_regs,
477762306a36Sopenharmony_ci	.serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude,
477862306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
477962306a36Sopenharmony_ci	.avb_ops = &mv88e6352_avb_ops,
478062306a36Sopenharmony_ci	.ptp_ops = &mv88e6352_ptp_ops,
478162306a36Sopenharmony_ci	.phylink_get_caps = mv88e6352_phylink_get_caps,
478262306a36Sopenharmony_ci	.pcs_ops = &mv88e6352_pcs_ops,
478362306a36Sopenharmony_ci};
478462306a36Sopenharmony_ci
478562306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6250_ops = {
478662306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6250 */
478762306a36Sopenharmony_ci	.ieee_pri_map = mv88e6250_g1_ieee_pri_map,
478862306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
478962306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
479062306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
479162306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
479262306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
479362306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
479462306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
479562306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
479662306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
479762306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
479862306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
479962306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
480062306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6250_port_set_speed_duplex,
480162306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
480262306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
480362306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
480462306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
480562306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
480662306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
480762306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
480862306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
480962306a36Sopenharmony_ci	.stats_snapshot = mv88e6320_g1_stats_snapshot,
481062306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
481162306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6250_stats_get_sset_count,
481262306a36Sopenharmony_ci	.stats_get_strings = mv88e6250_stats_get_strings,
481362306a36Sopenharmony_ci	.stats_get_stats = mv88e6250_stats_get_stats,
481462306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
481562306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
481662306a36Sopenharmony_ci	.watchdog_ops = &mv88e6250_watchdog_ops,
481762306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
481862306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
481962306a36Sopenharmony_ci	.reset = mv88e6250_g1_reset,
482062306a36Sopenharmony_ci	.vtu_getnext = mv88e6185_g1_vtu_getnext,
482162306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
482262306a36Sopenharmony_ci	.avb_ops = &mv88e6352_avb_ops,
482362306a36Sopenharmony_ci	.ptp_ops = &mv88e6250_ptp_ops,
482462306a36Sopenharmony_ci	.phylink_get_caps = mv88e6250_phylink_get_caps,
482562306a36Sopenharmony_ci	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
482662306a36Sopenharmony_ci};
482762306a36Sopenharmony_ci
482862306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6290_ops = {
482962306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6390 */
483062306a36Sopenharmony_ci	.setup_errata = mv88e6390_setup_errata,
483162306a36Sopenharmony_ci	.irl_init_all = mv88e6390_g2_irl_init_all,
483262306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
483362306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
483462306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
483562306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
483662306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
483762306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
483862306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
483962306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
484062306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
484162306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
484262306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
484362306a36Sopenharmony_ci	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
484462306a36Sopenharmony_ci	.port_tag_remap = mv88e6390_port_tag_remap,
484562306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
484662306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
484762306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
484862306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
484962306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
485062306a36Sopenharmony_ci	.port_pause_limit = mv88e6390_port_pause_limit,
485162306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
485262306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
485362306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
485462306a36Sopenharmony_ci	.port_set_cmode = mv88e6390_port_set_cmode,
485562306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
485662306a36Sopenharmony_ci	.stats_snapshot = mv88e6390_g1_stats_snapshot,
485762306a36Sopenharmony_ci	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
485862306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
485962306a36Sopenharmony_ci	.stats_get_strings = mv88e6320_stats_get_strings,
486062306a36Sopenharmony_ci	.stats_get_stats = mv88e6390_stats_get_stats,
486162306a36Sopenharmony_ci	.set_cpu_port = mv88e6390_g1_set_cpu_port,
486262306a36Sopenharmony_ci	.set_egress_port = mv88e6390_g1_set_egress_port,
486362306a36Sopenharmony_ci	.watchdog_ops = &mv88e6390_watchdog_ops,
486462306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
486562306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
486662306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
486762306a36Sopenharmony_ci	.rmu_disable = mv88e6390_g1_rmu_disable,
486862306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
486962306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
487062306a36Sopenharmony_ci	.vtu_getnext = mv88e6390_g1_vtu_getnext,
487162306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
487262306a36Sopenharmony_ci	.stu_getnext = mv88e6390_g1_stu_getnext,
487362306a36Sopenharmony_ci	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
487462306a36Sopenharmony_ci	.serdes_get_lane = mv88e6390_serdes_get_lane,
487562306a36Sopenharmony_ci	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
487662306a36Sopenharmony_ci	.serdes_get_strings = mv88e6390_serdes_get_strings,
487762306a36Sopenharmony_ci	.serdes_get_stats = mv88e6390_serdes_get_stats,
487862306a36Sopenharmony_ci	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
487962306a36Sopenharmony_ci	.serdes_get_regs = mv88e6390_serdes_get_regs,
488062306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
488162306a36Sopenharmony_ci	.avb_ops = &mv88e6390_avb_ops,
488262306a36Sopenharmony_ci	.ptp_ops = &mv88e6390_ptp_ops,
488362306a36Sopenharmony_ci	.phylink_get_caps = mv88e6390_phylink_get_caps,
488462306a36Sopenharmony_ci	.pcs_ops = &mv88e6390_pcs_ops,
488562306a36Sopenharmony_ci};
488662306a36Sopenharmony_ci
488762306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6320_ops = {
488862306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6320 */
488962306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
489062306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
489162306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
489262306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
489362306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
489462306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
489562306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
489662306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
489762306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
489862306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
489962306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
490062306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
490162306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6320_port_set_rgmii_delay,
490262306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
490362306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
490462306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
490562306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
490662306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
490762306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
490862306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
490962306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
491062306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
491162306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
491262306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
491362306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
491462306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
491562306a36Sopenharmony_ci	.stats_snapshot = mv88e6320_g1_stats_snapshot,
491662306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
491762306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
491862306a36Sopenharmony_ci	.stats_get_strings = mv88e6320_stats_get_strings,
491962306a36Sopenharmony_ci	.stats_get_stats = mv88e6320_stats_get_stats,
492062306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
492162306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
492262306a36Sopenharmony_ci	.watchdog_ops = &mv88e6390_watchdog_ops,
492362306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
492462306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
492562306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
492662306a36Sopenharmony_ci	.vtu_getnext = mv88e6185_g1_vtu_getnext,
492762306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
492862306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
492962306a36Sopenharmony_ci	.avb_ops = &mv88e6352_avb_ops,
493062306a36Sopenharmony_ci	.ptp_ops = &mv88e6352_ptp_ops,
493162306a36Sopenharmony_ci	.phylink_get_caps = mv88e6185_phylink_get_caps,
493262306a36Sopenharmony_ci};
493362306a36Sopenharmony_ci
493462306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6321_ops = {
493562306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6320 */
493662306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
493762306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
493862306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
493962306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
494062306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
494162306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
494262306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
494362306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
494462306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
494562306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
494662306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
494762306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
494862306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6320_port_set_rgmii_delay,
494962306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
495062306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
495162306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
495262306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
495362306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
495462306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
495562306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
495662306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
495762306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
495862306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
495962306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
496062306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
496162306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
496262306a36Sopenharmony_ci	.stats_snapshot = mv88e6320_g1_stats_snapshot,
496362306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
496462306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
496562306a36Sopenharmony_ci	.stats_get_strings = mv88e6320_stats_get_strings,
496662306a36Sopenharmony_ci	.stats_get_stats = mv88e6320_stats_get_stats,
496762306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
496862306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
496962306a36Sopenharmony_ci	.watchdog_ops = &mv88e6390_watchdog_ops,
497062306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
497162306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
497262306a36Sopenharmony_ci	.vtu_getnext = mv88e6185_g1_vtu_getnext,
497362306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
497462306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
497562306a36Sopenharmony_ci	.avb_ops = &mv88e6352_avb_ops,
497662306a36Sopenharmony_ci	.ptp_ops = &mv88e6352_ptp_ops,
497762306a36Sopenharmony_ci	.phylink_get_caps = mv88e6185_phylink_get_caps,
497862306a36Sopenharmony_ci};
497962306a36Sopenharmony_ci
498062306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6341_ops = {
498162306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6341 */
498262306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
498362306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
498462306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
498562306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
498662306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
498762306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
498862306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
498962306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
499062306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
499162306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
499262306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
499362306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
499462306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
499562306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
499662306a36Sopenharmony_ci	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
499762306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
499862306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
499962306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
500062306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
500162306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
500262306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
500362306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
500462306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
500562306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
500662306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
500762306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
500862306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
500962306a36Sopenharmony_ci	.port_set_cmode = mv88e6341_port_set_cmode,
501062306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
501162306a36Sopenharmony_ci	.stats_snapshot = mv88e6390_g1_stats_snapshot,
501262306a36Sopenharmony_ci	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
501362306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
501462306a36Sopenharmony_ci	.stats_get_strings = mv88e6320_stats_get_strings,
501562306a36Sopenharmony_ci	.stats_get_stats = mv88e6390_stats_get_stats,
501662306a36Sopenharmony_ci	.set_cpu_port = mv88e6390_g1_set_cpu_port,
501762306a36Sopenharmony_ci	.set_egress_port = mv88e6390_g1_set_egress_port,
501862306a36Sopenharmony_ci	.watchdog_ops = &mv88e6390_watchdog_ops,
501962306a36Sopenharmony_ci	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
502062306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
502162306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
502262306a36Sopenharmony_ci	.rmu_disable = mv88e6390_g1_rmu_disable,
502362306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
502462306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
502562306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
502662306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
502762306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
502862306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
502962306a36Sopenharmony_ci	.serdes_get_lane = mv88e6341_serdes_get_lane,
503062306a36Sopenharmony_ci	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
503162306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
503262306a36Sopenharmony_ci	.avb_ops = &mv88e6390_avb_ops,
503362306a36Sopenharmony_ci	.ptp_ops = &mv88e6352_ptp_ops,
503462306a36Sopenharmony_ci	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
503562306a36Sopenharmony_ci	.serdes_get_strings = mv88e6390_serdes_get_strings,
503662306a36Sopenharmony_ci	.serdes_get_stats = mv88e6390_serdes_get_stats,
503762306a36Sopenharmony_ci	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
503862306a36Sopenharmony_ci	.serdes_get_regs = mv88e6390_serdes_get_regs,
503962306a36Sopenharmony_ci	.phylink_get_caps = mv88e6341_phylink_get_caps,
504062306a36Sopenharmony_ci	.pcs_ops = &mv88e6390_pcs_ops,
504162306a36Sopenharmony_ci};
504262306a36Sopenharmony_ci
504362306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6350_ops = {
504462306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6351 */
504562306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
504662306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
504762306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
504862306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
504962306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
505062306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
505162306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
505262306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
505362306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
505462306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
505562306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
505662306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
505762306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
505862306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
505962306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
506062306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
506162306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
506262306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
506362306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
506462306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
506562306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
506662306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
506762306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
506862306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
506962306a36Sopenharmony_ci	.stats_snapshot = mv88e6320_g1_stats_snapshot,
507062306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
507162306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
507262306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
507362306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
507462306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
507562306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
507662306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
507762306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
507862306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
507962306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
508062306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
508162306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
508262306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
508362306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
508462306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
508562306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
508662306a36Sopenharmony_ci	.phylink_get_caps = mv88e6351_phylink_get_caps,
508762306a36Sopenharmony_ci};
508862306a36Sopenharmony_ci
508962306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6351_ops = {
509062306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6351 */
509162306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
509262306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
509362306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
509462306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
509562306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
509662306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
509762306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
509862306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
509962306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
510062306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
510162306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
510262306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
510362306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
510462306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
510562306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
510662306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
510762306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
510862306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
510962306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
511062306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
511162306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
511262306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
511362306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
511462306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
511562306a36Sopenharmony_ci	.stats_snapshot = mv88e6320_g1_stats_snapshot,
511662306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
511762306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
511862306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
511962306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
512062306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
512162306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
512262306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
512362306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
512462306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
512562306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
512662306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
512762306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
512862306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
512962306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
513062306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
513162306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
513262306a36Sopenharmony_ci	.avb_ops = &mv88e6352_avb_ops,
513362306a36Sopenharmony_ci	.ptp_ops = &mv88e6352_ptp_ops,
513462306a36Sopenharmony_ci	.phylink_get_caps = mv88e6351_phylink_get_caps,
513562306a36Sopenharmony_ci};
513662306a36Sopenharmony_ci
513762306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6352_ops = {
513862306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6352 */
513962306a36Sopenharmony_ci	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
514062306a36Sopenharmony_ci	.ip_pri_map = mv88e6085_g1_ip_pri_map,
514162306a36Sopenharmony_ci	.irl_init_all = mv88e6352_g2_irl_init_all,
514262306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
514362306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
514462306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
514562306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
514662306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
514762306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
514862306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
514962306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
515062306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
515162306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
515262306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
515362306a36Sopenharmony_ci	.port_tag_remap = mv88e6095_port_tag_remap,
515462306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
515562306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
515662306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
515762306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
515862306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
515962306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
516062306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
516162306a36Sopenharmony_ci	.port_pause_limit = mv88e6097_port_pause_limit,
516262306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
516362306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
516462306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
516562306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
516662306a36Sopenharmony_ci	.stats_snapshot = mv88e6320_g1_stats_snapshot,
516762306a36Sopenharmony_ci	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
516862306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
516962306a36Sopenharmony_ci	.stats_get_strings = mv88e6095_stats_get_strings,
517062306a36Sopenharmony_ci	.stats_get_stats = mv88e6095_stats_get_stats,
517162306a36Sopenharmony_ci	.set_cpu_port = mv88e6095_g1_set_cpu_port,
517262306a36Sopenharmony_ci	.set_egress_port = mv88e6095_g1_set_egress_port,
517362306a36Sopenharmony_ci	.watchdog_ops = &mv88e6097_watchdog_ops,
517462306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
517562306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
517662306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
517762306a36Sopenharmony_ci	.rmu_disable = mv88e6352_g1_rmu_disable,
517862306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
517962306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
518062306a36Sopenharmony_ci	.vtu_getnext = mv88e6352_g1_vtu_getnext,
518162306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
518262306a36Sopenharmony_ci	.stu_getnext = mv88e6352_g1_stu_getnext,
518362306a36Sopenharmony_ci	.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
518462306a36Sopenharmony_ci	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
518562306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
518662306a36Sopenharmony_ci	.avb_ops = &mv88e6352_avb_ops,
518762306a36Sopenharmony_ci	.ptp_ops = &mv88e6352_ptp_ops,
518862306a36Sopenharmony_ci	.serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
518962306a36Sopenharmony_ci	.serdes_get_strings = mv88e6352_serdes_get_strings,
519062306a36Sopenharmony_ci	.serdes_get_stats = mv88e6352_serdes_get_stats,
519162306a36Sopenharmony_ci	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
519262306a36Sopenharmony_ci	.serdes_get_regs = mv88e6352_serdes_get_regs,
519362306a36Sopenharmony_ci	.serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude,
519462306a36Sopenharmony_ci	.phylink_get_caps = mv88e6352_phylink_get_caps,
519562306a36Sopenharmony_ci	.pcs_ops = &mv88e6352_pcs_ops,
519662306a36Sopenharmony_ci};
519762306a36Sopenharmony_ci
519862306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6390_ops = {
519962306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6390 */
520062306a36Sopenharmony_ci	.setup_errata = mv88e6390_setup_errata,
520162306a36Sopenharmony_ci	.irl_init_all = mv88e6390_g2_irl_init_all,
520262306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
520362306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
520462306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
520562306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
520662306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
520762306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
520862306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
520962306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
521062306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
521162306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
521262306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
521362306a36Sopenharmony_ci	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
521462306a36Sopenharmony_ci	.port_tag_remap = mv88e6390_port_tag_remap,
521562306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
521662306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
521762306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
521862306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
521962306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
522062306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
522162306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
522262306a36Sopenharmony_ci	.port_pause_limit = mv88e6390_port_pause_limit,
522362306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
522462306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
522562306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
522662306a36Sopenharmony_ci	.port_set_cmode = mv88e6390_port_set_cmode,
522762306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
522862306a36Sopenharmony_ci	.stats_snapshot = mv88e6390_g1_stats_snapshot,
522962306a36Sopenharmony_ci	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
523062306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
523162306a36Sopenharmony_ci	.stats_get_strings = mv88e6320_stats_get_strings,
523262306a36Sopenharmony_ci	.stats_get_stats = mv88e6390_stats_get_stats,
523362306a36Sopenharmony_ci	.set_cpu_port = mv88e6390_g1_set_cpu_port,
523462306a36Sopenharmony_ci	.set_egress_port = mv88e6390_g1_set_egress_port,
523562306a36Sopenharmony_ci	.watchdog_ops = &mv88e6390_watchdog_ops,
523662306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
523762306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
523862306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
523962306a36Sopenharmony_ci	.rmu_disable = mv88e6390_g1_rmu_disable,
524062306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
524162306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
524262306a36Sopenharmony_ci	.vtu_getnext = mv88e6390_g1_vtu_getnext,
524362306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
524462306a36Sopenharmony_ci	.stu_getnext = mv88e6390_g1_stu_getnext,
524562306a36Sopenharmony_ci	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
524662306a36Sopenharmony_ci	.serdes_get_lane = mv88e6390_serdes_get_lane,
524762306a36Sopenharmony_ci	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
524862306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
524962306a36Sopenharmony_ci	.avb_ops = &mv88e6390_avb_ops,
525062306a36Sopenharmony_ci	.ptp_ops = &mv88e6390_ptp_ops,
525162306a36Sopenharmony_ci	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
525262306a36Sopenharmony_ci	.serdes_get_strings = mv88e6390_serdes_get_strings,
525362306a36Sopenharmony_ci	.serdes_get_stats = mv88e6390_serdes_get_stats,
525462306a36Sopenharmony_ci	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
525562306a36Sopenharmony_ci	.serdes_get_regs = mv88e6390_serdes_get_regs,
525662306a36Sopenharmony_ci	.phylink_get_caps = mv88e6390_phylink_get_caps,
525762306a36Sopenharmony_ci	.pcs_ops = &mv88e6390_pcs_ops,
525862306a36Sopenharmony_ci};
525962306a36Sopenharmony_ci
526062306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6390x_ops = {
526162306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6390 */
526262306a36Sopenharmony_ci	.setup_errata = mv88e6390_setup_errata,
526362306a36Sopenharmony_ci	.irl_init_all = mv88e6390_g2_irl_init_all,
526462306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
526562306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
526662306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
526762306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
526862306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
526962306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
527062306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
527162306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
527262306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
527362306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
527462306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
527562306a36Sopenharmony_ci	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
527662306a36Sopenharmony_ci	.port_tag_remap = mv88e6390_port_tag_remap,
527762306a36Sopenharmony_ci	.port_set_policy = mv88e6352_port_set_policy,
527862306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
527962306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
528062306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
528162306a36Sopenharmony_ci	.port_set_ether_type = mv88e6351_port_set_ether_type,
528262306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
528362306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
528462306a36Sopenharmony_ci	.port_pause_limit = mv88e6390_port_pause_limit,
528562306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
528662306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
528762306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
528862306a36Sopenharmony_ci	.port_set_cmode = mv88e6390x_port_set_cmode,
528962306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
529062306a36Sopenharmony_ci	.stats_snapshot = mv88e6390_g1_stats_snapshot,
529162306a36Sopenharmony_ci	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
529262306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
529362306a36Sopenharmony_ci	.stats_get_strings = mv88e6320_stats_get_strings,
529462306a36Sopenharmony_ci	.stats_get_stats = mv88e6390_stats_get_stats,
529562306a36Sopenharmony_ci	.set_cpu_port = mv88e6390_g1_set_cpu_port,
529662306a36Sopenharmony_ci	.set_egress_port = mv88e6390_g1_set_egress_port,
529762306a36Sopenharmony_ci	.watchdog_ops = &mv88e6390_watchdog_ops,
529862306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
529962306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
530062306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
530162306a36Sopenharmony_ci	.rmu_disable = mv88e6390_g1_rmu_disable,
530262306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
530362306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
530462306a36Sopenharmony_ci	.vtu_getnext = mv88e6390_g1_vtu_getnext,
530562306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
530662306a36Sopenharmony_ci	.stu_getnext = mv88e6390_g1_stu_getnext,
530762306a36Sopenharmony_ci	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
530862306a36Sopenharmony_ci	.serdes_get_lane = mv88e6390x_serdes_get_lane,
530962306a36Sopenharmony_ci	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
531062306a36Sopenharmony_ci	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
531162306a36Sopenharmony_ci	.serdes_get_strings = mv88e6390_serdes_get_strings,
531262306a36Sopenharmony_ci	.serdes_get_stats = mv88e6390_serdes_get_stats,
531362306a36Sopenharmony_ci	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
531462306a36Sopenharmony_ci	.serdes_get_regs = mv88e6390_serdes_get_regs,
531562306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
531662306a36Sopenharmony_ci	.avb_ops = &mv88e6390_avb_ops,
531762306a36Sopenharmony_ci	.ptp_ops = &mv88e6390_ptp_ops,
531862306a36Sopenharmony_ci	.phylink_get_caps = mv88e6390x_phylink_get_caps,
531962306a36Sopenharmony_ci	.pcs_ops = &mv88e6390_pcs_ops,
532062306a36Sopenharmony_ci};
532162306a36Sopenharmony_ci
532262306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6393x_ops = {
532362306a36Sopenharmony_ci	/* MV88E6XXX_FAMILY_6393 */
532462306a36Sopenharmony_ci	.irl_init_all = mv88e6390_g2_irl_init_all,
532562306a36Sopenharmony_ci	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
532662306a36Sopenharmony_ci	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
532762306a36Sopenharmony_ci	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
532862306a36Sopenharmony_ci	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
532962306a36Sopenharmony_ci	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
533062306a36Sopenharmony_ci	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
533162306a36Sopenharmony_ci	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
533262306a36Sopenharmony_ci	.port_set_link = mv88e6xxx_port_set_link,
533362306a36Sopenharmony_ci	.port_sync_link = mv88e6xxx_port_sync_link,
533462306a36Sopenharmony_ci	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
533562306a36Sopenharmony_ci	.port_set_speed_duplex = mv88e6393x_port_set_speed_duplex,
533662306a36Sopenharmony_ci	.port_max_speed_mode = mv88e6393x_port_max_speed_mode,
533762306a36Sopenharmony_ci	.port_tag_remap = mv88e6390_port_tag_remap,
533862306a36Sopenharmony_ci	.port_set_policy = mv88e6393x_port_set_policy,
533962306a36Sopenharmony_ci	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
534062306a36Sopenharmony_ci	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
534162306a36Sopenharmony_ci	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
534262306a36Sopenharmony_ci	.port_set_ether_type = mv88e6393x_port_set_ether_type,
534362306a36Sopenharmony_ci	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
534462306a36Sopenharmony_ci	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
534562306a36Sopenharmony_ci	.port_pause_limit = mv88e6390_port_pause_limit,
534662306a36Sopenharmony_ci	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
534762306a36Sopenharmony_ci	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
534862306a36Sopenharmony_ci	.port_get_cmode = mv88e6352_port_get_cmode,
534962306a36Sopenharmony_ci	.port_set_cmode = mv88e6393x_port_set_cmode,
535062306a36Sopenharmony_ci	.port_setup_message_port = mv88e6xxx_setup_message_port,
535162306a36Sopenharmony_ci	.port_set_upstream_port = mv88e6393x_port_set_upstream_port,
535262306a36Sopenharmony_ci	.stats_snapshot = mv88e6390_g1_stats_snapshot,
535362306a36Sopenharmony_ci	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
535462306a36Sopenharmony_ci	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
535562306a36Sopenharmony_ci	.stats_get_strings = mv88e6320_stats_get_strings,
535662306a36Sopenharmony_ci	.stats_get_stats = mv88e6390_stats_get_stats,
535762306a36Sopenharmony_ci	/* .set_cpu_port is missing because this family does not support a global
535862306a36Sopenharmony_ci	 * CPU port, only per port CPU port which is set via
535962306a36Sopenharmony_ci	 * .port_set_upstream_port method.
536062306a36Sopenharmony_ci	 */
536162306a36Sopenharmony_ci	.set_egress_port = mv88e6393x_set_egress_port,
536262306a36Sopenharmony_ci	.watchdog_ops = &mv88e6393x_watchdog_ops,
536362306a36Sopenharmony_ci	.mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu,
536462306a36Sopenharmony_ci	.pot_clear = mv88e6xxx_g2_pot_clear,
536562306a36Sopenharmony_ci	.reset = mv88e6352_g1_reset,
536662306a36Sopenharmony_ci	.rmu_disable = mv88e6390_g1_rmu_disable,
536762306a36Sopenharmony_ci	.atu_get_hash = mv88e6165_g1_atu_get_hash,
536862306a36Sopenharmony_ci	.atu_set_hash = mv88e6165_g1_atu_set_hash,
536962306a36Sopenharmony_ci	.vtu_getnext = mv88e6390_g1_vtu_getnext,
537062306a36Sopenharmony_ci	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
537162306a36Sopenharmony_ci	.stu_getnext = mv88e6390_g1_stu_getnext,
537262306a36Sopenharmony_ci	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
537362306a36Sopenharmony_ci	.serdes_get_lane = mv88e6393x_serdes_get_lane,
537462306a36Sopenharmony_ci	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
537562306a36Sopenharmony_ci	/* TODO: serdes stats */
537662306a36Sopenharmony_ci	.gpio_ops = &mv88e6352_gpio_ops,
537762306a36Sopenharmony_ci	.avb_ops = &mv88e6390_avb_ops,
537862306a36Sopenharmony_ci	.ptp_ops = &mv88e6352_ptp_ops,
537962306a36Sopenharmony_ci	.phylink_get_caps = mv88e6393x_phylink_get_caps,
538062306a36Sopenharmony_ci	.pcs_ops = &mv88e6393x_pcs_ops,
538162306a36Sopenharmony_ci};
538262306a36Sopenharmony_ci
538362306a36Sopenharmony_cistatic const struct mv88e6xxx_info mv88e6xxx_table[] = {
538462306a36Sopenharmony_ci	[MV88E6020] = {
538562306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6020,
538662306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6250,
538762306a36Sopenharmony_ci		.name = "Marvell 88E6020",
538862306a36Sopenharmony_ci		.num_databases = 64,
538962306a36Sopenharmony_ci		.num_ports = 4,
539062306a36Sopenharmony_ci		.num_internal_phys = 2,
539162306a36Sopenharmony_ci		.max_vid = 4095,
539262306a36Sopenharmony_ci		.port_base_addr = 0x8,
539362306a36Sopenharmony_ci		.phy_base_addr = 0x0,
539462306a36Sopenharmony_ci		.global1_addr = 0xf,
539562306a36Sopenharmony_ci		.global2_addr = 0x7,
539662306a36Sopenharmony_ci		.age_time_coeff = 15000,
539762306a36Sopenharmony_ci		.g1_irqs = 9,
539862306a36Sopenharmony_ci		.g2_irqs = 5,
539962306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
540062306a36Sopenharmony_ci		.dual_chip = true,
540162306a36Sopenharmony_ci		.ops = &mv88e6250_ops,
540262306a36Sopenharmony_ci	},
540362306a36Sopenharmony_ci
540462306a36Sopenharmony_ci	[MV88E6071] = {
540562306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6071,
540662306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6250,
540762306a36Sopenharmony_ci		.name = "Marvell 88E6071",
540862306a36Sopenharmony_ci		.num_databases = 64,
540962306a36Sopenharmony_ci		.num_ports = 7,
541062306a36Sopenharmony_ci		.num_internal_phys = 5,
541162306a36Sopenharmony_ci		.max_vid = 4095,
541262306a36Sopenharmony_ci		.port_base_addr = 0x08,
541362306a36Sopenharmony_ci		.phy_base_addr = 0x00,
541462306a36Sopenharmony_ci		.global1_addr = 0x0f,
541562306a36Sopenharmony_ci		.global2_addr = 0x07,
541662306a36Sopenharmony_ci		.age_time_coeff = 15000,
541762306a36Sopenharmony_ci		.g1_irqs = 9,
541862306a36Sopenharmony_ci		.g2_irqs = 5,
541962306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
542062306a36Sopenharmony_ci		.dual_chip = true,
542162306a36Sopenharmony_ci		.ops = &mv88e6250_ops,
542262306a36Sopenharmony_ci	},
542362306a36Sopenharmony_ci
542462306a36Sopenharmony_ci	[MV88E6085] = {
542562306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
542662306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6097,
542762306a36Sopenharmony_ci		.name = "Marvell 88E6085",
542862306a36Sopenharmony_ci		.num_databases = 4096,
542962306a36Sopenharmony_ci		.num_macs = 8192,
543062306a36Sopenharmony_ci		.num_ports = 10,
543162306a36Sopenharmony_ci		.num_internal_phys = 5,
543262306a36Sopenharmony_ci		.max_vid = 4095,
543362306a36Sopenharmony_ci		.max_sid = 63,
543462306a36Sopenharmony_ci		.port_base_addr = 0x10,
543562306a36Sopenharmony_ci		.phy_base_addr = 0x0,
543662306a36Sopenharmony_ci		.global1_addr = 0x1b,
543762306a36Sopenharmony_ci		.global2_addr = 0x1c,
543862306a36Sopenharmony_ci		.age_time_coeff = 15000,
543962306a36Sopenharmony_ci		.g1_irqs = 8,
544062306a36Sopenharmony_ci		.g2_irqs = 10,
544162306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
544262306a36Sopenharmony_ci		.pvt = true,
544362306a36Sopenharmony_ci		.multi_chip = true,
544462306a36Sopenharmony_ci		.ops = &mv88e6085_ops,
544562306a36Sopenharmony_ci	},
544662306a36Sopenharmony_ci
544762306a36Sopenharmony_ci	[MV88E6095] = {
544862306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095,
544962306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6095,
545062306a36Sopenharmony_ci		.name = "Marvell 88E6095/88E6095F",
545162306a36Sopenharmony_ci		.num_databases = 256,
545262306a36Sopenharmony_ci		.num_macs = 8192,
545362306a36Sopenharmony_ci		.num_ports = 11,
545462306a36Sopenharmony_ci		.num_internal_phys = 0,
545562306a36Sopenharmony_ci		.max_vid = 4095,
545662306a36Sopenharmony_ci		.port_base_addr = 0x10,
545762306a36Sopenharmony_ci		.phy_base_addr = 0x0,
545862306a36Sopenharmony_ci		.global1_addr = 0x1b,
545962306a36Sopenharmony_ci		.global2_addr = 0x1c,
546062306a36Sopenharmony_ci		.age_time_coeff = 15000,
546162306a36Sopenharmony_ci		.g1_irqs = 8,
546262306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
546362306a36Sopenharmony_ci		.multi_chip = true,
546462306a36Sopenharmony_ci		.ops = &mv88e6095_ops,
546562306a36Sopenharmony_ci	},
546662306a36Sopenharmony_ci
546762306a36Sopenharmony_ci	[MV88E6097] = {
546862306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097,
546962306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6097,
547062306a36Sopenharmony_ci		.name = "Marvell 88E6097/88E6097F",
547162306a36Sopenharmony_ci		.num_databases = 4096,
547262306a36Sopenharmony_ci		.num_macs = 8192,
547362306a36Sopenharmony_ci		.num_ports = 11,
547462306a36Sopenharmony_ci		.num_internal_phys = 8,
547562306a36Sopenharmony_ci		.max_vid = 4095,
547662306a36Sopenharmony_ci		.max_sid = 63,
547762306a36Sopenharmony_ci		.port_base_addr = 0x10,
547862306a36Sopenharmony_ci		.phy_base_addr = 0x0,
547962306a36Sopenharmony_ci		.global1_addr = 0x1b,
548062306a36Sopenharmony_ci		.global2_addr = 0x1c,
548162306a36Sopenharmony_ci		.age_time_coeff = 15000,
548262306a36Sopenharmony_ci		.g1_irqs = 8,
548362306a36Sopenharmony_ci		.g2_irqs = 10,
548462306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
548562306a36Sopenharmony_ci		.pvt = true,
548662306a36Sopenharmony_ci		.multi_chip = true,
548762306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
548862306a36Sopenharmony_ci		.ops = &mv88e6097_ops,
548962306a36Sopenharmony_ci	},
549062306a36Sopenharmony_ci
549162306a36Sopenharmony_ci	[MV88E6123] = {
549262306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123,
549362306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6165,
549462306a36Sopenharmony_ci		.name = "Marvell 88E6123",
549562306a36Sopenharmony_ci		.num_databases = 4096,
549662306a36Sopenharmony_ci		.num_macs = 1024,
549762306a36Sopenharmony_ci		.num_ports = 3,
549862306a36Sopenharmony_ci		.num_internal_phys = 5,
549962306a36Sopenharmony_ci		.max_vid = 4095,
550062306a36Sopenharmony_ci		.max_sid = 63,
550162306a36Sopenharmony_ci		.port_base_addr = 0x10,
550262306a36Sopenharmony_ci		.phy_base_addr = 0x0,
550362306a36Sopenharmony_ci		.global1_addr = 0x1b,
550462306a36Sopenharmony_ci		.global2_addr = 0x1c,
550562306a36Sopenharmony_ci		.age_time_coeff = 15000,
550662306a36Sopenharmony_ci		.g1_irqs = 9,
550762306a36Sopenharmony_ci		.g2_irqs = 10,
550862306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
550962306a36Sopenharmony_ci		.pvt = true,
551062306a36Sopenharmony_ci		.multi_chip = true,
551162306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
551262306a36Sopenharmony_ci		.ops = &mv88e6123_ops,
551362306a36Sopenharmony_ci	},
551462306a36Sopenharmony_ci
551562306a36Sopenharmony_ci	[MV88E6131] = {
551662306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131,
551762306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6185,
551862306a36Sopenharmony_ci		.name = "Marvell 88E6131",
551962306a36Sopenharmony_ci		.num_databases = 256,
552062306a36Sopenharmony_ci		.num_macs = 8192,
552162306a36Sopenharmony_ci		.num_ports = 8,
552262306a36Sopenharmony_ci		.num_internal_phys = 0,
552362306a36Sopenharmony_ci		.max_vid = 4095,
552462306a36Sopenharmony_ci		.port_base_addr = 0x10,
552562306a36Sopenharmony_ci		.phy_base_addr = 0x0,
552662306a36Sopenharmony_ci		.global1_addr = 0x1b,
552762306a36Sopenharmony_ci		.global2_addr = 0x1c,
552862306a36Sopenharmony_ci		.age_time_coeff = 15000,
552962306a36Sopenharmony_ci		.g1_irqs = 9,
553062306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
553162306a36Sopenharmony_ci		.multi_chip = true,
553262306a36Sopenharmony_ci		.ops = &mv88e6131_ops,
553362306a36Sopenharmony_ci	},
553462306a36Sopenharmony_ci
553562306a36Sopenharmony_ci	[MV88E6141] = {
553662306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141,
553762306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6341,
553862306a36Sopenharmony_ci		.name = "Marvell 88E6141",
553962306a36Sopenharmony_ci		.num_databases = 4096,
554062306a36Sopenharmony_ci		.num_macs = 2048,
554162306a36Sopenharmony_ci		.num_ports = 6,
554262306a36Sopenharmony_ci		.num_internal_phys = 5,
554362306a36Sopenharmony_ci		.num_gpio = 11,
554462306a36Sopenharmony_ci		.max_vid = 4095,
554562306a36Sopenharmony_ci		.max_sid = 63,
554662306a36Sopenharmony_ci		.port_base_addr = 0x10,
554762306a36Sopenharmony_ci		.phy_base_addr = 0x10,
554862306a36Sopenharmony_ci		.global1_addr = 0x1b,
554962306a36Sopenharmony_ci		.global2_addr = 0x1c,
555062306a36Sopenharmony_ci		.age_time_coeff = 3750,
555162306a36Sopenharmony_ci		.atu_move_port_mask = 0x1f,
555262306a36Sopenharmony_ci		.g1_irqs = 9,
555362306a36Sopenharmony_ci		.g2_irqs = 10,
555462306a36Sopenharmony_ci		.pvt = true,
555562306a36Sopenharmony_ci		.multi_chip = true,
555662306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
555762306a36Sopenharmony_ci		.ops = &mv88e6141_ops,
555862306a36Sopenharmony_ci	},
555962306a36Sopenharmony_ci
556062306a36Sopenharmony_ci	[MV88E6161] = {
556162306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161,
556262306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6165,
556362306a36Sopenharmony_ci		.name = "Marvell 88E6161",
556462306a36Sopenharmony_ci		.num_databases = 4096,
556562306a36Sopenharmony_ci		.num_macs = 1024,
556662306a36Sopenharmony_ci		.num_ports = 6,
556762306a36Sopenharmony_ci		.num_internal_phys = 5,
556862306a36Sopenharmony_ci		.max_vid = 4095,
556962306a36Sopenharmony_ci		.max_sid = 63,
557062306a36Sopenharmony_ci		.port_base_addr = 0x10,
557162306a36Sopenharmony_ci		.phy_base_addr = 0x0,
557262306a36Sopenharmony_ci		.global1_addr = 0x1b,
557362306a36Sopenharmony_ci		.global2_addr = 0x1c,
557462306a36Sopenharmony_ci		.age_time_coeff = 15000,
557562306a36Sopenharmony_ci		.g1_irqs = 9,
557662306a36Sopenharmony_ci		.g2_irqs = 10,
557762306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
557862306a36Sopenharmony_ci		.pvt = true,
557962306a36Sopenharmony_ci		.multi_chip = true,
558062306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
558162306a36Sopenharmony_ci		.ptp_support = true,
558262306a36Sopenharmony_ci		.ops = &mv88e6161_ops,
558362306a36Sopenharmony_ci	},
558462306a36Sopenharmony_ci
558562306a36Sopenharmony_ci	[MV88E6165] = {
558662306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165,
558762306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6165,
558862306a36Sopenharmony_ci		.name = "Marvell 88E6165",
558962306a36Sopenharmony_ci		.num_databases = 4096,
559062306a36Sopenharmony_ci		.num_macs = 8192,
559162306a36Sopenharmony_ci		.num_ports = 6,
559262306a36Sopenharmony_ci		.num_internal_phys = 0,
559362306a36Sopenharmony_ci		.max_vid = 4095,
559462306a36Sopenharmony_ci		.max_sid = 63,
559562306a36Sopenharmony_ci		.port_base_addr = 0x10,
559662306a36Sopenharmony_ci		.phy_base_addr = 0x0,
559762306a36Sopenharmony_ci		.global1_addr = 0x1b,
559862306a36Sopenharmony_ci		.global2_addr = 0x1c,
559962306a36Sopenharmony_ci		.age_time_coeff = 15000,
560062306a36Sopenharmony_ci		.g1_irqs = 9,
560162306a36Sopenharmony_ci		.g2_irqs = 10,
560262306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
560362306a36Sopenharmony_ci		.pvt = true,
560462306a36Sopenharmony_ci		.multi_chip = true,
560562306a36Sopenharmony_ci		.ptp_support = true,
560662306a36Sopenharmony_ci		.ops = &mv88e6165_ops,
560762306a36Sopenharmony_ci	},
560862306a36Sopenharmony_ci
560962306a36Sopenharmony_ci	[MV88E6171] = {
561062306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171,
561162306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6351,
561262306a36Sopenharmony_ci		.name = "Marvell 88E6171",
561362306a36Sopenharmony_ci		.num_databases = 4096,
561462306a36Sopenharmony_ci		.num_macs = 8192,
561562306a36Sopenharmony_ci		.num_ports = 7,
561662306a36Sopenharmony_ci		.num_internal_phys = 5,
561762306a36Sopenharmony_ci		.max_vid = 4095,
561862306a36Sopenharmony_ci		.max_sid = 63,
561962306a36Sopenharmony_ci		.port_base_addr = 0x10,
562062306a36Sopenharmony_ci		.phy_base_addr = 0x0,
562162306a36Sopenharmony_ci		.global1_addr = 0x1b,
562262306a36Sopenharmony_ci		.global2_addr = 0x1c,
562362306a36Sopenharmony_ci		.age_time_coeff = 15000,
562462306a36Sopenharmony_ci		.g1_irqs = 9,
562562306a36Sopenharmony_ci		.g2_irqs = 10,
562662306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
562762306a36Sopenharmony_ci		.pvt = true,
562862306a36Sopenharmony_ci		.multi_chip = true,
562962306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
563062306a36Sopenharmony_ci		.ops = &mv88e6171_ops,
563162306a36Sopenharmony_ci	},
563262306a36Sopenharmony_ci
563362306a36Sopenharmony_ci	[MV88E6172] = {
563462306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172,
563562306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6352,
563662306a36Sopenharmony_ci		.name = "Marvell 88E6172",
563762306a36Sopenharmony_ci		.num_databases = 4096,
563862306a36Sopenharmony_ci		.num_macs = 8192,
563962306a36Sopenharmony_ci		.num_ports = 7,
564062306a36Sopenharmony_ci		.num_internal_phys = 5,
564162306a36Sopenharmony_ci		.num_gpio = 15,
564262306a36Sopenharmony_ci		.max_vid = 4095,
564362306a36Sopenharmony_ci		.max_sid = 63,
564462306a36Sopenharmony_ci		.port_base_addr = 0x10,
564562306a36Sopenharmony_ci		.phy_base_addr = 0x0,
564662306a36Sopenharmony_ci		.global1_addr = 0x1b,
564762306a36Sopenharmony_ci		.global2_addr = 0x1c,
564862306a36Sopenharmony_ci		.age_time_coeff = 15000,
564962306a36Sopenharmony_ci		.g1_irqs = 9,
565062306a36Sopenharmony_ci		.g2_irqs = 10,
565162306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
565262306a36Sopenharmony_ci		.pvt = true,
565362306a36Sopenharmony_ci		.multi_chip = true,
565462306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
565562306a36Sopenharmony_ci		.ops = &mv88e6172_ops,
565662306a36Sopenharmony_ci	},
565762306a36Sopenharmony_ci
565862306a36Sopenharmony_ci	[MV88E6175] = {
565962306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175,
566062306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6351,
566162306a36Sopenharmony_ci		.name = "Marvell 88E6175",
566262306a36Sopenharmony_ci		.num_databases = 4096,
566362306a36Sopenharmony_ci		.num_macs = 8192,
566462306a36Sopenharmony_ci		.num_ports = 7,
566562306a36Sopenharmony_ci		.num_internal_phys = 5,
566662306a36Sopenharmony_ci		.max_vid = 4095,
566762306a36Sopenharmony_ci		.max_sid = 63,
566862306a36Sopenharmony_ci		.port_base_addr = 0x10,
566962306a36Sopenharmony_ci		.phy_base_addr = 0x0,
567062306a36Sopenharmony_ci		.global1_addr = 0x1b,
567162306a36Sopenharmony_ci		.global2_addr = 0x1c,
567262306a36Sopenharmony_ci		.age_time_coeff = 15000,
567362306a36Sopenharmony_ci		.g1_irqs = 9,
567462306a36Sopenharmony_ci		.g2_irqs = 10,
567562306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
567662306a36Sopenharmony_ci		.pvt = true,
567762306a36Sopenharmony_ci		.multi_chip = true,
567862306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
567962306a36Sopenharmony_ci		.ops = &mv88e6175_ops,
568062306a36Sopenharmony_ci	},
568162306a36Sopenharmony_ci
568262306a36Sopenharmony_ci	[MV88E6176] = {
568362306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176,
568462306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6352,
568562306a36Sopenharmony_ci		.name = "Marvell 88E6176",
568662306a36Sopenharmony_ci		.num_databases = 4096,
568762306a36Sopenharmony_ci		.num_macs = 8192,
568862306a36Sopenharmony_ci		.num_ports = 7,
568962306a36Sopenharmony_ci		.num_internal_phys = 5,
569062306a36Sopenharmony_ci		.num_gpio = 15,
569162306a36Sopenharmony_ci		.max_vid = 4095,
569262306a36Sopenharmony_ci		.max_sid = 63,
569362306a36Sopenharmony_ci		.port_base_addr = 0x10,
569462306a36Sopenharmony_ci		.phy_base_addr = 0x0,
569562306a36Sopenharmony_ci		.global1_addr = 0x1b,
569662306a36Sopenharmony_ci		.global2_addr = 0x1c,
569762306a36Sopenharmony_ci		.age_time_coeff = 15000,
569862306a36Sopenharmony_ci		.g1_irqs = 9,
569962306a36Sopenharmony_ci		.g2_irqs = 10,
570062306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
570162306a36Sopenharmony_ci		.pvt = true,
570262306a36Sopenharmony_ci		.multi_chip = true,
570362306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
570462306a36Sopenharmony_ci		.ops = &mv88e6176_ops,
570562306a36Sopenharmony_ci	},
570662306a36Sopenharmony_ci
570762306a36Sopenharmony_ci	[MV88E6185] = {
570862306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185,
570962306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6185,
571062306a36Sopenharmony_ci		.name = "Marvell 88E6185",
571162306a36Sopenharmony_ci		.num_databases = 256,
571262306a36Sopenharmony_ci		.num_macs = 8192,
571362306a36Sopenharmony_ci		.num_ports = 10,
571462306a36Sopenharmony_ci		.num_internal_phys = 0,
571562306a36Sopenharmony_ci		.max_vid = 4095,
571662306a36Sopenharmony_ci		.port_base_addr = 0x10,
571762306a36Sopenharmony_ci		.phy_base_addr = 0x0,
571862306a36Sopenharmony_ci		.global1_addr = 0x1b,
571962306a36Sopenharmony_ci		.global2_addr = 0x1c,
572062306a36Sopenharmony_ci		.age_time_coeff = 15000,
572162306a36Sopenharmony_ci		.g1_irqs = 8,
572262306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
572362306a36Sopenharmony_ci		.multi_chip = true,
572462306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
572562306a36Sopenharmony_ci		.ops = &mv88e6185_ops,
572662306a36Sopenharmony_ci	},
572762306a36Sopenharmony_ci
572862306a36Sopenharmony_ci	[MV88E6190] = {
572962306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190,
573062306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6390,
573162306a36Sopenharmony_ci		.name = "Marvell 88E6190",
573262306a36Sopenharmony_ci		.num_databases = 4096,
573362306a36Sopenharmony_ci		.num_macs = 16384,
573462306a36Sopenharmony_ci		.num_ports = 11,	/* 10 + Z80 */
573562306a36Sopenharmony_ci		.num_internal_phys = 9,
573662306a36Sopenharmony_ci		.num_gpio = 16,
573762306a36Sopenharmony_ci		.max_vid = 8191,
573862306a36Sopenharmony_ci		.max_sid = 63,
573962306a36Sopenharmony_ci		.port_base_addr = 0x0,
574062306a36Sopenharmony_ci		.phy_base_addr = 0x0,
574162306a36Sopenharmony_ci		.global1_addr = 0x1b,
574262306a36Sopenharmony_ci		.global2_addr = 0x1c,
574362306a36Sopenharmony_ci		.age_time_coeff = 3750,
574462306a36Sopenharmony_ci		.g1_irqs = 9,
574562306a36Sopenharmony_ci		.g2_irqs = 14,
574662306a36Sopenharmony_ci		.pvt = true,
574762306a36Sopenharmony_ci		.multi_chip = true,
574862306a36Sopenharmony_ci		.atu_move_port_mask = 0x1f,
574962306a36Sopenharmony_ci		.ops = &mv88e6190_ops,
575062306a36Sopenharmony_ci	},
575162306a36Sopenharmony_ci
575262306a36Sopenharmony_ci	[MV88E6190X] = {
575362306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X,
575462306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6390,
575562306a36Sopenharmony_ci		.name = "Marvell 88E6190X",
575662306a36Sopenharmony_ci		.num_databases = 4096,
575762306a36Sopenharmony_ci		.num_macs = 16384,
575862306a36Sopenharmony_ci		.num_ports = 11,	/* 10 + Z80 */
575962306a36Sopenharmony_ci		.num_internal_phys = 9,
576062306a36Sopenharmony_ci		.num_gpio = 16,
576162306a36Sopenharmony_ci		.max_vid = 8191,
576262306a36Sopenharmony_ci		.max_sid = 63,
576362306a36Sopenharmony_ci		.port_base_addr = 0x0,
576462306a36Sopenharmony_ci		.phy_base_addr = 0x0,
576562306a36Sopenharmony_ci		.global1_addr = 0x1b,
576662306a36Sopenharmony_ci		.global2_addr = 0x1c,
576762306a36Sopenharmony_ci		.age_time_coeff = 3750,
576862306a36Sopenharmony_ci		.g1_irqs = 9,
576962306a36Sopenharmony_ci		.g2_irqs = 14,
577062306a36Sopenharmony_ci		.atu_move_port_mask = 0x1f,
577162306a36Sopenharmony_ci		.pvt = true,
577262306a36Sopenharmony_ci		.multi_chip = true,
577362306a36Sopenharmony_ci		.ops = &mv88e6190x_ops,
577462306a36Sopenharmony_ci	},
577562306a36Sopenharmony_ci
577662306a36Sopenharmony_ci	[MV88E6191] = {
577762306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191,
577862306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6390,
577962306a36Sopenharmony_ci		.name = "Marvell 88E6191",
578062306a36Sopenharmony_ci		.num_databases = 4096,
578162306a36Sopenharmony_ci		.num_macs = 16384,
578262306a36Sopenharmony_ci		.num_ports = 11,	/* 10 + Z80 */
578362306a36Sopenharmony_ci		.num_internal_phys = 9,
578462306a36Sopenharmony_ci		.max_vid = 8191,
578562306a36Sopenharmony_ci		.max_sid = 63,
578662306a36Sopenharmony_ci		.port_base_addr = 0x0,
578762306a36Sopenharmony_ci		.phy_base_addr = 0x0,
578862306a36Sopenharmony_ci		.global1_addr = 0x1b,
578962306a36Sopenharmony_ci		.global2_addr = 0x1c,
579062306a36Sopenharmony_ci		.age_time_coeff = 3750,
579162306a36Sopenharmony_ci		.g1_irqs = 9,
579262306a36Sopenharmony_ci		.g2_irqs = 14,
579362306a36Sopenharmony_ci		.atu_move_port_mask = 0x1f,
579462306a36Sopenharmony_ci		.pvt = true,
579562306a36Sopenharmony_ci		.multi_chip = true,
579662306a36Sopenharmony_ci		.ptp_support = true,
579762306a36Sopenharmony_ci		.ops = &mv88e6191_ops,
579862306a36Sopenharmony_ci	},
579962306a36Sopenharmony_ci
580062306a36Sopenharmony_ci	[MV88E6191X] = {
580162306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X,
580262306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6393,
580362306a36Sopenharmony_ci		.name = "Marvell 88E6191X",
580462306a36Sopenharmony_ci		.num_databases = 4096,
580562306a36Sopenharmony_ci		.num_ports = 11,	/* 10 + Z80 */
580662306a36Sopenharmony_ci		.num_internal_phys = 8,
580762306a36Sopenharmony_ci		.internal_phys_offset = 1,
580862306a36Sopenharmony_ci		.max_vid = 8191,
580962306a36Sopenharmony_ci		.max_sid = 63,
581062306a36Sopenharmony_ci		.port_base_addr = 0x0,
581162306a36Sopenharmony_ci		.phy_base_addr = 0x0,
581262306a36Sopenharmony_ci		.global1_addr = 0x1b,
581362306a36Sopenharmony_ci		.global2_addr = 0x1c,
581462306a36Sopenharmony_ci		.age_time_coeff = 3750,
581562306a36Sopenharmony_ci		.g1_irqs = 10,
581662306a36Sopenharmony_ci		.g2_irqs = 14,
581762306a36Sopenharmony_ci		.atu_move_port_mask = 0x1f,
581862306a36Sopenharmony_ci		.pvt = true,
581962306a36Sopenharmony_ci		.multi_chip = true,
582062306a36Sopenharmony_ci		.ptp_support = true,
582162306a36Sopenharmony_ci		.ops = &mv88e6393x_ops,
582262306a36Sopenharmony_ci	},
582362306a36Sopenharmony_ci
582462306a36Sopenharmony_ci	[MV88E6193X] = {
582562306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6193X,
582662306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6393,
582762306a36Sopenharmony_ci		.name = "Marvell 88E6193X",
582862306a36Sopenharmony_ci		.num_databases = 4096,
582962306a36Sopenharmony_ci		.num_ports = 11,	/* 10 + Z80 */
583062306a36Sopenharmony_ci		.num_internal_phys = 8,
583162306a36Sopenharmony_ci		.internal_phys_offset = 1,
583262306a36Sopenharmony_ci		.max_vid = 8191,
583362306a36Sopenharmony_ci		.max_sid = 63,
583462306a36Sopenharmony_ci		.port_base_addr = 0x0,
583562306a36Sopenharmony_ci		.phy_base_addr = 0x0,
583662306a36Sopenharmony_ci		.global1_addr = 0x1b,
583762306a36Sopenharmony_ci		.global2_addr = 0x1c,
583862306a36Sopenharmony_ci		.age_time_coeff = 3750,
583962306a36Sopenharmony_ci		.g1_irqs = 10,
584062306a36Sopenharmony_ci		.g2_irqs = 14,
584162306a36Sopenharmony_ci		.atu_move_port_mask = 0x1f,
584262306a36Sopenharmony_ci		.pvt = true,
584362306a36Sopenharmony_ci		.multi_chip = true,
584462306a36Sopenharmony_ci		.ptp_support = true,
584562306a36Sopenharmony_ci		.ops = &mv88e6393x_ops,
584662306a36Sopenharmony_ci	},
584762306a36Sopenharmony_ci
584862306a36Sopenharmony_ci	[MV88E6220] = {
584962306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
585062306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6250,
585162306a36Sopenharmony_ci		.name = "Marvell 88E6220",
585262306a36Sopenharmony_ci		.num_databases = 64,
585362306a36Sopenharmony_ci
585462306a36Sopenharmony_ci		/* Ports 2-4 are not routed to pins
585562306a36Sopenharmony_ci		 * => usable ports 0, 1, 5, 6
585662306a36Sopenharmony_ci		 */
585762306a36Sopenharmony_ci		.num_ports = 7,
585862306a36Sopenharmony_ci		.num_internal_phys = 2,
585962306a36Sopenharmony_ci		.invalid_port_mask = BIT(2) | BIT(3) | BIT(4),
586062306a36Sopenharmony_ci		.max_vid = 4095,
586162306a36Sopenharmony_ci		.port_base_addr = 0x08,
586262306a36Sopenharmony_ci		.phy_base_addr = 0x00,
586362306a36Sopenharmony_ci		.global1_addr = 0x0f,
586462306a36Sopenharmony_ci		.global2_addr = 0x07,
586562306a36Sopenharmony_ci		.age_time_coeff = 15000,
586662306a36Sopenharmony_ci		.g1_irqs = 9,
586762306a36Sopenharmony_ci		.g2_irqs = 10,
586862306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
586962306a36Sopenharmony_ci		.dual_chip = true,
587062306a36Sopenharmony_ci		.ptp_support = true,
587162306a36Sopenharmony_ci		.ops = &mv88e6250_ops,
587262306a36Sopenharmony_ci	},
587362306a36Sopenharmony_ci
587462306a36Sopenharmony_ci	[MV88E6240] = {
587562306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240,
587662306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6352,
587762306a36Sopenharmony_ci		.name = "Marvell 88E6240",
587862306a36Sopenharmony_ci		.num_databases = 4096,
587962306a36Sopenharmony_ci		.num_macs = 8192,
588062306a36Sopenharmony_ci		.num_ports = 7,
588162306a36Sopenharmony_ci		.num_internal_phys = 5,
588262306a36Sopenharmony_ci		.num_gpio = 15,
588362306a36Sopenharmony_ci		.max_vid = 4095,
588462306a36Sopenharmony_ci		.max_sid = 63,
588562306a36Sopenharmony_ci		.port_base_addr = 0x10,
588662306a36Sopenharmony_ci		.phy_base_addr = 0x0,
588762306a36Sopenharmony_ci		.global1_addr = 0x1b,
588862306a36Sopenharmony_ci		.global2_addr = 0x1c,
588962306a36Sopenharmony_ci		.age_time_coeff = 15000,
589062306a36Sopenharmony_ci		.g1_irqs = 9,
589162306a36Sopenharmony_ci		.g2_irqs = 10,
589262306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
589362306a36Sopenharmony_ci		.pvt = true,
589462306a36Sopenharmony_ci		.multi_chip = true,
589562306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
589662306a36Sopenharmony_ci		.ptp_support = true,
589762306a36Sopenharmony_ci		.ops = &mv88e6240_ops,
589862306a36Sopenharmony_ci	},
589962306a36Sopenharmony_ci
590062306a36Sopenharmony_ci	[MV88E6250] = {
590162306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250,
590262306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6250,
590362306a36Sopenharmony_ci		.name = "Marvell 88E6250",
590462306a36Sopenharmony_ci		.num_databases = 64,
590562306a36Sopenharmony_ci		.num_ports = 7,
590662306a36Sopenharmony_ci		.num_internal_phys = 5,
590762306a36Sopenharmony_ci		.max_vid = 4095,
590862306a36Sopenharmony_ci		.port_base_addr = 0x08,
590962306a36Sopenharmony_ci		.phy_base_addr = 0x00,
591062306a36Sopenharmony_ci		.global1_addr = 0x0f,
591162306a36Sopenharmony_ci		.global2_addr = 0x07,
591262306a36Sopenharmony_ci		.age_time_coeff = 15000,
591362306a36Sopenharmony_ci		.g1_irqs = 9,
591462306a36Sopenharmony_ci		.g2_irqs = 10,
591562306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
591662306a36Sopenharmony_ci		.dual_chip = true,
591762306a36Sopenharmony_ci		.ptp_support = true,
591862306a36Sopenharmony_ci		.ops = &mv88e6250_ops,
591962306a36Sopenharmony_ci	},
592062306a36Sopenharmony_ci
592162306a36Sopenharmony_ci	[MV88E6290] = {
592262306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
592362306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6390,
592462306a36Sopenharmony_ci		.name = "Marvell 88E6290",
592562306a36Sopenharmony_ci		.num_databases = 4096,
592662306a36Sopenharmony_ci		.num_ports = 11,	/* 10 + Z80 */
592762306a36Sopenharmony_ci		.num_internal_phys = 9,
592862306a36Sopenharmony_ci		.num_gpio = 16,
592962306a36Sopenharmony_ci		.max_vid = 8191,
593062306a36Sopenharmony_ci		.max_sid = 63,
593162306a36Sopenharmony_ci		.port_base_addr = 0x0,
593262306a36Sopenharmony_ci		.phy_base_addr = 0x0,
593362306a36Sopenharmony_ci		.global1_addr = 0x1b,
593462306a36Sopenharmony_ci		.global2_addr = 0x1c,
593562306a36Sopenharmony_ci		.age_time_coeff = 3750,
593662306a36Sopenharmony_ci		.g1_irqs = 9,
593762306a36Sopenharmony_ci		.g2_irqs = 14,
593862306a36Sopenharmony_ci		.atu_move_port_mask = 0x1f,
593962306a36Sopenharmony_ci		.pvt = true,
594062306a36Sopenharmony_ci		.multi_chip = true,
594162306a36Sopenharmony_ci		.ptp_support = true,
594262306a36Sopenharmony_ci		.ops = &mv88e6290_ops,
594362306a36Sopenharmony_ci	},
594462306a36Sopenharmony_ci
594562306a36Sopenharmony_ci	[MV88E6320] = {
594662306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320,
594762306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6320,
594862306a36Sopenharmony_ci		.name = "Marvell 88E6320",
594962306a36Sopenharmony_ci		.num_databases = 4096,
595062306a36Sopenharmony_ci		.num_macs = 8192,
595162306a36Sopenharmony_ci		.num_ports = 7,
595262306a36Sopenharmony_ci		.num_internal_phys = 5,
595362306a36Sopenharmony_ci		.num_gpio = 15,
595462306a36Sopenharmony_ci		.max_vid = 4095,
595562306a36Sopenharmony_ci		.port_base_addr = 0x10,
595662306a36Sopenharmony_ci		.phy_base_addr = 0x0,
595762306a36Sopenharmony_ci		.global1_addr = 0x1b,
595862306a36Sopenharmony_ci		.global2_addr = 0x1c,
595962306a36Sopenharmony_ci		.age_time_coeff = 15000,
596062306a36Sopenharmony_ci		.g1_irqs = 8,
596162306a36Sopenharmony_ci		.g2_irqs = 10,
596262306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
596362306a36Sopenharmony_ci		.pvt = true,
596462306a36Sopenharmony_ci		.multi_chip = true,
596562306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
596662306a36Sopenharmony_ci		.ptp_support = true,
596762306a36Sopenharmony_ci		.ops = &mv88e6320_ops,
596862306a36Sopenharmony_ci	},
596962306a36Sopenharmony_ci
597062306a36Sopenharmony_ci	[MV88E6321] = {
597162306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321,
597262306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6320,
597362306a36Sopenharmony_ci		.name = "Marvell 88E6321",
597462306a36Sopenharmony_ci		.num_databases = 4096,
597562306a36Sopenharmony_ci		.num_macs = 8192,
597662306a36Sopenharmony_ci		.num_ports = 7,
597762306a36Sopenharmony_ci		.num_internal_phys = 5,
597862306a36Sopenharmony_ci		.num_gpio = 15,
597962306a36Sopenharmony_ci		.max_vid = 4095,
598062306a36Sopenharmony_ci		.port_base_addr = 0x10,
598162306a36Sopenharmony_ci		.phy_base_addr = 0x0,
598262306a36Sopenharmony_ci		.global1_addr = 0x1b,
598362306a36Sopenharmony_ci		.global2_addr = 0x1c,
598462306a36Sopenharmony_ci		.age_time_coeff = 15000,
598562306a36Sopenharmony_ci		.g1_irqs = 8,
598662306a36Sopenharmony_ci		.g2_irqs = 10,
598762306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
598862306a36Sopenharmony_ci		.multi_chip = true,
598962306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
599062306a36Sopenharmony_ci		.ptp_support = true,
599162306a36Sopenharmony_ci		.ops = &mv88e6321_ops,
599262306a36Sopenharmony_ci	},
599362306a36Sopenharmony_ci
599462306a36Sopenharmony_ci	[MV88E6341] = {
599562306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
599662306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6341,
599762306a36Sopenharmony_ci		.name = "Marvell 88E6341",
599862306a36Sopenharmony_ci		.num_databases = 4096,
599962306a36Sopenharmony_ci		.num_macs = 2048,
600062306a36Sopenharmony_ci		.num_internal_phys = 5,
600162306a36Sopenharmony_ci		.num_ports = 6,
600262306a36Sopenharmony_ci		.num_gpio = 11,
600362306a36Sopenharmony_ci		.max_vid = 4095,
600462306a36Sopenharmony_ci		.max_sid = 63,
600562306a36Sopenharmony_ci		.port_base_addr = 0x10,
600662306a36Sopenharmony_ci		.phy_base_addr = 0x10,
600762306a36Sopenharmony_ci		.global1_addr = 0x1b,
600862306a36Sopenharmony_ci		.global2_addr = 0x1c,
600962306a36Sopenharmony_ci		.age_time_coeff = 3750,
601062306a36Sopenharmony_ci		.atu_move_port_mask = 0x1f,
601162306a36Sopenharmony_ci		.g1_irqs = 9,
601262306a36Sopenharmony_ci		.g2_irqs = 10,
601362306a36Sopenharmony_ci		.pvt = true,
601462306a36Sopenharmony_ci		.multi_chip = true,
601562306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
601662306a36Sopenharmony_ci		.ptp_support = true,
601762306a36Sopenharmony_ci		.ops = &mv88e6341_ops,
601862306a36Sopenharmony_ci	},
601962306a36Sopenharmony_ci
602062306a36Sopenharmony_ci	[MV88E6350] = {
602162306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350,
602262306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6351,
602362306a36Sopenharmony_ci		.name = "Marvell 88E6350",
602462306a36Sopenharmony_ci		.num_databases = 4096,
602562306a36Sopenharmony_ci		.num_macs = 8192,
602662306a36Sopenharmony_ci		.num_ports = 7,
602762306a36Sopenharmony_ci		.num_internal_phys = 5,
602862306a36Sopenharmony_ci		.max_vid = 4095,
602962306a36Sopenharmony_ci		.max_sid = 63,
603062306a36Sopenharmony_ci		.port_base_addr = 0x10,
603162306a36Sopenharmony_ci		.phy_base_addr = 0x0,
603262306a36Sopenharmony_ci		.global1_addr = 0x1b,
603362306a36Sopenharmony_ci		.global2_addr = 0x1c,
603462306a36Sopenharmony_ci		.age_time_coeff = 15000,
603562306a36Sopenharmony_ci		.g1_irqs = 9,
603662306a36Sopenharmony_ci		.g2_irqs = 10,
603762306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
603862306a36Sopenharmony_ci		.pvt = true,
603962306a36Sopenharmony_ci		.multi_chip = true,
604062306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
604162306a36Sopenharmony_ci		.ops = &mv88e6350_ops,
604262306a36Sopenharmony_ci	},
604362306a36Sopenharmony_ci
604462306a36Sopenharmony_ci	[MV88E6351] = {
604562306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351,
604662306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6351,
604762306a36Sopenharmony_ci		.name = "Marvell 88E6351",
604862306a36Sopenharmony_ci		.num_databases = 4096,
604962306a36Sopenharmony_ci		.num_macs = 8192,
605062306a36Sopenharmony_ci		.num_ports = 7,
605162306a36Sopenharmony_ci		.num_internal_phys = 5,
605262306a36Sopenharmony_ci		.max_vid = 4095,
605362306a36Sopenharmony_ci		.max_sid = 63,
605462306a36Sopenharmony_ci		.port_base_addr = 0x10,
605562306a36Sopenharmony_ci		.phy_base_addr = 0x0,
605662306a36Sopenharmony_ci		.global1_addr = 0x1b,
605762306a36Sopenharmony_ci		.global2_addr = 0x1c,
605862306a36Sopenharmony_ci		.age_time_coeff = 15000,
605962306a36Sopenharmony_ci		.g1_irqs = 9,
606062306a36Sopenharmony_ci		.g2_irqs = 10,
606162306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
606262306a36Sopenharmony_ci		.pvt = true,
606362306a36Sopenharmony_ci		.multi_chip = true,
606462306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
606562306a36Sopenharmony_ci		.ops = &mv88e6351_ops,
606662306a36Sopenharmony_ci	},
606762306a36Sopenharmony_ci
606862306a36Sopenharmony_ci	[MV88E6352] = {
606962306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352,
607062306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6352,
607162306a36Sopenharmony_ci		.name = "Marvell 88E6352",
607262306a36Sopenharmony_ci		.num_databases = 4096,
607362306a36Sopenharmony_ci		.num_macs = 8192,
607462306a36Sopenharmony_ci		.num_ports = 7,
607562306a36Sopenharmony_ci		.num_internal_phys = 5,
607662306a36Sopenharmony_ci		.num_gpio = 15,
607762306a36Sopenharmony_ci		.max_vid = 4095,
607862306a36Sopenharmony_ci		.max_sid = 63,
607962306a36Sopenharmony_ci		.port_base_addr = 0x10,
608062306a36Sopenharmony_ci		.phy_base_addr = 0x0,
608162306a36Sopenharmony_ci		.global1_addr = 0x1b,
608262306a36Sopenharmony_ci		.global2_addr = 0x1c,
608362306a36Sopenharmony_ci		.age_time_coeff = 15000,
608462306a36Sopenharmony_ci		.g1_irqs = 9,
608562306a36Sopenharmony_ci		.g2_irqs = 10,
608662306a36Sopenharmony_ci		.atu_move_port_mask = 0xf,
608762306a36Sopenharmony_ci		.pvt = true,
608862306a36Sopenharmony_ci		.multi_chip = true,
608962306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
609062306a36Sopenharmony_ci		.ptp_support = true,
609162306a36Sopenharmony_ci		.ops = &mv88e6352_ops,
609262306a36Sopenharmony_ci	},
609362306a36Sopenharmony_ci	[MV88E6361] = {
609462306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6361,
609562306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6393,
609662306a36Sopenharmony_ci		.name = "Marvell 88E6361",
609762306a36Sopenharmony_ci		.num_databases = 4096,
609862306a36Sopenharmony_ci		.num_macs = 16384,
609962306a36Sopenharmony_ci		.num_ports = 11,
610062306a36Sopenharmony_ci		/* Ports 1, 2 and 8 are not routed */
610162306a36Sopenharmony_ci		.invalid_port_mask = BIT(1) | BIT(2) | BIT(8),
610262306a36Sopenharmony_ci		.num_internal_phys = 5,
610362306a36Sopenharmony_ci		.internal_phys_offset = 3,
610462306a36Sopenharmony_ci		.max_vid = 4095,
610562306a36Sopenharmony_ci		.max_sid = 63,
610662306a36Sopenharmony_ci		.port_base_addr = 0x0,
610762306a36Sopenharmony_ci		.phy_base_addr = 0x0,
610862306a36Sopenharmony_ci		.global1_addr = 0x1b,
610962306a36Sopenharmony_ci		.global2_addr = 0x1c,
611062306a36Sopenharmony_ci		.age_time_coeff = 3750,
611162306a36Sopenharmony_ci		.g1_irqs = 10,
611262306a36Sopenharmony_ci		.g2_irqs = 14,
611362306a36Sopenharmony_ci		.atu_move_port_mask = 0x1f,
611462306a36Sopenharmony_ci		.pvt = true,
611562306a36Sopenharmony_ci		.multi_chip = true,
611662306a36Sopenharmony_ci		.ptp_support = true,
611762306a36Sopenharmony_ci		.ops = &mv88e6393x_ops,
611862306a36Sopenharmony_ci	},
611962306a36Sopenharmony_ci	[MV88E6390] = {
612062306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
612162306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6390,
612262306a36Sopenharmony_ci		.name = "Marvell 88E6390",
612362306a36Sopenharmony_ci		.num_databases = 4096,
612462306a36Sopenharmony_ci		.num_macs = 16384,
612562306a36Sopenharmony_ci		.num_ports = 11,	/* 10 + Z80 */
612662306a36Sopenharmony_ci		.num_internal_phys = 9,
612762306a36Sopenharmony_ci		.num_gpio = 16,
612862306a36Sopenharmony_ci		.max_vid = 8191,
612962306a36Sopenharmony_ci		.max_sid = 63,
613062306a36Sopenharmony_ci		.port_base_addr = 0x0,
613162306a36Sopenharmony_ci		.phy_base_addr = 0x0,
613262306a36Sopenharmony_ci		.global1_addr = 0x1b,
613362306a36Sopenharmony_ci		.global2_addr = 0x1c,
613462306a36Sopenharmony_ci		.age_time_coeff = 3750,
613562306a36Sopenharmony_ci		.g1_irqs = 9,
613662306a36Sopenharmony_ci		.g2_irqs = 14,
613762306a36Sopenharmony_ci		.atu_move_port_mask = 0x1f,
613862306a36Sopenharmony_ci		.pvt = true,
613962306a36Sopenharmony_ci		.multi_chip = true,
614062306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED,
614162306a36Sopenharmony_ci		.ptp_support = true,
614262306a36Sopenharmony_ci		.ops = &mv88e6390_ops,
614362306a36Sopenharmony_ci	},
614462306a36Sopenharmony_ci	[MV88E6390X] = {
614562306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X,
614662306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6390,
614762306a36Sopenharmony_ci		.name = "Marvell 88E6390X",
614862306a36Sopenharmony_ci		.num_databases = 4096,
614962306a36Sopenharmony_ci		.num_macs = 16384,
615062306a36Sopenharmony_ci		.num_ports = 11,	/* 10 + Z80 */
615162306a36Sopenharmony_ci		.num_internal_phys = 9,
615262306a36Sopenharmony_ci		.num_gpio = 16,
615362306a36Sopenharmony_ci		.max_vid = 8191,
615462306a36Sopenharmony_ci		.max_sid = 63,
615562306a36Sopenharmony_ci		.port_base_addr = 0x0,
615662306a36Sopenharmony_ci		.phy_base_addr = 0x0,
615762306a36Sopenharmony_ci		.global1_addr = 0x1b,
615862306a36Sopenharmony_ci		.global2_addr = 0x1c,
615962306a36Sopenharmony_ci		.age_time_coeff = 3750,
616062306a36Sopenharmony_ci		.g1_irqs = 9,
616162306a36Sopenharmony_ci		.g2_irqs = 14,
616262306a36Sopenharmony_ci		.atu_move_port_mask = 0x1f,
616362306a36Sopenharmony_ci		.pvt = true,
616462306a36Sopenharmony_ci		.multi_chip = true,
616562306a36Sopenharmony_ci		.edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED,
616662306a36Sopenharmony_ci		.ptp_support = true,
616762306a36Sopenharmony_ci		.ops = &mv88e6390x_ops,
616862306a36Sopenharmony_ci	},
616962306a36Sopenharmony_ci
617062306a36Sopenharmony_ci	[MV88E6393X] = {
617162306a36Sopenharmony_ci		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
617262306a36Sopenharmony_ci		.family = MV88E6XXX_FAMILY_6393,
617362306a36Sopenharmony_ci		.name = "Marvell 88E6393X",
617462306a36Sopenharmony_ci		.num_databases = 4096,
617562306a36Sopenharmony_ci		.num_ports = 11,	/* 10 + Z80 */
617662306a36Sopenharmony_ci		.num_internal_phys = 8,
617762306a36Sopenharmony_ci		.internal_phys_offset = 1,
617862306a36Sopenharmony_ci		.max_vid = 8191,
617962306a36Sopenharmony_ci		.max_sid = 63,
618062306a36Sopenharmony_ci		.port_base_addr = 0x0,
618162306a36Sopenharmony_ci		.phy_base_addr = 0x0,
618262306a36Sopenharmony_ci		.global1_addr = 0x1b,
618362306a36Sopenharmony_ci		.global2_addr = 0x1c,
618462306a36Sopenharmony_ci		.age_time_coeff = 3750,
618562306a36Sopenharmony_ci		.g1_irqs = 10,
618662306a36Sopenharmony_ci		.g2_irqs = 14,
618762306a36Sopenharmony_ci		.atu_move_port_mask = 0x1f,
618862306a36Sopenharmony_ci		.pvt = true,
618962306a36Sopenharmony_ci		.multi_chip = true,
619062306a36Sopenharmony_ci		.ptp_support = true,
619162306a36Sopenharmony_ci		.ops = &mv88e6393x_ops,
619262306a36Sopenharmony_ci	},
619362306a36Sopenharmony_ci};
619462306a36Sopenharmony_ci
619562306a36Sopenharmony_cistatic const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
619662306a36Sopenharmony_ci{
619762306a36Sopenharmony_ci	int i;
619862306a36Sopenharmony_ci
619962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
620062306a36Sopenharmony_ci		if (mv88e6xxx_table[i].prod_num == prod_num)
620162306a36Sopenharmony_ci			return &mv88e6xxx_table[i];
620262306a36Sopenharmony_ci
620362306a36Sopenharmony_ci	return NULL;
620462306a36Sopenharmony_ci}
620562306a36Sopenharmony_ci
620662306a36Sopenharmony_cistatic int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
620762306a36Sopenharmony_ci{
620862306a36Sopenharmony_ci	const struct mv88e6xxx_info *info;
620962306a36Sopenharmony_ci	unsigned int prod_num, rev;
621062306a36Sopenharmony_ci	u16 id;
621162306a36Sopenharmony_ci	int err;
621262306a36Sopenharmony_ci
621362306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
621462306a36Sopenharmony_ci	err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
621562306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
621662306a36Sopenharmony_ci	if (err)
621762306a36Sopenharmony_ci		return err;
621862306a36Sopenharmony_ci
621962306a36Sopenharmony_ci	prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK;
622062306a36Sopenharmony_ci	rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK;
622162306a36Sopenharmony_ci
622262306a36Sopenharmony_ci	info = mv88e6xxx_lookup_info(prod_num);
622362306a36Sopenharmony_ci	if (!info)
622462306a36Sopenharmony_ci		return -ENODEV;
622562306a36Sopenharmony_ci
622662306a36Sopenharmony_ci	/* Update the compatible info with the probed one */
622762306a36Sopenharmony_ci	chip->info = info;
622862306a36Sopenharmony_ci
622962306a36Sopenharmony_ci	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
623062306a36Sopenharmony_ci		 chip->info->prod_num, chip->info->name, rev);
623162306a36Sopenharmony_ci
623262306a36Sopenharmony_ci	return 0;
623362306a36Sopenharmony_ci}
623462306a36Sopenharmony_ci
623562306a36Sopenharmony_cistatic int mv88e6xxx_single_chip_detect(struct mv88e6xxx_chip *chip,
623662306a36Sopenharmony_ci					struct mdio_device *mdiodev)
623762306a36Sopenharmony_ci{
623862306a36Sopenharmony_ci	int err;
623962306a36Sopenharmony_ci
624062306a36Sopenharmony_ci	/* dual_chip takes precedence over single/multi-chip modes */
624162306a36Sopenharmony_ci	if (chip->info->dual_chip)
624262306a36Sopenharmony_ci		return -EINVAL;
624362306a36Sopenharmony_ci
624462306a36Sopenharmony_ci	/* If the mdio addr is 16 indicating the first port address of a switch
624562306a36Sopenharmony_ci	 * (e.g. mv88e6*41) in single chip addressing mode the device may be
624662306a36Sopenharmony_ci	 * configured in single chip addressing mode. Setup the smi access as
624762306a36Sopenharmony_ci	 * single chip addressing mode and attempt to detect the model of the
624862306a36Sopenharmony_ci	 * switch, if this fails the device is not configured in single chip
624962306a36Sopenharmony_ci	 * addressing mode.
625062306a36Sopenharmony_ci	 */
625162306a36Sopenharmony_ci	if (mdiodev->addr != 16)
625262306a36Sopenharmony_ci		return -EINVAL;
625362306a36Sopenharmony_ci
625462306a36Sopenharmony_ci	err = mv88e6xxx_smi_init(chip, mdiodev->bus, 0);
625562306a36Sopenharmony_ci	if (err)
625662306a36Sopenharmony_ci		return err;
625762306a36Sopenharmony_ci
625862306a36Sopenharmony_ci	return mv88e6xxx_detect(chip);
625962306a36Sopenharmony_ci}
626062306a36Sopenharmony_ci
626162306a36Sopenharmony_cistatic struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
626262306a36Sopenharmony_ci{
626362306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip;
626462306a36Sopenharmony_ci
626562306a36Sopenharmony_ci	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
626662306a36Sopenharmony_ci	if (!chip)
626762306a36Sopenharmony_ci		return NULL;
626862306a36Sopenharmony_ci
626962306a36Sopenharmony_ci	chip->dev = dev;
627062306a36Sopenharmony_ci
627162306a36Sopenharmony_ci	mutex_init(&chip->reg_lock);
627262306a36Sopenharmony_ci	INIT_LIST_HEAD(&chip->mdios);
627362306a36Sopenharmony_ci	idr_init(&chip->policies);
627462306a36Sopenharmony_ci	INIT_LIST_HEAD(&chip->msts);
627562306a36Sopenharmony_ci
627662306a36Sopenharmony_ci	return chip;
627762306a36Sopenharmony_ci}
627862306a36Sopenharmony_ci
627962306a36Sopenharmony_cistatic enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
628062306a36Sopenharmony_ci							int port,
628162306a36Sopenharmony_ci							enum dsa_tag_protocol m)
628262306a36Sopenharmony_ci{
628362306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
628462306a36Sopenharmony_ci
628562306a36Sopenharmony_ci	return chip->tag_protocol;
628662306a36Sopenharmony_ci}
628762306a36Sopenharmony_ci
628862306a36Sopenharmony_cistatic int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds,
628962306a36Sopenharmony_ci					 enum dsa_tag_protocol proto)
629062306a36Sopenharmony_ci{
629162306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
629262306a36Sopenharmony_ci	enum dsa_tag_protocol old_protocol;
629362306a36Sopenharmony_ci	struct dsa_port *cpu_dp;
629462306a36Sopenharmony_ci	int err;
629562306a36Sopenharmony_ci
629662306a36Sopenharmony_ci	switch (proto) {
629762306a36Sopenharmony_ci	case DSA_TAG_PROTO_EDSA:
629862306a36Sopenharmony_ci		switch (chip->info->edsa_support) {
629962306a36Sopenharmony_ci		case MV88E6XXX_EDSA_UNSUPPORTED:
630062306a36Sopenharmony_ci			return -EPROTONOSUPPORT;
630162306a36Sopenharmony_ci		case MV88E6XXX_EDSA_UNDOCUMENTED:
630262306a36Sopenharmony_ci			dev_warn(chip->dev, "Relying on undocumented EDSA tagging behavior\n");
630362306a36Sopenharmony_ci			fallthrough;
630462306a36Sopenharmony_ci		case MV88E6XXX_EDSA_SUPPORTED:
630562306a36Sopenharmony_ci			break;
630662306a36Sopenharmony_ci		}
630762306a36Sopenharmony_ci		break;
630862306a36Sopenharmony_ci	case DSA_TAG_PROTO_DSA:
630962306a36Sopenharmony_ci		break;
631062306a36Sopenharmony_ci	default:
631162306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
631262306a36Sopenharmony_ci	}
631362306a36Sopenharmony_ci
631462306a36Sopenharmony_ci	old_protocol = chip->tag_protocol;
631562306a36Sopenharmony_ci	chip->tag_protocol = proto;
631662306a36Sopenharmony_ci
631762306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
631862306a36Sopenharmony_ci	dsa_switch_for_each_cpu_port(cpu_dp, ds) {
631962306a36Sopenharmony_ci		err = mv88e6xxx_setup_port_mode(chip, cpu_dp->index);
632062306a36Sopenharmony_ci		if (err) {
632162306a36Sopenharmony_ci			mv88e6xxx_reg_unlock(chip);
632262306a36Sopenharmony_ci			goto unwind;
632362306a36Sopenharmony_ci		}
632462306a36Sopenharmony_ci	}
632562306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
632662306a36Sopenharmony_ci
632762306a36Sopenharmony_ci	return 0;
632862306a36Sopenharmony_ci
632962306a36Sopenharmony_ciunwind:
633062306a36Sopenharmony_ci	chip->tag_protocol = old_protocol;
633162306a36Sopenharmony_ci
633262306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
633362306a36Sopenharmony_ci	dsa_switch_for_each_cpu_port_continue_reverse(cpu_dp, ds)
633462306a36Sopenharmony_ci		mv88e6xxx_setup_port_mode(chip, cpu_dp->index);
633562306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
633662306a36Sopenharmony_ci
633762306a36Sopenharmony_ci	return err;
633862306a36Sopenharmony_ci}
633962306a36Sopenharmony_ci
634062306a36Sopenharmony_cistatic int mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
634162306a36Sopenharmony_ci				  const struct switchdev_obj_port_mdb *mdb,
634262306a36Sopenharmony_ci				  struct dsa_db db)
634362306a36Sopenharmony_ci{
634462306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
634562306a36Sopenharmony_ci	int err;
634662306a36Sopenharmony_ci
634762306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
634862306a36Sopenharmony_ci	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
634962306a36Sopenharmony_ci					   MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC);
635062306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
635162306a36Sopenharmony_ci
635262306a36Sopenharmony_ci	return err;
635362306a36Sopenharmony_ci}
635462306a36Sopenharmony_ci
635562306a36Sopenharmony_cistatic int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
635662306a36Sopenharmony_ci				  const struct switchdev_obj_port_mdb *mdb,
635762306a36Sopenharmony_ci				  struct dsa_db db)
635862306a36Sopenharmony_ci{
635962306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
636062306a36Sopenharmony_ci	int err;
636162306a36Sopenharmony_ci
636262306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
636362306a36Sopenharmony_ci	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0);
636462306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
636562306a36Sopenharmony_ci
636662306a36Sopenharmony_ci	return err;
636762306a36Sopenharmony_ci}
636862306a36Sopenharmony_ci
636962306a36Sopenharmony_cistatic int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
637062306a36Sopenharmony_ci				     struct dsa_mall_mirror_tc_entry *mirror,
637162306a36Sopenharmony_ci				     bool ingress,
637262306a36Sopenharmony_ci				     struct netlink_ext_ack *extack)
637362306a36Sopenharmony_ci{
637462306a36Sopenharmony_ci	enum mv88e6xxx_egress_direction direction = ingress ?
637562306a36Sopenharmony_ci						MV88E6XXX_EGRESS_DIR_INGRESS :
637662306a36Sopenharmony_ci						MV88E6XXX_EGRESS_DIR_EGRESS;
637762306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
637862306a36Sopenharmony_ci	bool other_mirrors = false;
637962306a36Sopenharmony_ci	int i;
638062306a36Sopenharmony_ci	int err;
638162306a36Sopenharmony_ci
638262306a36Sopenharmony_ci	mutex_lock(&chip->reg_lock);
638362306a36Sopenharmony_ci	if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
638462306a36Sopenharmony_ci	    mirror->to_local_port) {
638562306a36Sopenharmony_ci		for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
638662306a36Sopenharmony_ci			other_mirrors |= ingress ?
638762306a36Sopenharmony_ci					 chip->ports[i].mirror_ingress :
638862306a36Sopenharmony_ci					 chip->ports[i].mirror_egress;
638962306a36Sopenharmony_ci
639062306a36Sopenharmony_ci		/* Can't change egress port when other mirror is active */
639162306a36Sopenharmony_ci		if (other_mirrors) {
639262306a36Sopenharmony_ci			err = -EBUSY;
639362306a36Sopenharmony_ci			goto out;
639462306a36Sopenharmony_ci		}
639562306a36Sopenharmony_ci
639662306a36Sopenharmony_ci		err = mv88e6xxx_set_egress_port(chip, direction,
639762306a36Sopenharmony_ci						mirror->to_local_port);
639862306a36Sopenharmony_ci		if (err)
639962306a36Sopenharmony_ci			goto out;
640062306a36Sopenharmony_ci	}
640162306a36Sopenharmony_ci
640262306a36Sopenharmony_ci	err = mv88e6xxx_port_set_mirror(chip, port, direction, true);
640362306a36Sopenharmony_ciout:
640462306a36Sopenharmony_ci	mutex_unlock(&chip->reg_lock);
640562306a36Sopenharmony_ci
640662306a36Sopenharmony_ci	return err;
640762306a36Sopenharmony_ci}
640862306a36Sopenharmony_ci
640962306a36Sopenharmony_cistatic void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
641062306a36Sopenharmony_ci				      struct dsa_mall_mirror_tc_entry *mirror)
641162306a36Sopenharmony_ci{
641262306a36Sopenharmony_ci	enum mv88e6xxx_egress_direction direction = mirror->ingress ?
641362306a36Sopenharmony_ci						MV88E6XXX_EGRESS_DIR_INGRESS :
641462306a36Sopenharmony_ci						MV88E6XXX_EGRESS_DIR_EGRESS;
641562306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
641662306a36Sopenharmony_ci	bool other_mirrors = false;
641762306a36Sopenharmony_ci	int i;
641862306a36Sopenharmony_ci
641962306a36Sopenharmony_ci	mutex_lock(&chip->reg_lock);
642062306a36Sopenharmony_ci	if (mv88e6xxx_port_set_mirror(chip, port, direction, false))
642162306a36Sopenharmony_ci		dev_err(ds->dev, "p%d: failed to disable mirroring\n", port);
642262306a36Sopenharmony_ci
642362306a36Sopenharmony_ci	for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
642462306a36Sopenharmony_ci		other_mirrors |= mirror->ingress ?
642562306a36Sopenharmony_ci				 chip->ports[i].mirror_ingress :
642662306a36Sopenharmony_ci				 chip->ports[i].mirror_egress;
642762306a36Sopenharmony_ci
642862306a36Sopenharmony_ci	/* Reset egress port when no other mirror is active */
642962306a36Sopenharmony_ci	if (!other_mirrors) {
643062306a36Sopenharmony_ci		if (mv88e6xxx_set_egress_port(chip, direction,
643162306a36Sopenharmony_ci					      dsa_upstream_port(ds, port)))
643262306a36Sopenharmony_ci			dev_err(ds->dev, "failed to set egress port\n");
643362306a36Sopenharmony_ci	}
643462306a36Sopenharmony_ci
643562306a36Sopenharmony_ci	mutex_unlock(&chip->reg_lock);
643662306a36Sopenharmony_ci}
643762306a36Sopenharmony_ci
643862306a36Sopenharmony_cistatic int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port,
643962306a36Sopenharmony_ci					   struct switchdev_brport_flags flags,
644062306a36Sopenharmony_ci					   struct netlink_ext_ack *extack)
644162306a36Sopenharmony_ci{
644262306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
644362306a36Sopenharmony_ci	const struct mv88e6xxx_ops *ops;
644462306a36Sopenharmony_ci
644562306a36Sopenharmony_ci	if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
644662306a36Sopenharmony_ci			   BR_BCAST_FLOOD | BR_PORT_LOCKED | BR_PORT_MAB))
644762306a36Sopenharmony_ci		return -EINVAL;
644862306a36Sopenharmony_ci
644962306a36Sopenharmony_ci	ops = chip->info->ops;
645062306a36Sopenharmony_ci
645162306a36Sopenharmony_ci	if ((flags.mask & BR_FLOOD) && !ops->port_set_ucast_flood)
645262306a36Sopenharmony_ci		return -EINVAL;
645362306a36Sopenharmony_ci
645462306a36Sopenharmony_ci	if ((flags.mask & BR_MCAST_FLOOD) && !ops->port_set_mcast_flood)
645562306a36Sopenharmony_ci		return -EINVAL;
645662306a36Sopenharmony_ci
645762306a36Sopenharmony_ci	return 0;
645862306a36Sopenharmony_ci}
645962306a36Sopenharmony_ci
646062306a36Sopenharmony_cistatic int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
646162306a36Sopenharmony_ci				       struct switchdev_brport_flags flags,
646262306a36Sopenharmony_ci				       struct netlink_ext_ack *extack)
646362306a36Sopenharmony_ci{
646462306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
646562306a36Sopenharmony_ci	int err = 0;
646662306a36Sopenharmony_ci
646762306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
646862306a36Sopenharmony_ci
646962306a36Sopenharmony_ci	if (flags.mask & BR_LEARNING) {
647062306a36Sopenharmony_ci		bool learning = !!(flags.val & BR_LEARNING);
647162306a36Sopenharmony_ci		u16 pav = learning ? (1 << port) : 0;
647262306a36Sopenharmony_ci
647362306a36Sopenharmony_ci		err = mv88e6xxx_port_set_assoc_vector(chip, port, pav);
647462306a36Sopenharmony_ci		if (err)
647562306a36Sopenharmony_ci			goto out;
647662306a36Sopenharmony_ci	}
647762306a36Sopenharmony_ci
647862306a36Sopenharmony_ci	if (flags.mask & BR_FLOOD) {
647962306a36Sopenharmony_ci		bool unicast = !!(flags.val & BR_FLOOD);
648062306a36Sopenharmony_ci
648162306a36Sopenharmony_ci		err = chip->info->ops->port_set_ucast_flood(chip, port,
648262306a36Sopenharmony_ci							    unicast);
648362306a36Sopenharmony_ci		if (err)
648462306a36Sopenharmony_ci			goto out;
648562306a36Sopenharmony_ci	}
648662306a36Sopenharmony_ci
648762306a36Sopenharmony_ci	if (flags.mask & BR_MCAST_FLOOD) {
648862306a36Sopenharmony_ci		bool multicast = !!(flags.val & BR_MCAST_FLOOD);
648962306a36Sopenharmony_ci
649062306a36Sopenharmony_ci		err = chip->info->ops->port_set_mcast_flood(chip, port,
649162306a36Sopenharmony_ci							    multicast);
649262306a36Sopenharmony_ci		if (err)
649362306a36Sopenharmony_ci			goto out;
649462306a36Sopenharmony_ci	}
649562306a36Sopenharmony_ci
649662306a36Sopenharmony_ci	if (flags.mask & BR_BCAST_FLOOD) {
649762306a36Sopenharmony_ci		bool broadcast = !!(flags.val & BR_BCAST_FLOOD);
649862306a36Sopenharmony_ci
649962306a36Sopenharmony_ci		err = mv88e6xxx_port_broadcast_sync(chip, port, broadcast);
650062306a36Sopenharmony_ci		if (err)
650162306a36Sopenharmony_ci			goto out;
650262306a36Sopenharmony_ci	}
650362306a36Sopenharmony_ci
650462306a36Sopenharmony_ci	if (flags.mask & BR_PORT_MAB) {
650562306a36Sopenharmony_ci		bool mab = !!(flags.val & BR_PORT_MAB);
650662306a36Sopenharmony_ci
650762306a36Sopenharmony_ci		mv88e6xxx_port_set_mab(chip, port, mab);
650862306a36Sopenharmony_ci	}
650962306a36Sopenharmony_ci
651062306a36Sopenharmony_ci	if (flags.mask & BR_PORT_LOCKED) {
651162306a36Sopenharmony_ci		bool locked = !!(flags.val & BR_PORT_LOCKED);
651262306a36Sopenharmony_ci
651362306a36Sopenharmony_ci		err = mv88e6xxx_port_set_lock(chip, port, locked);
651462306a36Sopenharmony_ci		if (err)
651562306a36Sopenharmony_ci			goto out;
651662306a36Sopenharmony_ci	}
651762306a36Sopenharmony_ciout:
651862306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
651962306a36Sopenharmony_ci
652062306a36Sopenharmony_ci	return err;
652162306a36Sopenharmony_ci}
652262306a36Sopenharmony_ci
652362306a36Sopenharmony_cistatic bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds,
652462306a36Sopenharmony_ci				      struct dsa_lag lag,
652562306a36Sopenharmony_ci				      struct netdev_lag_upper_info *info,
652662306a36Sopenharmony_ci				      struct netlink_ext_ack *extack)
652762306a36Sopenharmony_ci{
652862306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
652962306a36Sopenharmony_ci	struct dsa_port *dp;
653062306a36Sopenharmony_ci	int members = 0;
653162306a36Sopenharmony_ci
653262306a36Sopenharmony_ci	if (!mv88e6xxx_has_lag(chip)) {
653362306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Chip does not support LAG offload");
653462306a36Sopenharmony_ci		return false;
653562306a36Sopenharmony_ci	}
653662306a36Sopenharmony_ci
653762306a36Sopenharmony_ci	if (!lag.id)
653862306a36Sopenharmony_ci		return false;
653962306a36Sopenharmony_ci
654062306a36Sopenharmony_ci	dsa_lag_foreach_port(dp, ds->dst, &lag)
654162306a36Sopenharmony_ci		/* Includes the port joining the LAG */
654262306a36Sopenharmony_ci		members++;
654362306a36Sopenharmony_ci
654462306a36Sopenharmony_ci	if (members > 8) {
654562306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack,
654662306a36Sopenharmony_ci				   "Cannot offload more than 8 LAG ports");
654762306a36Sopenharmony_ci		return false;
654862306a36Sopenharmony_ci	}
654962306a36Sopenharmony_ci
655062306a36Sopenharmony_ci	/* We could potentially relax this to include active
655162306a36Sopenharmony_ci	 * backup in the future.
655262306a36Sopenharmony_ci	 */
655362306a36Sopenharmony_ci	if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
655462306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack,
655562306a36Sopenharmony_ci				   "Can only offload LAG using hash TX type");
655662306a36Sopenharmony_ci		return false;
655762306a36Sopenharmony_ci	}
655862306a36Sopenharmony_ci
655962306a36Sopenharmony_ci	/* Ideally we would also validate that the hash type matches
656062306a36Sopenharmony_ci	 * the hardware. Alas, this is always set to unknown on team
656162306a36Sopenharmony_ci	 * interfaces.
656262306a36Sopenharmony_ci	 */
656362306a36Sopenharmony_ci	return true;
656462306a36Sopenharmony_ci}
656562306a36Sopenharmony_ci
656662306a36Sopenharmony_cistatic int mv88e6xxx_lag_sync_map(struct dsa_switch *ds, struct dsa_lag lag)
656762306a36Sopenharmony_ci{
656862306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
656962306a36Sopenharmony_ci	struct dsa_port *dp;
657062306a36Sopenharmony_ci	u16 map = 0;
657162306a36Sopenharmony_ci	int id;
657262306a36Sopenharmony_ci
657362306a36Sopenharmony_ci	/* DSA LAG IDs are one-based, hardware is zero-based */
657462306a36Sopenharmony_ci	id = lag.id - 1;
657562306a36Sopenharmony_ci
657662306a36Sopenharmony_ci	/* Build the map of all ports to distribute flows destined for
657762306a36Sopenharmony_ci	 * this LAG. This can be either a local user port, or a DSA
657862306a36Sopenharmony_ci	 * port if the LAG port is on a remote chip.
657962306a36Sopenharmony_ci	 */
658062306a36Sopenharmony_ci	dsa_lag_foreach_port(dp, ds->dst, &lag)
658162306a36Sopenharmony_ci		map |= BIT(dsa_towards_port(ds, dp->ds->index, dp->index));
658262306a36Sopenharmony_ci
658362306a36Sopenharmony_ci	return mv88e6xxx_g2_trunk_mapping_write(chip, id, map);
658462306a36Sopenharmony_ci}
658562306a36Sopenharmony_ci
658662306a36Sopenharmony_cistatic const u8 mv88e6xxx_lag_mask_table[8][8] = {
658762306a36Sopenharmony_ci	/* Row number corresponds to the number of active members in a
658862306a36Sopenharmony_ci	 * LAG. Each column states which of the eight hash buckets are
658962306a36Sopenharmony_ci	 * mapped to the column:th port in the LAG.
659062306a36Sopenharmony_ci	 *
659162306a36Sopenharmony_ci	 * Example: In a LAG with three active ports, the second port
659262306a36Sopenharmony_ci	 * ([2][1]) would be selected for traffic mapped to buckets
659362306a36Sopenharmony_ci	 * 3,4,5 (0x38).
659462306a36Sopenharmony_ci	 */
659562306a36Sopenharmony_ci	{ 0xff,    0,    0,    0,    0,    0,    0,    0 },
659662306a36Sopenharmony_ci	{ 0x0f, 0xf0,    0,    0,    0,    0,    0,    0 },
659762306a36Sopenharmony_ci	{ 0x07, 0x38, 0xc0,    0,    0,    0,    0,    0 },
659862306a36Sopenharmony_ci	{ 0x03, 0x0c, 0x30, 0xc0,    0,    0,    0,    0 },
659962306a36Sopenharmony_ci	{ 0x03, 0x0c, 0x30, 0x40, 0x80,    0,    0,    0 },
660062306a36Sopenharmony_ci	{ 0x03, 0x0c, 0x10, 0x20, 0x40, 0x80,    0,    0 },
660162306a36Sopenharmony_ci	{ 0x03, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,    0 },
660262306a36Sopenharmony_ci	{ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 },
660362306a36Sopenharmony_ci};
660462306a36Sopenharmony_ci
660562306a36Sopenharmony_cistatic void mv88e6xxx_lag_set_port_mask(u16 *mask, int port,
660662306a36Sopenharmony_ci					int num_tx, int nth)
660762306a36Sopenharmony_ci{
660862306a36Sopenharmony_ci	u8 active = 0;
660962306a36Sopenharmony_ci	int i;
661062306a36Sopenharmony_ci
661162306a36Sopenharmony_ci	num_tx = num_tx <= 8 ? num_tx : 8;
661262306a36Sopenharmony_ci	if (nth < num_tx)
661362306a36Sopenharmony_ci		active = mv88e6xxx_lag_mask_table[num_tx - 1][nth];
661462306a36Sopenharmony_ci
661562306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
661662306a36Sopenharmony_ci		if (BIT(i) & active)
661762306a36Sopenharmony_ci			mask[i] |= BIT(port);
661862306a36Sopenharmony_ci	}
661962306a36Sopenharmony_ci}
662062306a36Sopenharmony_ci
662162306a36Sopenharmony_cistatic int mv88e6xxx_lag_sync_masks(struct dsa_switch *ds)
662262306a36Sopenharmony_ci{
662362306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
662462306a36Sopenharmony_ci	unsigned int id, num_tx;
662562306a36Sopenharmony_ci	struct dsa_port *dp;
662662306a36Sopenharmony_ci	struct dsa_lag *lag;
662762306a36Sopenharmony_ci	int i, err, nth;
662862306a36Sopenharmony_ci	u16 mask[8];
662962306a36Sopenharmony_ci	u16 ivec;
663062306a36Sopenharmony_ci
663162306a36Sopenharmony_ci	/* Assume no port is a member of any LAG. */
663262306a36Sopenharmony_ci	ivec = BIT(mv88e6xxx_num_ports(chip)) - 1;
663362306a36Sopenharmony_ci
663462306a36Sopenharmony_ci	/* Disable all masks for ports that _are_ members of a LAG. */
663562306a36Sopenharmony_ci	dsa_switch_for_each_port(dp, ds) {
663662306a36Sopenharmony_ci		if (!dp->lag)
663762306a36Sopenharmony_ci			continue;
663862306a36Sopenharmony_ci
663962306a36Sopenharmony_ci		ivec &= ~BIT(dp->index);
664062306a36Sopenharmony_ci	}
664162306a36Sopenharmony_ci
664262306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
664362306a36Sopenharmony_ci		mask[i] = ivec;
664462306a36Sopenharmony_ci
664562306a36Sopenharmony_ci	/* Enable the correct subset of masks for all LAG ports that
664662306a36Sopenharmony_ci	 * are in the Tx set.
664762306a36Sopenharmony_ci	 */
664862306a36Sopenharmony_ci	dsa_lags_foreach_id(id, ds->dst) {
664962306a36Sopenharmony_ci		lag = dsa_lag_by_id(ds->dst, id);
665062306a36Sopenharmony_ci		if (!lag)
665162306a36Sopenharmony_ci			continue;
665262306a36Sopenharmony_ci
665362306a36Sopenharmony_ci		num_tx = 0;
665462306a36Sopenharmony_ci		dsa_lag_foreach_port(dp, ds->dst, lag) {
665562306a36Sopenharmony_ci			if (dp->lag_tx_enabled)
665662306a36Sopenharmony_ci				num_tx++;
665762306a36Sopenharmony_ci		}
665862306a36Sopenharmony_ci
665962306a36Sopenharmony_ci		if (!num_tx)
666062306a36Sopenharmony_ci			continue;
666162306a36Sopenharmony_ci
666262306a36Sopenharmony_ci		nth = 0;
666362306a36Sopenharmony_ci		dsa_lag_foreach_port(dp, ds->dst, lag) {
666462306a36Sopenharmony_ci			if (!dp->lag_tx_enabled)
666562306a36Sopenharmony_ci				continue;
666662306a36Sopenharmony_ci
666762306a36Sopenharmony_ci			if (dp->ds == ds)
666862306a36Sopenharmony_ci				mv88e6xxx_lag_set_port_mask(mask, dp->index,
666962306a36Sopenharmony_ci							    num_tx, nth);
667062306a36Sopenharmony_ci
667162306a36Sopenharmony_ci			nth++;
667262306a36Sopenharmony_ci		}
667362306a36Sopenharmony_ci	}
667462306a36Sopenharmony_ci
667562306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
667662306a36Sopenharmony_ci		err = mv88e6xxx_g2_trunk_mask_write(chip, i, true, mask[i]);
667762306a36Sopenharmony_ci		if (err)
667862306a36Sopenharmony_ci			return err;
667962306a36Sopenharmony_ci	}
668062306a36Sopenharmony_ci
668162306a36Sopenharmony_ci	return 0;
668262306a36Sopenharmony_ci}
668362306a36Sopenharmony_ci
668462306a36Sopenharmony_cistatic int mv88e6xxx_lag_sync_masks_map(struct dsa_switch *ds,
668562306a36Sopenharmony_ci					struct dsa_lag lag)
668662306a36Sopenharmony_ci{
668762306a36Sopenharmony_ci	int err;
668862306a36Sopenharmony_ci
668962306a36Sopenharmony_ci	err = mv88e6xxx_lag_sync_masks(ds);
669062306a36Sopenharmony_ci
669162306a36Sopenharmony_ci	if (!err)
669262306a36Sopenharmony_ci		err = mv88e6xxx_lag_sync_map(ds, lag);
669362306a36Sopenharmony_ci
669462306a36Sopenharmony_ci	return err;
669562306a36Sopenharmony_ci}
669662306a36Sopenharmony_ci
669762306a36Sopenharmony_cistatic int mv88e6xxx_port_lag_change(struct dsa_switch *ds, int port)
669862306a36Sopenharmony_ci{
669962306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
670062306a36Sopenharmony_ci	int err;
670162306a36Sopenharmony_ci
670262306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
670362306a36Sopenharmony_ci	err = mv88e6xxx_lag_sync_masks(ds);
670462306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
670562306a36Sopenharmony_ci	return err;
670662306a36Sopenharmony_ci}
670762306a36Sopenharmony_ci
670862306a36Sopenharmony_cistatic int mv88e6xxx_port_lag_join(struct dsa_switch *ds, int port,
670962306a36Sopenharmony_ci				   struct dsa_lag lag,
671062306a36Sopenharmony_ci				   struct netdev_lag_upper_info *info,
671162306a36Sopenharmony_ci				   struct netlink_ext_ack *extack)
671262306a36Sopenharmony_ci{
671362306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
671462306a36Sopenharmony_ci	int err, id;
671562306a36Sopenharmony_ci
671662306a36Sopenharmony_ci	if (!mv88e6xxx_lag_can_offload(ds, lag, info, extack))
671762306a36Sopenharmony_ci		return -EOPNOTSUPP;
671862306a36Sopenharmony_ci
671962306a36Sopenharmony_ci	/* DSA LAG IDs are one-based */
672062306a36Sopenharmony_ci	id = lag.id - 1;
672162306a36Sopenharmony_ci
672262306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
672362306a36Sopenharmony_ci
672462306a36Sopenharmony_ci	err = mv88e6xxx_port_set_trunk(chip, port, true, id);
672562306a36Sopenharmony_ci	if (err)
672662306a36Sopenharmony_ci		goto err_unlock;
672762306a36Sopenharmony_ci
672862306a36Sopenharmony_ci	err = mv88e6xxx_lag_sync_masks_map(ds, lag);
672962306a36Sopenharmony_ci	if (err)
673062306a36Sopenharmony_ci		goto err_clear_trunk;
673162306a36Sopenharmony_ci
673262306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
673362306a36Sopenharmony_ci	return 0;
673462306a36Sopenharmony_ci
673562306a36Sopenharmony_cierr_clear_trunk:
673662306a36Sopenharmony_ci	mv88e6xxx_port_set_trunk(chip, port, false, 0);
673762306a36Sopenharmony_cierr_unlock:
673862306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
673962306a36Sopenharmony_ci	return err;
674062306a36Sopenharmony_ci}
674162306a36Sopenharmony_ci
674262306a36Sopenharmony_cistatic int mv88e6xxx_port_lag_leave(struct dsa_switch *ds, int port,
674362306a36Sopenharmony_ci				    struct dsa_lag lag)
674462306a36Sopenharmony_ci{
674562306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
674662306a36Sopenharmony_ci	int err_sync, err_trunk;
674762306a36Sopenharmony_ci
674862306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
674962306a36Sopenharmony_ci	err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag);
675062306a36Sopenharmony_ci	err_trunk = mv88e6xxx_port_set_trunk(chip, port, false, 0);
675162306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
675262306a36Sopenharmony_ci	return err_sync ? : err_trunk;
675362306a36Sopenharmony_ci}
675462306a36Sopenharmony_ci
675562306a36Sopenharmony_cistatic int mv88e6xxx_crosschip_lag_change(struct dsa_switch *ds, int sw_index,
675662306a36Sopenharmony_ci					  int port)
675762306a36Sopenharmony_ci{
675862306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
675962306a36Sopenharmony_ci	int err;
676062306a36Sopenharmony_ci
676162306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
676262306a36Sopenharmony_ci	err = mv88e6xxx_lag_sync_masks(ds);
676362306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
676462306a36Sopenharmony_ci	return err;
676562306a36Sopenharmony_ci}
676662306a36Sopenharmony_ci
676762306a36Sopenharmony_cistatic int mv88e6xxx_crosschip_lag_join(struct dsa_switch *ds, int sw_index,
676862306a36Sopenharmony_ci					int port, struct dsa_lag lag,
676962306a36Sopenharmony_ci					struct netdev_lag_upper_info *info,
677062306a36Sopenharmony_ci					struct netlink_ext_ack *extack)
677162306a36Sopenharmony_ci{
677262306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
677362306a36Sopenharmony_ci	int err;
677462306a36Sopenharmony_ci
677562306a36Sopenharmony_ci	if (!mv88e6xxx_lag_can_offload(ds, lag, info, extack))
677662306a36Sopenharmony_ci		return -EOPNOTSUPP;
677762306a36Sopenharmony_ci
677862306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
677962306a36Sopenharmony_ci
678062306a36Sopenharmony_ci	err = mv88e6xxx_lag_sync_masks_map(ds, lag);
678162306a36Sopenharmony_ci	if (err)
678262306a36Sopenharmony_ci		goto unlock;
678362306a36Sopenharmony_ci
678462306a36Sopenharmony_ci	err = mv88e6xxx_pvt_map(chip, sw_index, port);
678562306a36Sopenharmony_ci
678662306a36Sopenharmony_ciunlock:
678762306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
678862306a36Sopenharmony_ci	return err;
678962306a36Sopenharmony_ci}
679062306a36Sopenharmony_ci
679162306a36Sopenharmony_cistatic int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index,
679262306a36Sopenharmony_ci					 int port, struct dsa_lag lag)
679362306a36Sopenharmony_ci{
679462306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip = ds->priv;
679562306a36Sopenharmony_ci	int err_sync, err_pvt;
679662306a36Sopenharmony_ci
679762306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
679862306a36Sopenharmony_ci	err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag);
679962306a36Sopenharmony_ci	err_pvt = mv88e6xxx_pvt_map(chip, sw_index, port);
680062306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
680162306a36Sopenharmony_ci	return err_sync ? : err_pvt;
680262306a36Sopenharmony_ci}
680362306a36Sopenharmony_ci
680462306a36Sopenharmony_cistatic const struct dsa_switch_ops mv88e6xxx_switch_ops = {
680562306a36Sopenharmony_ci	.get_tag_protocol	= mv88e6xxx_get_tag_protocol,
680662306a36Sopenharmony_ci	.change_tag_protocol	= mv88e6xxx_change_tag_protocol,
680762306a36Sopenharmony_ci	.setup			= mv88e6xxx_setup,
680862306a36Sopenharmony_ci	.teardown		= mv88e6xxx_teardown,
680962306a36Sopenharmony_ci	.port_setup		= mv88e6xxx_port_setup,
681062306a36Sopenharmony_ci	.port_teardown		= mv88e6xxx_port_teardown,
681162306a36Sopenharmony_ci	.phylink_get_caps	= mv88e6xxx_get_caps,
681262306a36Sopenharmony_ci	.phylink_mac_select_pcs	= mv88e6xxx_mac_select_pcs,
681362306a36Sopenharmony_ci	.phylink_mac_prepare	= mv88e6xxx_mac_prepare,
681462306a36Sopenharmony_ci	.phylink_mac_config	= mv88e6xxx_mac_config,
681562306a36Sopenharmony_ci	.phylink_mac_finish	= mv88e6xxx_mac_finish,
681662306a36Sopenharmony_ci	.phylink_mac_link_down	= mv88e6xxx_mac_link_down,
681762306a36Sopenharmony_ci	.phylink_mac_link_up	= mv88e6xxx_mac_link_up,
681862306a36Sopenharmony_ci	.get_strings		= mv88e6xxx_get_strings,
681962306a36Sopenharmony_ci	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
682062306a36Sopenharmony_ci	.get_sset_count		= mv88e6xxx_get_sset_count,
682162306a36Sopenharmony_ci	.port_max_mtu		= mv88e6xxx_get_max_mtu,
682262306a36Sopenharmony_ci	.port_change_mtu	= mv88e6xxx_change_mtu,
682362306a36Sopenharmony_ci	.get_mac_eee		= mv88e6xxx_get_mac_eee,
682462306a36Sopenharmony_ci	.set_mac_eee		= mv88e6xxx_set_mac_eee,
682562306a36Sopenharmony_ci	.get_eeprom_len		= mv88e6xxx_get_eeprom_len,
682662306a36Sopenharmony_ci	.get_eeprom		= mv88e6xxx_get_eeprom,
682762306a36Sopenharmony_ci	.set_eeprom		= mv88e6xxx_set_eeprom,
682862306a36Sopenharmony_ci	.get_regs_len		= mv88e6xxx_get_regs_len,
682962306a36Sopenharmony_ci	.get_regs		= mv88e6xxx_get_regs,
683062306a36Sopenharmony_ci	.get_rxnfc		= mv88e6xxx_get_rxnfc,
683162306a36Sopenharmony_ci	.set_rxnfc		= mv88e6xxx_set_rxnfc,
683262306a36Sopenharmony_ci	.set_ageing_time	= mv88e6xxx_set_ageing_time,
683362306a36Sopenharmony_ci	.port_bridge_join	= mv88e6xxx_port_bridge_join,
683462306a36Sopenharmony_ci	.port_bridge_leave	= mv88e6xxx_port_bridge_leave,
683562306a36Sopenharmony_ci	.port_pre_bridge_flags	= mv88e6xxx_port_pre_bridge_flags,
683662306a36Sopenharmony_ci	.port_bridge_flags	= mv88e6xxx_port_bridge_flags,
683762306a36Sopenharmony_ci	.port_stp_state_set	= mv88e6xxx_port_stp_state_set,
683862306a36Sopenharmony_ci	.port_mst_state_set	= mv88e6xxx_port_mst_state_set,
683962306a36Sopenharmony_ci	.port_fast_age		= mv88e6xxx_port_fast_age,
684062306a36Sopenharmony_ci	.port_vlan_fast_age	= mv88e6xxx_port_vlan_fast_age,
684162306a36Sopenharmony_ci	.port_vlan_filtering	= mv88e6xxx_port_vlan_filtering,
684262306a36Sopenharmony_ci	.port_vlan_add		= mv88e6xxx_port_vlan_add,
684362306a36Sopenharmony_ci	.port_vlan_del		= mv88e6xxx_port_vlan_del,
684462306a36Sopenharmony_ci	.vlan_msti_set		= mv88e6xxx_vlan_msti_set,
684562306a36Sopenharmony_ci	.port_fdb_add		= mv88e6xxx_port_fdb_add,
684662306a36Sopenharmony_ci	.port_fdb_del		= mv88e6xxx_port_fdb_del,
684762306a36Sopenharmony_ci	.port_fdb_dump		= mv88e6xxx_port_fdb_dump,
684862306a36Sopenharmony_ci	.port_mdb_add		= mv88e6xxx_port_mdb_add,
684962306a36Sopenharmony_ci	.port_mdb_del		= mv88e6xxx_port_mdb_del,
685062306a36Sopenharmony_ci	.port_mirror_add	= mv88e6xxx_port_mirror_add,
685162306a36Sopenharmony_ci	.port_mirror_del	= mv88e6xxx_port_mirror_del,
685262306a36Sopenharmony_ci	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
685362306a36Sopenharmony_ci	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
685462306a36Sopenharmony_ci	.port_hwtstamp_set	= mv88e6xxx_port_hwtstamp_set,
685562306a36Sopenharmony_ci	.port_hwtstamp_get	= mv88e6xxx_port_hwtstamp_get,
685662306a36Sopenharmony_ci	.port_txtstamp		= mv88e6xxx_port_txtstamp,
685762306a36Sopenharmony_ci	.port_rxtstamp		= mv88e6xxx_port_rxtstamp,
685862306a36Sopenharmony_ci	.get_ts_info		= mv88e6xxx_get_ts_info,
685962306a36Sopenharmony_ci	.devlink_param_get	= mv88e6xxx_devlink_param_get,
686062306a36Sopenharmony_ci	.devlink_param_set	= mv88e6xxx_devlink_param_set,
686162306a36Sopenharmony_ci	.devlink_info_get	= mv88e6xxx_devlink_info_get,
686262306a36Sopenharmony_ci	.port_lag_change	= mv88e6xxx_port_lag_change,
686362306a36Sopenharmony_ci	.port_lag_join		= mv88e6xxx_port_lag_join,
686462306a36Sopenharmony_ci	.port_lag_leave		= mv88e6xxx_port_lag_leave,
686562306a36Sopenharmony_ci	.crosschip_lag_change	= mv88e6xxx_crosschip_lag_change,
686662306a36Sopenharmony_ci	.crosschip_lag_join	= mv88e6xxx_crosschip_lag_join,
686762306a36Sopenharmony_ci	.crosschip_lag_leave	= mv88e6xxx_crosschip_lag_leave,
686862306a36Sopenharmony_ci};
686962306a36Sopenharmony_ci
687062306a36Sopenharmony_cistatic int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
687162306a36Sopenharmony_ci{
687262306a36Sopenharmony_ci	struct device *dev = chip->dev;
687362306a36Sopenharmony_ci	struct dsa_switch *ds;
687462306a36Sopenharmony_ci
687562306a36Sopenharmony_ci	ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
687662306a36Sopenharmony_ci	if (!ds)
687762306a36Sopenharmony_ci		return -ENOMEM;
687862306a36Sopenharmony_ci
687962306a36Sopenharmony_ci	ds->dev = dev;
688062306a36Sopenharmony_ci	ds->num_ports = mv88e6xxx_num_ports(chip);
688162306a36Sopenharmony_ci	ds->priv = chip;
688262306a36Sopenharmony_ci	ds->dev = dev;
688362306a36Sopenharmony_ci	ds->ops = &mv88e6xxx_switch_ops;
688462306a36Sopenharmony_ci	ds->ageing_time_min = chip->info->age_time_coeff;
688562306a36Sopenharmony_ci	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
688662306a36Sopenharmony_ci
688762306a36Sopenharmony_ci	/* Some chips support up to 32, but that requires enabling the
688862306a36Sopenharmony_ci	 * 5-bit port mode, which we do not support. 640k^W16 ought to
688962306a36Sopenharmony_ci	 * be enough for anyone.
689062306a36Sopenharmony_ci	 */
689162306a36Sopenharmony_ci	ds->num_lag_ids = mv88e6xxx_has_lag(chip) ? 16 : 0;
689262306a36Sopenharmony_ci
689362306a36Sopenharmony_ci	dev_set_drvdata(dev, ds);
689462306a36Sopenharmony_ci
689562306a36Sopenharmony_ci	return dsa_register_switch(ds);
689662306a36Sopenharmony_ci}
689762306a36Sopenharmony_ci
689862306a36Sopenharmony_cistatic void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
689962306a36Sopenharmony_ci{
690062306a36Sopenharmony_ci	dsa_unregister_switch(chip->ds);
690162306a36Sopenharmony_ci}
690262306a36Sopenharmony_ci
690362306a36Sopenharmony_cistatic const void *pdata_device_get_match_data(struct device *dev)
690462306a36Sopenharmony_ci{
690562306a36Sopenharmony_ci	const struct of_device_id *matches = dev->driver->of_match_table;
690662306a36Sopenharmony_ci	const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data;
690762306a36Sopenharmony_ci
690862306a36Sopenharmony_ci	for (; matches->name[0] || matches->type[0] || matches->compatible[0];
690962306a36Sopenharmony_ci	     matches++) {
691062306a36Sopenharmony_ci		if (!strcmp(pdata->compatible, matches->compatible))
691162306a36Sopenharmony_ci			return matches->data;
691262306a36Sopenharmony_ci	}
691362306a36Sopenharmony_ci	return NULL;
691462306a36Sopenharmony_ci}
691562306a36Sopenharmony_ci
691662306a36Sopenharmony_ci/* There is no suspend to RAM support at DSA level yet, the switch configuration
691762306a36Sopenharmony_ci * would be lost after a power cycle so prevent it to be suspended.
691862306a36Sopenharmony_ci */
691962306a36Sopenharmony_cistatic int __maybe_unused mv88e6xxx_suspend(struct device *dev)
692062306a36Sopenharmony_ci{
692162306a36Sopenharmony_ci	return -EOPNOTSUPP;
692262306a36Sopenharmony_ci}
692362306a36Sopenharmony_ci
692462306a36Sopenharmony_cistatic int __maybe_unused mv88e6xxx_resume(struct device *dev)
692562306a36Sopenharmony_ci{
692662306a36Sopenharmony_ci	return 0;
692762306a36Sopenharmony_ci}
692862306a36Sopenharmony_ci
692962306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume);
693062306a36Sopenharmony_ci
693162306a36Sopenharmony_cistatic int mv88e6xxx_probe(struct mdio_device *mdiodev)
693262306a36Sopenharmony_ci{
693362306a36Sopenharmony_ci	struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data;
693462306a36Sopenharmony_ci	const struct mv88e6xxx_info *compat_info = NULL;
693562306a36Sopenharmony_ci	struct device *dev = &mdiodev->dev;
693662306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
693762306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip;
693862306a36Sopenharmony_ci	int port;
693962306a36Sopenharmony_ci	int err;
694062306a36Sopenharmony_ci
694162306a36Sopenharmony_ci	if (!np && !pdata)
694262306a36Sopenharmony_ci		return -EINVAL;
694362306a36Sopenharmony_ci
694462306a36Sopenharmony_ci	if (np)
694562306a36Sopenharmony_ci		compat_info = of_device_get_match_data(dev);
694662306a36Sopenharmony_ci
694762306a36Sopenharmony_ci	if (pdata) {
694862306a36Sopenharmony_ci		compat_info = pdata_device_get_match_data(dev);
694962306a36Sopenharmony_ci
695062306a36Sopenharmony_ci		if (!pdata->netdev)
695162306a36Sopenharmony_ci			return -EINVAL;
695262306a36Sopenharmony_ci
695362306a36Sopenharmony_ci		for (port = 0; port < DSA_MAX_PORTS; port++) {
695462306a36Sopenharmony_ci			if (!(pdata->enabled_ports & (1 << port)))
695562306a36Sopenharmony_ci				continue;
695662306a36Sopenharmony_ci			if (strcmp(pdata->cd.port_names[port], "cpu"))
695762306a36Sopenharmony_ci				continue;
695862306a36Sopenharmony_ci			pdata->cd.netdev[port] = &pdata->netdev->dev;
695962306a36Sopenharmony_ci			break;
696062306a36Sopenharmony_ci		}
696162306a36Sopenharmony_ci	}
696262306a36Sopenharmony_ci
696362306a36Sopenharmony_ci	if (!compat_info)
696462306a36Sopenharmony_ci		return -EINVAL;
696562306a36Sopenharmony_ci
696662306a36Sopenharmony_ci	chip = mv88e6xxx_alloc_chip(dev);
696762306a36Sopenharmony_ci	if (!chip) {
696862306a36Sopenharmony_ci		err = -ENOMEM;
696962306a36Sopenharmony_ci		goto out;
697062306a36Sopenharmony_ci	}
697162306a36Sopenharmony_ci
697262306a36Sopenharmony_ci	chip->info = compat_info;
697362306a36Sopenharmony_ci
697462306a36Sopenharmony_ci	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
697562306a36Sopenharmony_ci	if (IS_ERR(chip->reset)) {
697662306a36Sopenharmony_ci		err = PTR_ERR(chip->reset);
697762306a36Sopenharmony_ci		goto out;
697862306a36Sopenharmony_ci	}
697962306a36Sopenharmony_ci	if (chip->reset)
698062306a36Sopenharmony_ci		usleep_range(10000, 20000);
698162306a36Sopenharmony_ci
698262306a36Sopenharmony_ci	/* Detect if the device is configured in single chip addressing mode,
698362306a36Sopenharmony_ci	 * otherwise continue with address specific smi init/detection.
698462306a36Sopenharmony_ci	 */
698562306a36Sopenharmony_ci	err = mv88e6xxx_single_chip_detect(chip, mdiodev);
698662306a36Sopenharmony_ci	if (err) {
698762306a36Sopenharmony_ci		err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
698862306a36Sopenharmony_ci		if (err)
698962306a36Sopenharmony_ci			goto out;
699062306a36Sopenharmony_ci
699162306a36Sopenharmony_ci		err = mv88e6xxx_detect(chip);
699262306a36Sopenharmony_ci		if (err)
699362306a36Sopenharmony_ci			goto out;
699462306a36Sopenharmony_ci	}
699562306a36Sopenharmony_ci
699662306a36Sopenharmony_ci	if (chip->info->edsa_support == MV88E6XXX_EDSA_SUPPORTED)
699762306a36Sopenharmony_ci		chip->tag_protocol = DSA_TAG_PROTO_EDSA;
699862306a36Sopenharmony_ci	else
699962306a36Sopenharmony_ci		chip->tag_protocol = DSA_TAG_PROTO_DSA;
700062306a36Sopenharmony_ci
700162306a36Sopenharmony_ci	mv88e6xxx_phy_init(chip);
700262306a36Sopenharmony_ci
700362306a36Sopenharmony_ci	if (chip->info->ops->get_eeprom) {
700462306a36Sopenharmony_ci		if (np)
700562306a36Sopenharmony_ci			of_property_read_u32(np, "eeprom-length",
700662306a36Sopenharmony_ci					     &chip->eeprom_len);
700762306a36Sopenharmony_ci		else
700862306a36Sopenharmony_ci			chip->eeprom_len = pdata->eeprom_len;
700962306a36Sopenharmony_ci	}
701062306a36Sopenharmony_ci
701162306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
701262306a36Sopenharmony_ci	err = mv88e6xxx_switch_reset(chip);
701362306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
701462306a36Sopenharmony_ci	if (err)
701562306a36Sopenharmony_ci		goto out;
701662306a36Sopenharmony_ci
701762306a36Sopenharmony_ci	if (np) {
701862306a36Sopenharmony_ci		chip->irq = of_irq_get(np, 0);
701962306a36Sopenharmony_ci		if (chip->irq == -EPROBE_DEFER) {
702062306a36Sopenharmony_ci			err = chip->irq;
702162306a36Sopenharmony_ci			goto out;
702262306a36Sopenharmony_ci		}
702362306a36Sopenharmony_ci	}
702462306a36Sopenharmony_ci
702562306a36Sopenharmony_ci	if (pdata)
702662306a36Sopenharmony_ci		chip->irq = pdata->irq;
702762306a36Sopenharmony_ci
702862306a36Sopenharmony_ci	/* Has to be performed before the MDIO bus is created, because
702962306a36Sopenharmony_ci	 * the PHYs will link their interrupts to these interrupt
703062306a36Sopenharmony_ci	 * controllers
703162306a36Sopenharmony_ci	 */
703262306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
703362306a36Sopenharmony_ci	if (chip->irq > 0)
703462306a36Sopenharmony_ci		err = mv88e6xxx_g1_irq_setup(chip);
703562306a36Sopenharmony_ci	else
703662306a36Sopenharmony_ci		err = mv88e6xxx_irq_poll_setup(chip);
703762306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
703862306a36Sopenharmony_ci
703962306a36Sopenharmony_ci	if (err)
704062306a36Sopenharmony_ci		goto out;
704162306a36Sopenharmony_ci
704262306a36Sopenharmony_ci	if (chip->info->g2_irqs > 0) {
704362306a36Sopenharmony_ci		err = mv88e6xxx_g2_irq_setup(chip);
704462306a36Sopenharmony_ci		if (err)
704562306a36Sopenharmony_ci			goto out_g1_irq;
704662306a36Sopenharmony_ci	}
704762306a36Sopenharmony_ci
704862306a36Sopenharmony_ci	err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
704962306a36Sopenharmony_ci	if (err)
705062306a36Sopenharmony_ci		goto out_g2_irq;
705162306a36Sopenharmony_ci
705262306a36Sopenharmony_ci	err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
705362306a36Sopenharmony_ci	if (err)
705462306a36Sopenharmony_ci		goto out_g1_atu_prob_irq;
705562306a36Sopenharmony_ci
705662306a36Sopenharmony_ci	err = mv88e6xxx_register_switch(chip);
705762306a36Sopenharmony_ci	if (err)
705862306a36Sopenharmony_ci		goto out_g1_vtu_prob_irq;
705962306a36Sopenharmony_ci
706062306a36Sopenharmony_ci	return 0;
706162306a36Sopenharmony_ci
706262306a36Sopenharmony_ciout_g1_vtu_prob_irq:
706362306a36Sopenharmony_ci	mv88e6xxx_g1_vtu_prob_irq_free(chip);
706462306a36Sopenharmony_ciout_g1_atu_prob_irq:
706562306a36Sopenharmony_ci	mv88e6xxx_g1_atu_prob_irq_free(chip);
706662306a36Sopenharmony_ciout_g2_irq:
706762306a36Sopenharmony_ci	if (chip->info->g2_irqs > 0)
706862306a36Sopenharmony_ci		mv88e6xxx_g2_irq_free(chip);
706962306a36Sopenharmony_ciout_g1_irq:
707062306a36Sopenharmony_ci	if (chip->irq > 0)
707162306a36Sopenharmony_ci		mv88e6xxx_g1_irq_free(chip);
707262306a36Sopenharmony_ci	else
707362306a36Sopenharmony_ci		mv88e6xxx_irq_poll_free(chip);
707462306a36Sopenharmony_ciout:
707562306a36Sopenharmony_ci	if (pdata)
707662306a36Sopenharmony_ci		dev_put(pdata->netdev);
707762306a36Sopenharmony_ci
707862306a36Sopenharmony_ci	return err;
707962306a36Sopenharmony_ci}
708062306a36Sopenharmony_ci
708162306a36Sopenharmony_cistatic void mv88e6xxx_remove(struct mdio_device *mdiodev)
708262306a36Sopenharmony_ci{
708362306a36Sopenharmony_ci	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
708462306a36Sopenharmony_ci	struct mv88e6xxx_chip *chip;
708562306a36Sopenharmony_ci
708662306a36Sopenharmony_ci	if (!ds)
708762306a36Sopenharmony_ci		return;
708862306a36Sopenharmony_ci
708962306a36Sopenharmony_ci	chip = ds->priv;
709062306a36Sopenharmony_ci
709162306a36Sopenharmony_ci	if (chip->info->ptp_support) {
709262306a36Sopenharmony_ci		mv88e6xxx_hwtstamp_free(chip);
709362306a36Sopenharmony_ci		mv88e6xxx_ptp_free(chip);
709462306a36Sopenharmony_ci	}
709562306a36Sopenharmony_ci
709662306a36Sopenharmony_ci	mv88e6xxx_phy_destroy(chip);
709762306a36Sopenharmony_ci	mv88e6xxx_unregister_switch(chip);
709862306a36Sopenharmony_ci
709962306a36Sopenharmony_ci	mv88e6xxx_g1_vtu_prob_irq_free(chip);
710062306a36Sopenharmony_ci	mv88e6xxx_g1_atu_prob_irq_free(chip);
710162306a36Sopenharmony_ci
710262306a36Sopenharmony_ci	if (chip->info->g2_irqs > 0)
710362306a36Sopenharmony_ci		mv88e6xxx_g2_irq_free(chip);
710462306a36Sopenharmony_ci
710562306a36Sopenharmony_ci	if (chip->irq > 0)
710662306a36Sopenharmony_ci		mv88e6xxx_g1_irq_free(chip);
710762306a36Sopenharmony_ci	else
710862306a36Sopenharmony_ci		mv88e6xxx_irq_poll_free(chip);
710962306a36Sopenharmony_ci}
711062306a36Sopenharmony_ci
711162306a36Sopenharmony_cistatic void mv88e6xxx_shutdown(struct mdio_device *mdiodev)
711262306a36Sopenharmony_ci{
711362306a36Sopenharmony_ci	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
711462306a36Sopenharmony_ci
711562306a36Sopenharmony_ci	if (!ds)
711662306a36Sopenharmony_ci		return;
711762306a36Sopenharmony_ci
711862306a36Sopenharmony_ci	dsa_switch_shutdown(ds);
711962306a36Sopenharmony_ci
712062306a36Sopenharmony_ci	dev_set_drvdata(&mdiodev->dev, NULL);
712162306a36Sopenharmony_ci}
712262306a36Sopenharmony_ci
712362306a36Sopenharmony_cistatic const struct of_device_id mv88e6xxx_of_match[] = {
712462306a36Sopenharmony_ci	{
712562306a36Sopenharmony_ci		.compatible = "marvell,mv88e6085",
712662306a36Sopenharmony_ci		.data = &mv88e6xxx_table[MV88E6085],
712762306a36Sopenharmony_ci	},
712862306a36Sopenharmony_ci	{
712962306a36Sopenharmony_ci		.compatible = "marvell,mv88e6190",
713062306a36Sopenharmony_ci		.data = &mv88e6xxx_table[MV88E6190],
713162306a36Sopenharmony_ci	},
713262306a36Sopenharmony_ci	{
713362306a36Sopenharmony_ci		.compatible = "marvell,mv88e6250",
713462306a36Sopenharmony_ci		.data = &mv88e6xxx_table[MV88E6250],
713562306a36Sopenharmony_ci	},
713662306a36Sopenharmony_ci	{ /* sentinel */ },
713762306a36Sopenharmony_ci};
713862306a36Sopenharmony_ci
713962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);
714062306a36Sopenharmony_ci
714162306a36Sopenharmony_cistatic struct mdio_driver mv88e6xxx_driver = {
714262306a36Sopenharmony_ci	.probe	= mv88e6xxx_probe,
714362306a36Sopenharmony_ci	.remove = mv88e6xxx_remove,
714462306a36Sopenharmony_ci	.shutdown = mv88e6xxx_shutdown,
714562306a36Sopenharmony_ci	.mdiodrv.driver = {
714662306a36Sopenharmony_ci		.name = "mv88e6085",
714762306a36Sopenharmony_ci		.of_match_table = mv88e6xxx_of_match,
714862306a36Sopenharmony_ci		.pm = &mv88e6xxx_pm_ops,
714962306a36Sopenharmony_ci	},
715062306a36Sopenharmony_ci};
715162306a36Sopenharmony_ci
715262306a36Sopenharmony_cimdio_module_driver(mv88e6xxx_driver);
715362306a36Sopenharmony_ci
715462306a36Sopenharmony_ciMODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
715562306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
715662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
7157