12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2fad09c73SVivien Didelot /* 3fad09c73SVivien Didelot * Marvell 88e6xxx Ethernet switch single-chip support 4fad09c73SVivien Didelot * 5fad09c73SVivien Didelot * Copyright (c) 2008 Marvell Semiconductor 6fad09c73SVivien Didelot * 7fad09c73SVivien Didelot * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch> 8fad09c73SVivien Didelot * 94333d619SVivien Didelot * Copyright (c) 2016-2017 Savoir-faire Linux Inc. 104333d619SVivien Didelot * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 11fad09c73SVivien Didelot */ 12fad09c73SVivien Didelot 1319fb7f69SVivien Didelot #include <linux/bitfield.h> 14fad09c73SVivien Didelot #include <linux/delay.h> 15fad09c73SVivien Didelot #include <linux/etherdevice.h> 16fad09c73SVivien Didelot #include <linux/ethtool.h> 17fad09c73SVivien Didelot #include <linux/if_bridge.h> 18dc30c35bSAndrew Lunn #include <linux/interrupt.h> 19dc30c35bSAndrew Lunn #include <linux/irq.h> 20dc30c35bSAndrew Lunn #include <linux/irqdomain.h> 21fad09c73SVivien Didelot #include <linux/jiffies.h> 22fad09c73SVivien Didelot #include <linux/list.h> 23fad09c73SVivien Didelot #include <linux/mdio.h> 24fad09c73SVivien Didelot #include <linux/module.h> 25fad09c73SVivien Didelot #include <linux/of_device.h> 26dc30c35bSAndrew Lunn #include <linux/of_irq.h> 27fad09c73SVivien Didelot #include <linux/of_mdio.h> 28877b7cb0SAndrew Lunn #include <linux/platform_data/mv88e6xxx.h> 29fad09c73SVivien Didelot #include <linux/netdevice.h> 30fad09c73SVivien Didelot #include <linux/gpio/consumer.h> 31c9a2356fSRussell King #include <linux/phylink.h> 32fad09c73SVivien Didelot #include <net/dsa.h> 33ec561276SVivien Didelot 344d5f2ba7SVivien Didelot #include "chip.h" 35a935c052SVivien Didelot #include "global1.h" 36ec561276SVivien Didelot #include "global2.h" 37c6fe0ad2SBrandon Streiff #include "hwtstamp.h" 3810fa5bfcSAndrew Lunn #include "phy.h" 3918abed21SVivien Didelot #include "port.h" 402fa8d3afSBrandon Streiff #include "ptp.h" 416d91782fSAndrew Lunn #include "serdes.h" 42e7ba0fadSVivien Didelot #include "smi.h" 43fad09c73SVivien Didelot 44fad09c73SVivien Didelot static void assert_reg_lock(struct mv88e6xxx_chip *chip) 45fad09c73SVivien Didelot { 46fad09c73SVivien Didelot if (unlikely(!mutex_is_locked(&chip->reg_lock))) { 47fad09c73SVivien Didelot dev_err(chip->dev, "Switch registers lock not held!\n"); 48fad09c73SVivien Didelot dump_stack(); 49fad09c73SVivien Didelot } 50fad09c73SVivien Didelot } 51fad09c73SVivien Didelot 52ec561276SVivien Didelot int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val) 53fad09c73SVivien Didelot { 54fad09c73SVivien Didelot int err; 55fad09c73SVivien Didelot 56fad09c73SVivien Didelot assert_reg_lock(chip); 57fad09c73SVivien Didelot 58fad09c73SVivien Didelot err = mv88e6xxx_smi_read(chip, addr, reg, val); 59fad09c73SVivien Didelot if (err) 60fad09c73SVivien Didelot return err; 61fad09c73SVivien Didelot 62fad09c73SVivien Didelot dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 63fad09c73SVivien Didelot addr, reg, *val); 64fad09c73SVivien Didelot 65fad09c73SVivien Didelot return 0; 66fad09c73SVivien Didelot } 67fad09c73SVivien Didelot 68ec561276SVivien Didelot int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val) 69fad09c73SVivien Didelot { 70fad09c73SVivien Didelot int err; 71fad09c73SVivien Didelot 72fad09c73SVivien Didelot assert_reg_lock(chip); 73fad09c73SVivien Didelot 74fad09c73SVivien Didelot err = mv88e6xxx_smi_write(chip, addr, reg, val); 75fad09c73SVivien Didelot if (err) 76fad09c73SVivien Didelot return err; 77fad09c73SVivien Didelot 78fad09c73SVivien Didelot dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 79fad09c73SVivien Didelot addr, reg, val); 80fad09c73SVivien Didelot 81fad09c73SVivien Didelot return 0; 82fad09c73SVivien Didelot } 83fad09c73SVivien Didelot 84683f2244SVivien Didelot int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg, 85683f2244SVivien Didelot u16 mask, u16 val) 86683f2244SVivien Didelot { 87683f2244SVivien Didelot u16 data; 88683f2244SVivien Didelot int err; 89683f2244SVivien Didelot int i; 90683f2244SVivien Didelot 91683f2244SVivien Didelot /* There's no bus specific operation to wait for a mask */ 92683f2244SVivien Didelot for (i = 0; i < 16; i++) { 93683f2244SVivien Didelot err = mv88e6xxx_read(chip, addr, reg, &data); 94683f2244SVivien Didelot if (err) 95683f2244SVivien Didelot return err; 96683f2244SVivien Didelot 97683f2244SVivien Didelot if ((data & mask) == val) 98683f2244SVivien Didelot return 0; 99683f2244SVivien Didelot 100683f2244SVivien Didelot usleep_range(1000, 2000); 101683f2244SVivien Didelot } 102683f2244SVivien Didelot 103683f2244SVivien Didelot dev_err(chip->dev, "Timeout while waiting for switch\n"); 104683f2244SVivien Didelot return -ETIMEDOUT; 105683f2244SVivien Didelot } 106683f2244SVivien Didelot 10719fb7f69SVivien Didelot int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg, 10819fb7f69SVivien Didelot int bit, int val) 10919fb7f69SVivien Didelot { 11019fb7f69SVivien Didelot return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit), 11119fb7f69SVivien Didelot val ? BIT(bit) : 0x0000); 11219fb7f69SVivien Didelot } 11319fb7f69SVivien Didelot 11410fa5bfcSAndrew Lunn struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) 115a3c53be5SAndrew Lunn { 116a3c53be5SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 117a3c53be5SAndrew Lunn 118a3c53be5SAndrew Lunn mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus, 119a3c53be5SAndrew Lunn list); 120a3c53be5SAndrew Lunn if (!mdio_bus) 121a3c53be5SAndrew Lunn return NULL; 122a3c53be5SAndrew Lunn 123a3c53be5SAndrew Lunn return mdio_bus->bus; 124a3c53be5SAndrew Lunn } 125a3c53be5SAndrew Lunn 126dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_mask(struct irq_data *d) 127dc30c35bSAndrew Lunn { 128dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 129dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 130dc30c35bSAndrew Lunn 131dc30c35bSAndrew Lunn chip->g1_irq.masked |= (1 << n); 132dc30c35bSAndrew Lunn } 133dc30c35bSAndrew Lunn 134dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_unmask(struct irq_data *d) 135dc30c35bSAndrew Lunn { 136dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 137dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 138dc30c35bSAndrew Lunn 139dc30c35bSAndrew Lunn chip->g1_irq.masked &= ~(1 << n); 140dc30c35bSAndrew Lunn } 141dc30c35bSAndrew Lunn 142294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip) 143dc30c35bSAndrew Lunn { 144dc30c35bSAndrew Lunn unsigned int nhandled = 0; 145dc30c35bSAndrew Lunn unsigned int sub_irq; 146dc30c35bSAndrew Lunn unsigned int n; 147dc30c35bSAndrew Lunn u16 reg; 1487c0db24cSJohn David Anglin u16 ctl1; 149dc30c35bSAndrew Lunn int err; 150dc30c35bSAndrew Lunn 151c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 15282466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 153c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 154dc30c35bSAndrew Lunn 155dc30c35bSAndrew Lunn if (err) 156dc30c35bSAndrew Lunn goto out; 157dc30c35bSAndrew Lunn 1587c0db24cSJohn David Anglin do { 159dc30c35bSAndrew Lunn for (n = 0; n < chip->g1_irq.nirqs; ++n) { 160dc30c35bSAndrew Lunn if (reg & (1 << n)) { 1617c0db24cSJohn David Anglin sub_irq = irq_find_mapping(chip->g1_irq.domain, 1627c0db24cSJohn David Anglin n); 163dc30c35bSAndrew Lunn handle_nested_irq(sub_irq); 164dc30c35bSAndrew Lunn ++nhandled; 165dc30c35bSAndrew Lunn } 166dc30c35bSAndrew Lunn } 1677c0db24cSJohn David Anglin 168c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1697c0db24cSJohn David Anglin err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1); 1707c0db24cSJohn David Anglin if (err) 1717c0db24cSJohn David Anglin goto unlock; 1727c0db24cSJohn David Anglin err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 1737c0db24cSJohn David Anglin unlock: 174c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1757c0db24cSJohn David Anglin if (err) 1767c0db24cSJohn David Anglin goto out; 1777c0db24cSJohn David Anglin ctl1 &= GENMASK(chip->g1_irq.nirqs, 0); 1787c0db24cSJohn David Anglin } while (reg & ctl1); 1797c0db24cSJohn David Anglin 180dc30c35bSAndrew Lunn out: 181dc30c35bSAndrew Lunn return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); 182dc30c35bSAndrew Lunn } 183dc30c35bSAndrew Lunn 184294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id) 185294d711eSAndrew Lunn { 186294d711eSAndrew Lunn struct mv88e6xxx_chip *chip = dev_id; 187294d711eSAndrew Lunn 188294d711eSAndrew Lunn return mv88e6xxx_g1_irq_thread_work(chip); 189294d711eSAndrew Lunn } 190294d711eSAndrew Lunn 191dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d) 192dc30c35bSAndrew Lunn { 193dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 194dc30c35bSAndrew Lunn 195c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 196dc30c35bSAndrew Lunn } 197dc30c35bSAndrew Lunn 198dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d) 199dc30c35bSAndrew Lunn { 200dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 201dc30c35bSAndrew Lunn u16 mask = GENMASK(chip->g1_irq.nirqs, 0); 202dc30c35bSAndrew Lunn u16 reg; 203dc30c35bSAndrew Lunn int err; 204dc30c35bSAndrew Lunn 205d77f4321SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, ®); 206dc30c35bSAndrew Lunn if (err) 207dc30c35bSAndrew Lunn goto out; 208dc30c35bSAndrew Lunn 209dc30c35bSAndrew Lunn reg &= ~mask; 210dc30c35bSAndrew Lunn reg |= (~chip->g1_irq.masked & mask); 211dc30c35bSAndrew Lunn 212d77f4321SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg); 213dc30c35bSAndrew Lunn if (err) 214dc30c35bSAndrew Lunn goto out; 215dc30c35bSAndrew Lunn 216dc30c35bSAndrew Lunn out: 217c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 218dc30c35bSAndrew Lunn } 219dc30c35bSAndrew Lunn 2206eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g1_irq_chip = { 221dc30c35bSAndrew Lunn .name = "mv88e6xxx-g1", 222dc30c35bSAndrew Lunn .irq_mask = mv88e6xxx_g1_irq_mask, 223dc30c35bSAndrew Lunn .irq_unmask = mv88e6xxx_g1_irq_unmask, 224dc30c35bSAndrew Lunn .irq_bus_lock = mv88e6xxx_g1_irq_bus_lock, 225dc30c35bSAndrew Lunn .irq_bus_sync_unlock = mv88e6xxx_g1_irq_bus_sync_unlock, 226dc30c35bSAndrew Lunn }; 227dc30c35bSAndrew Lunn 228dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d, 229dc30c35bSAndrew Lunn unsigned int irq, 230dc30c35bSAndrew Lunn irq_hw_number_t hwirq) 231dc30c35bSAndrew Lunn { 232dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = d->host_data; 233dc30c35bSAndrew Lunn 234dc30c35bSAndrew Lunn irq_set_chip_data(irq, d->host_data); 235dc30c35bSAndrew Lunn irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq); 236dc30c35bSAndrew Lunn irq_set_noprobe(irq); 237dc30c35bSAndrew Lunn 238dc30c35bSAndrew Lunn return 0; 239dc30c35bSAndrew Lunn } 240dc30c35bSAndrew Lunn 241dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = { 242dc30c35bSAndrew Lunn .map = mv88e6xxx_g1_irq_domain_map, 243dc30c35bSAndrew Lunn .xlate = irq_domain_xlate_twocell, 244dc30c35bSAndrew Lunn }; 245dc30c35bSAndrew Lunn 2463d82475aSUwe Kleine-König /* To be called with reg_lock held */ 247294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip) 248dc30c35bSAndrew Lunn { 249dc30c35bSAndrew Lunn int irq, virq; 2503460a577SAndrew Lunn u16 mask; 2513460a577SAndrew Lunn 252d77f4321SVivien Didelot mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 2533d5fdba1SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 254d77f4321SVivien Didelot mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 2553460a577SAndrew Lunn 2565edef2f2SAndreas Färber for (irq = 0; irq < chip->g1_irq.nirqs; irq++) { 257a3db3d3aSAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 258dc30c35bSAndrew Lunn irq_dispose_mapping(virq); 259dc30c35bSAndrew Lunn } 260dc30c35bSAndrew Lunn 261a3db3d3aSAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 262dc30c35bSAndrew Lunn } 263dc30c35bSAndrew Lunn 264294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) 265294d711eSAndrew Lunn { 2663d82475aSUwe Kleine-König /* 2673d82475aSUwe Kleine-König * free_irq must be called without reg_lock taken because the irq 2683d82475aSUwe Kleine-König * handler takes this lock, too. 2693d82475aSUwe Kleine-König */ 270294d711eSAndrew Lunn free_irq(chip->irq, chip); 2713d82475aSUwe Kleine-König 272c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2733d82475aSUwe Kleine-König mv88e6xxx_g1_irq_free_common(chip); 274c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 275294d711eSAndrew Lunn } 276294d711eSAndrew Lunn 277294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip) 278dc30c35bSAndrew Lunn { 2793dd0ef05SAndrew Lunn int err, irq, virq; 2803dd0ef05SAndrew Lunn u16 reg, mask; 281dc30c35bSAndrew Lunn 282dc30c35bSAndrew Lunn chip->g1_irq.nirqs = chip->info->g1_irqs; 283dc30c35bSAndrew Lunn chip->g1_irq.domain = irq_domain_add_simple( 284dc30c35bSAndrew Lunn NULL, chip->g1_irq.nirqs, 0, 285dc30c35bSAndrew Lunn &mv88e6xxx_g1_irq_domain_ops, chip); 286dc30c35bSAndrew Lunn if (!chip->g1_irq.domain) 287dc30c35bSAndrew Lunn return -ENOMEM; 288dc30c35bSAndrew Lunn 289dc30c35bSAndrew Lunn for (irq = 0; irq < chip->g1_irq.nirqs; irq++) 290dc30c35bSAndrew Lunn irq_create_mapping(chip->g1_irq.domain, irq); 291dc30c35bSAndrew Lunn 292dc30c35bSAndrew Lunn chip->g1_irq.chip = mv88e6xxx_g1_irq_chip; 293dc30c35bSAndrew Lunn chip->g1_irq.masked = ~0; 294dc30c35bSAndrew Lunn 295d77f4321SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 296dc30c35bSAndrew Lunn if (err) 2973dd0ef05SAndrew Lunn goto out_mapping; 298dc30c35bSAndrew Lunn 2993dd0ef05SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 300dc30c35bSAndrew Lunn 301d77f4321SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 302dc30c35bSAndrew Lunn if (err) 3033dd0ef05SAndrew Lunn goto out_disable; 304dc30c35bSAndrew Lunn 305dc30c35bSAndrew Lunn /* Reading the interrupt status clears (most of) them */ 30682466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 307dc30c35bSAndrew Lunn if (err) 3083dd0ef05SAndrew Lunn goto out_disable; 309dc30c35bSAndrew Lunn 310dc30c35bSAndrew Lunn return 0; 311dc30c35bSAndrew Lunn 3123dd0ef05SAndrew Lunn out_disable: 3133d5fdba1SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 314d77f4321SVivien Didelot mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 3153dd0ef05SAndrew Lunn 3163dd0ef05SAndrew Lunn out_mapping: 3173dd0ef05SAndrew Lunn for (irq = 0; irq < 16; irq++) { 3183dd0ef05SAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 3193dd0ef05SAndrew Lunn irq_dispose_mapping(virq); 3203dd0ef05SAndrew Lunn } 3213dd0ef05SAndrew Lunn 3223dd0ef05SAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 323dc30c35bSAndrew Lunn 324dc30c35bSAndrew Lunn return err; 325dc30c35bSAndrew Lunn } 326dc30c35bSAndrew Lunn 327294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) 328294d711eSAndrew Lunn { 329f6d9758bSAndrew Lunn static struct lock_class_key lock_key; 330f6d9758bSAndrew Lunn static struct lock_class_key request_key; 331294d711eSAndrew Lunn int err; 332294d711eSAndrew Lunn 333294d711eSAndrew Lunn err = mv88e6xxx_g1_irq_setup_common(chip); 334294d711eSAndrew Lunn if (err) 335294d711eSAndrew Lunn return err; 336294d711eSAndrew Lunn 337f6d9758bSAndrew Lunn /* These lock classes tells lockdep that global 1 irqs are in 338f6d9758bSAndrew Lunn * a different category than their parent GPIO, so it won't 339f6d9758bSAndrew Lunn * report false recursion. 340f6d9758bSAndrew Lunn */ 341f6d9758bSAndrew Lunn irq_set_lockdep_class(chip->irq, &lock_key, &request_key); 342f6d9758bSAndrew Lunn 3433095383aSAndrew Lunn snprintf(chip->irq_name, sizeof(chip->irq_name), 3443095383aSAndrew Lunn "mv88e6xxx-%s", dev_name(chip->dev)); 3453095383aSAndrew Lunn 346c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 347294d711eSAndrew Lunn err = request_threaded_irq(chip->irq, NULL, 348294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_fn, 3490340376eSMarek Behún IRQF_ONESHOT | IRQF_SHARED, 3503095383aSAndrew Lunn chip->irq_name, chip); 351c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 352294d711eSAndrew Lunn if (err) 353294d711eSAndrew Lunn mv88e6xxx_g1_irq_free_common(chip); 354294d711eSAndrew Lunn 355294d711eSAndrew Lunn return err; 356294d711eSAndrew Lunn } 357294d711eSAndrew Lunn 358294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work) 359294d711eSAndrew Lunn { 360294d711eSAndrew Lunn struct mv88e6xxx_chip *chip = container_of(work, 361294d711eSAndrew Lunn struct mv88e6xxx_chip, 362294d711eSAndrew Lunn irq_poll_work.work); 363294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_work(chip); 364294d711eSAndrew Lunn 365294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 366294d711eSAndrew Lunn msecs_to_jiffies(100)); 367294d711eSAndrew Lunn } 368294d711eSAndrew Lunn 369294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip) 370294d711eSAndrew Lunn { 371294d711eSAndrew Lunn int err; 372294d711eSAndrew Lunn 373294d711eSAndrew Lunn err = mv88e6xxx_g1_irq_setup_common(chip); 374294d711eSAndrew Lunn if (err) 375294d711eSAndrew Lunn return err; 376294d711eSAndrew Lunn 377294d711eSAndrew Lunn kthread_init_delayed_work(&chip->irq_poll_work, 378294d711eSAndrew Lunn mv88e6xxx_irq_poll); 379294d711eSAndrew Lunn 3803f8b8696SFlorian Fainelli chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev)); 381294d711eSAndrew Lunn if (IS_ERR(chip->kworker)) 382294d711eSAndrew Lunn return PTR_ERR(chip->kworker); 383294d711eSAndrew Lunn 384294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 385294d711eSAndrew Lunn msecs_to_jiffies(100)); 386294d711eSAndrew Lunn 387294d711eSAndrew Lunn return 0; 388294d711eSAndrew Lunn } 389294d711eSAndrew Lunn 390294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip) 391294d711eSAndrew Lunn { 392294d711eSAndrew Lunn kthread_cancel_delayed_work_sync(&chip->irq_poll_work); 393294d711eSAndrew Lunn kthread_destroy_worker(chip->kworker); 3943d82475aSUwe Kleine-König 395c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3963d82475aSUwe Kleine-König mv88e6xxx_g1_irq_free_common(chip); 397c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 398294d711eSAndrew Lunn } 399294d711eSAndrew Lunn 40064d47d50SRussell King static int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip, 40164d47d50SRussell King int port, phy_interface_t interface) 40264d47d50SRussell King { 40364d47d50SRussell King int err; 40464d47d50SRussell King 40564d47d50SRussell King if (chip->info->ops->port_set_rgmii_delay) { 40664d47d50SRussell King err = chip->info->ops->port_set_rgmii_delay(chip, port, 40764d47d50SRussell King interface); 40864d47d50SRussell King if (err && err != -EOPNOTSUPP) 40964d47d50SRussell King return err; 41064d47d50SRussell King } 41164d47d50SRussell King 41264d47d50SRussell King if (chip->info->ops->port_set_cmode) { 41364d47d50SRussell King err = chip->info->ops->port_set_cmode(chip, port, 41464d47d50SRussell King interface); 41564d47d50SRussell King if (err && err != -EOPNOTSUPP) 41664d47d50SRussell King return err; 41764d47d50SRussell King } 41864d47d50SRussell King 41964d47d50SRussell King return 0; 42064d47d50SRussell King } 42164d47d50SRussell King 42272d8b4fdSHeiner Kallweit int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link, 42372d8b4fdSHeiner Kallweit int speed, int duplex, int pause, 424d78343d2SVivien Didelot phy_interface_t mode) 425d78343d2SVivien Didelot { 426a26deec6SAndrew Lunn struct phylink_link_state state; 427d78343d2SVivien Didelot int err; 428d78343d2SVivien Didelot 429d78343d2SVivien Didelot if (!chip->info->ops->port_set_link) 430d78343d2SVivien Didelot return 0; 431d78343d2SVivien Didelot 432a26deec6SAndrew Lunn if (!chip->info->ops->port_link_state) 433a26deec6SAndrew Lunn return 0; 434a26deec6SAndrew Lunn 435a26deec6SAndrew Lunn err = chip->info->ops->port_link_state(chip, port, &state); 436a26deec6SAndrew Lunn if (err) 437a26deec6SAndrew Lunn return err; 438a26deec6SAndrew Lunn 439a26deec6SAndrew Lunn /* Has anything actually changed? We don't expect the 440a26deec6SAndrew Lunn * interface mode to change without one of the other 441a26deec6SAndrew Lunn * parameters also changing 442a26deec6SAndrew Lunn */ 443a26deec6SAndrew Lunn if (state.link == link && 444a26deec6SAndrew Lunn state.speed == speed && 445927441adSMarek Behún state.duplex == duplex && 446927441adSMarek Behún (state.interface == mode || 447927441adSMarek Behún state.interface == PHY_INTERFACE_MODE_NA)) 448a26deec6SAndrew Lunn return 0; 449a26deec6SAndrew Lunn 450d78343d2SVivien Didelot /* Port's MAC control must not be changed unless the link is down */ 45143c8e0aeSHubert Feurstein err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN); 452d78343d2SVivien Didelot if (err) 453d78343d2SVivien Didelot return err; 454d78343d2SVivien Didelot 455d78343d2SVivien Didelot if (chip->info->ops->port_set_speed) { 456d78343d2SVivien Didelot err = chip->info->ops->port_set_speed(chip, port, speed); 457d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 458d78343d2SVivien Didelot goto restore_link; 459d78343d2SVivien Didelot } 460d78343d2SVivien Didelot 4617cbbee05SAndrew Lunn if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode) 4627cbbee05SAndrew Lunn mode = chip->info->ops->port_max_speed_mode(port); 4637cbbee05SAndrew Lunn 46454186b91SAndrew Lunn if (chip->info->ops->port_set_pause) { 46554186b91SAndrew Lunn err = chip->info->ops->port_set_pause(chip, port, pause); 46654186b91SAndrew Lunn if (err) 46754186b91SAndrew Lunn goto restore_link; 46854186b91SAndrew Lunn } 46954186b91SAndrew Lunn 470d78343d2SVivien Didelot if (chip->info->ops->port_set_duplex) { 471d78343d2SVivien Didelot err = chip->info->ops->port_set_duplex(chip, port, duplex); 472d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 473d78343d2SVivien Didelot goto restore_link; 474d78343d2SVivien Didelot } 475d78343d2SVivien Didelot 47664d47d50SRussell King err = mv88e6xxx_port_config_interface(chip, port, mode); 477d78343d2SVivien Didelot restore_link: 478d78343d2SVivien Didelot if (chip->info->ops->port_set_link(chip, port, link)) 479774439e5SVivien Didelot dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port); 480d78343d2SVivien Didelot 481d78343d2SVivien Didelot return err; 482d78343d2SVivien Didelot } 483d78343d2SVivien Didelot 484d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) 485d700ec41SMarek Vasut { 486d700ec41SMarek Vasut struct mv88e6xxx_chip *chip = ds->priv; 487d700ec41SMarek Vasut 488d700ec41SMarek Vasut return port < chip->info->num_internal_phys; 489d700ec41SMarek Vasut } 490d700ec41SMarek Vasut 4916c422e34SRussell King static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port, 4926c422e34SRussell King unsigned long *mask, 4936c422e34SRussell King struct phylink_link_state *state) 4946c422e34SRussell King { 4956c422e34SRussell King if (!phy_interface_mode_is_8023z(state->interface)) { 4966c422e34SRussell King /* 10M and 100M are only supported in non-802.3z mode */ 4976c422e34SRussell King phylink_set(mask, 10baseT_Half); 4986c422e34SRussell King phylink_set(mask, 10baseT_Full); 4996c422e34SRussell King phylink_set(mask, 100baseT_Half); 5006c422e34SRussell King phylink_set(mask, 100baseT_Full); 5016c422e34SRussell King } 5026c422e34SRussell King } 5036c422e34SRussell King 5046c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5056c422e34SRussell King unsigned long *mask, 5066c422e34SRussell King struct phylink_link_state *state) 5076c422e34SRussell King { 5086c422e34SRussell King /* FIXME: if the port is in 1000Base-X mode, then it only supports 5096c422e34SRussell King * 1000M FD speeds. In this case, CMODE will indicate 5. 5106c422e34SRussell King */ 5116c422e34SRussell King phylink_set(mask, 1000baseT_Full); 5126c422e34SRussell King phylink_set(mask, 1000baseX_Full); 5136c422e34SRussell King 5146c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 5156c422e34SRussell King } 5166c422e34SRussell King 517e3af71a3SMarek Behún static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port, 518e3af71a3SMarek Behún unsigned long *mask, 519e3af71a3SMarek Behún struct phylink_link_state *state) 520e3af71a3SMarek Behún { 521e3af71a3SMarek Behún if (port >= 5) 522e3af71a3SMarek Behún phylink_set(mask, 2500baseX_Full); 523e3af71a3SMarek Behún 524e3af71a3SMarek Behún /* No ethtool bits for 200Mbps */ 525e3af71a3SMarek Behún phylink_set(mask, 1000baseT_Full); 526e3af71a3SMarek Behún phylink_set(mask, 1000baseX_Full); 527e3af71a3SMarek Behún 528e3af71a3SMarek Behún mv88e6065_phylink_validate(chip, port, mask, state); 529e3af71a3SMarek Behún } 530e3af71a3SMarek Behún 5316c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5326c422e34SRussell King unsigned long *mask, 5336c422e34SRussell King struct phylink_link_state *state) 5346c422e34SRussell King { 5356c422e34SRussell King /* No ethtool bits for 200Mbps */ 5366c422e34SRussell King phylink_set(mask, 1000baseT_Full); 5376c422e34SRussell King phylink_set(mask, 1000baseX_Full); 5386c422e34SRussell King 5396c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 5406c422e34SRussell King } 5416c422e34SRussell King 5426c422e34SRussell King static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5436c422e34SRussell King unsigned long *mask, 5446c422e34SRussell King struct phylink_link_state *state) 5456c422e34SRussell King { 546ec26016bSAndrew Lunn if (port >= 9) { 5476c422e34SRussell King phylink_set(mask, 2500baseX_Full); 548ec26016bSAndrew Lunn phylink_set(mask, 2500baseT_Full); 549ec26016bSAndrew Lunn } 5506c422e34SRussell King 5516c422e34SRussell King /* No ethtool bits for 200Mbps */ 5526c422e34SRussell King phylink_set(mask, 1000baseT_Full); 5536c422e34SRussell King phylink_set(mask, 1000baseX_Full); 5546c422e34SRussell King 5556c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 5566c422e34SRussell King } 5576c422e34SRussell King 5586c422e34SRussell King static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5596c422e34SRussell King unsigned long *mask, 5606c422e34SRussell King struct phylink_link_state *state) 5616c422e34SRussell King { 5626c422e34SRussell King if (port >= 9) { 5636c422e34SRussell King phylink_set(mask, 10000baseT_Full); 5646c422e34SRussell King phylink_set(mask, 10000baseKR_Full); 5656c422e34SRussell King } 5666c422e34SRussell King 5676c422e34SRussell King mv88e6390_phylink_validate(chip, port, mask, state); 5686c422e34SRussell King } 5696c422e34SRussell King 570c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port, 571c9a2356fSRussell King unsigned long *supported, 572c9a2356fSRussell King struct phylink_link_state *state) 573c9a2356fSRussell King { 5746c422e34SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 5756c422e34SRussell King struct mv88e6xxx_chip *chip = ds->priv; 5766c422e34SRussell King 5776c422e34SRussell King /* Allow all the expected bits */ 5786c422e34SRussell King phylink_set(mask, Autoneg); 5796c422e34SRussell King phylink_set(mask, Pause); 5806c422e34SRussell King phylink_set_port_modes(mask); 5816c422e34SRussell King 5826c422e34SRussell King if (chip->info->ops->phylink_validate) 5836c422e34SRussell King chip->info->ops->phylink_validate(chip, port, mask, state); 5846c422e34SRussell King 5856c422e34SRussell King bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); 5866c422e34SRussell King bitmap_and(state->advertising, state->advertising, mask, 5876c422e34SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS); 5886c422e34SRussell King 5896c422e34SRussell King /* We can only operate at 2500BaseX or 1000BaseX. If requested 5906c422e34SRussell King * to advertise both, only report advertising at 2500BaseX. 5916c422e34SRussell King */ 5926c422e34SRussell King phylink_helper_basex_speed(state); 593c9a2356fSRussell King } 594c9a2356fSRussell King 595c9a2356fSRussell King static int mv88e6xxx_link_state(struct dsa_switch *ds, int port, 596c9a2356fSRussell King struct phylink_link_state *state) 597c9a2356fSRussell King { 598c9a2356fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 599c9a2356fSRussell King int err; 600c9a2356fSRussell King 601c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 6026c422e34SRussell King if (chip->info->ops->port_link_state) 6036c422e34SRussell King err = chip->info->ops->port_link_state(chip, port, state); 6046c422e34SRussell King else 6056c422e34SRussell King err = -EOPNOTSUPP; 606c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 607c9a2356fSRussell King 608c9a2356fSRussell King return err; 609c9a2356fSRussell King } 610c9a2356fSRussell King 611c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, 612c9a2356fSRussell King unsigned int mode, 613c9a2356fSRussell King const struct phylink_link_state *state) 614c9a2356fSRussell King { 615c9a2356fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 61664d47d50SRussell King int err; 617c9a2356fSRussell King 61864d47d50SRussell King /* FIXME: is this the correct test? If we're in fixed mode on an 61964d47d50SRussell King * internal port, why should we process this any different from 62064d47d50SRussell King * PHY mode? On the other hand, the port may be automedia between 62164d47d50SRussell King * an internal PHY and the serdes... 62264d47d50SRussell King */ 623d700ec41SMarek Vasut if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port)) 624c9a2356fSRussell King return; 625c9a2356fSRussell King 626c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 62764d47d50SRussell King /* FIXME: should we force the link down here - but if we do, how 62864d47d50SRussell King * do we restore the link force/unforce state? The driver layering 62964d47d50SRussell King * gets in the way. 63064d47d50SRussell King */ 63164d47d50SRussell King err = mv88e6xxx_port_config_interface(chip, port, state->interface); 632c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 633c9a2356fSRussell King 634c9a2356fSRussell King if (err && err != -EOPNOTSUPP) 63564d47d50SRussell King dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port); 636c9a2356fSRussell King } 637c9a2356fSRussell King 638c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port, 639c9a2356fSRussell King unsigned int mode, 640c9a2356fSRussell King phy_interface_t interface) 641c9a2356fSRussell King { 64230c4a5b0SRussell King struct mv88e6xxx_chip *chip = ds->priv; 64330c4a5b0SRussell King const struct mv88e6xxx_ops *ops; 64430c4a5b0SRussell King int err = 0; 64530c4a5b0SRussell King 64630c4a5b0SRussell King ops = chip->info->ops; 64730c4a5b0SRussell King 64830c4a5b0SRussell King /* Internal PHYs propagate their configuration directly to the MAC. 64930c4a5b0SRussell King * External PHYs depend on whether the PPU is enabled for this port. 65030c4a5b0SRussell King * FIXME: we should be using the PPU enable state here. What about 65130c4a5b0SRussell King * an automedia port? 65230c4a5b0SRussell King */ 65330c4a5b0SRussell King if (!mv88e6xxx_phy_is_internal(ds, port) && ops->port_set_link) { 65430c4a5b0SRussell King mv88e6xxx_reg_lock(chip); 65530c4a5b0SRussell King err = ops->port_set_link(chip, port, LINK_FORCED_DOWN); 65630c4a5b0SRussell King mv88e6xxx_reg_unlock(chip); 65730c4a5b0SRussell King 65830c4a5b0SRussell King if (err) 65930c4a5b0SRussell King dev_err(chip->dev, 66030c4a5b0SRussell King "p%d: failed to force MAC link down\n", port); 66130c4a5b0SRussell King } 662c9a2356fSRussell King } 663c9a2356fSRussell King 664c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, 665c9a2356fSRussell King unsigned int mode, phy_interface_t interface, 6665b502a7bSRussell King struct phy_device *phydev, 6675b502a7bSRussell King int speed, int duplex, 6685b502a7bSRussell King bool tx_pause, bool rx_pause) 669c9a2356fSRussell King { 67030c4a5b0SRussell King struct mv88e6xxx_chip *chip = ds->priv; 67130c4a5b0SRussell King const struct mv88e6xxx_ops *ops; 67230c4a5b0SRussell King int err = 0; 67330c4a5b0SRussell King 67430c4a5b0SRussell King ops = chip->info->ops; 67530c4a5b0SRussell King 67630c4a5b0SRussell King /* Internal PHYs propagate their configuration directly to the MAC. 67730c4a5b0SRussell King * External PHYs depend on whether the PPU is enabled for this port. 67830c4a5b0SRussell King * FIXME: we should be using the PPU enable state here. What about 67930c4a5b0SRussell King * an automedia port? 68030c4a5b0SRussell King */ 68130c4a5b0SRussell King if (!mv88e6xxx_phy_is_internal(ds, port)) { 68230c4a5b0SRussell King mv88e6xxx_reg_lock(chip); 68330c4a5b0SRussell King /* FIXME: for an automedia port, should we force the link 68430c4a5b0SRussell King * down here - what if the link comes up due to "other" media 68530c4a5b0SRussell King * while we're bringing the port up, how is the exclusivity 68630c4a5b0SRussell King * handled in the Marvell hardware? E.g. port 4 on 88E6532 68730c4a5b0SRussell King * shared between internal PHY and Serdes. 68830c4a5b0SRussell King */ 68930c4a5b0SRussell King if (ops->port_set_speed) { 69030c4a5b0SRussell King err = ops->port_set_speed(chip, port, speed); 69130c4a5b0SRussell King if (err && err != -EOPNOTSUPP) 69230c4a5b0SRussell King goto error; 69330c4a5b0SRussell King } 69430c4a5b0SRussell King 69530c4a5b0SRussell King if (ops->port_set_duplex) { 69630c4a5b0SRussell King err = ops->port_set_duplex(chip, port, duplex); 69730c4a5b0SRussell King if (err && err != -EOPNOTSUPP) 69830c4a5b0SRussell King goto error; 69930c4a5b0SRussell King } 70030c4a5b0SRussell King 70130c4a5b0SRussell King if (ops->port_set_link) 70230c4a5b0SRussell King err = ops->port_set_link(chip, port, LINK_FORCED_UP); 70330c4a5b0SRussell King error: 70430c4a5b0SRussell King mv88e6xxx_reg_unlock(chip); 70530c4a5b0SRussell King 70630c4a5b0SRussell King if (err && err != -EOPNOTSUPP) 70730c4a5b0SRussell King dev_err(ds->dev, 70830c4a5b0SRussell King "p%d: failed to configure MAC link up\n", port); 70930c4a5b0SRussell King } 710c9a2356fSRussell King } 711c9a2356fSRussell King 712a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 713fad09c73SVivien Didelot { 714a605a0feSAndrew Lunn if (!chip->info->ops->stats_snapshot) 715a605a0feSAndrew Lunn return -EOPNOTSUPP; 716fad09c73SVivien Didelot 717a605a0feSAndrew Lunn return chip->info->ops->stats_snapshot(chip, port); 718fad09c73SVivien Didelot } 719fad09c73SVivien Didelot 720fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = { 721dfafe449SAndrew Lunn { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, }, 722dfafe449SAndrew Lunn { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, }, 723dfafe449SAndrew Lunn { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, }, 724dfafe449SAndrew Lunn { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, }, 725dfafe449SAndrew Lunn { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, }, 726dfafe449SAndrew Lunn { "in_pause", 4, 0x16, STATS_TYPE_BANK0, }, 727dfafe449SAndrew Lunn { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, }, 728dfafe449SAndrew Lunn { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, }, 729dfafe449SAndrew Lunn { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, }, 730dfafe449SAndrew Lunn { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, }, 731dfafe449SAndrew Lunn { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, }, 732dfafe449SAndrew Lunn { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, }, 733dfafe449SAndrew Lunn { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, }, 734dfafe449SAndrew Lunn { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, }, 735dfafe449SAndrew Lunn { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, }, 736dfafe449SAndrew Lunn { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, }, 737dfafe449SAndrew Lunn { "out_pause", 4, 0x15, STATS_TYPE_BANK0, }, 738dfafe449SAndrew Lunn { "excessive", 4, 0x11, STATS_TYPE_BANK0, }, 739dfafe449SAndrew Lunn { "collisions", 4, 0x1e, STATS_TYPE_BANK0, }, 740dfafe449SAndrew Lunn { "deferred", 4, 0x05, STATS_TYPE_BANK0, }, 741dfafe449SAndrew Lunn { "single", 4, 0x14, STATS_TYPE_BANK0, }, 742dfafe449SAndrew Lunn { "multiple", 4, 0x17, STATS_TYPE_BANK0, }, 743dfafe449SAndrew Lunn { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, }, 744dfafe449SAndrew Lunn { "late", 4, 0x1f, STATS_TYPE_BANK0, }, 745dfafe449SAndrew Lunn { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, }, 746dfafe449SAndrew Lunn { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, }, 747dfafe449SAndrew Lunn { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, }, 748dfafe449SAndrew Lunn { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, }, 749dfafe449SAndrew Lunn { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, }, 750dfafe449SAndrew Lunn { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, }, 751dfafe449SAndrew Lunn { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, }, 752dfafe449SAndrew Lunn { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, }, 753dfafe449SAndrew Lunn { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, }, 754dfafe449SAndrew Lunn { "in_discards", 4, 0x00, STATS_TYPE_BANK1, }, 755dfafe449SAndrew Lunn { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, }, 756dfafe449SAndrew Lunn { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, }, 757dfafe449SAndrew Lunn { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, }, 758dfafe449SAndrew Lunn { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, }, 759dfafe449SAndrew Lunn { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, }, 760dfafe449SAndrew Lunn { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, }, 761dfafe449SAndrew Lunn { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, }, 762dfafe449SAndrew Lunn { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, }, 763dfafe449SAndrew Lunn { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, }, 764dfafe449SAndrew Lunn { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, }, 765dfafe449SAndrew Lunn { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, }, 766dfafe449SAndrew Lunn { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, }, 767dfafe449SAndrew Lunn { "in_management", 4, 0x0f, STATS_TYPE_BANK1, }, 768dfafe449SAndrew Lunn { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, }, 769dfafe449SAndrew Lunn { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, }, 770dfafe449SAndrew Lunn { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, }, 771dfafe449SAndrew Lunn { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, }, 772dfafe449SAndrew Lunn { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, }, 773dfafe449SAndrew Lunn { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, }, 774dfafe449SAndrew Lunn { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, }, 775dfafe449SAndrew Lunn { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, }, 776dfafe449SAndrew Lunn { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, }, 777dfafe449SAndrew Lunn { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, }, 778dfafe449SAndrew Lunn { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, }, 779dfafe449SAndrew Lunn { "out_management", 4, 0x1f, STATS_TYPE_BANK1, }, 780fad09c73SVivien Didelot }; 781fad09c73SVivien Didelot 782fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, 783fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *s, 784e0d8b615SAndrew Lunn int port, u16 bank1_select, 785e0d8b615SAndrew Lunn u16 histogram) 786fad09c73SVivien Didelot { 787fad09c73SVivien Didelot u32 low; 788fad09c73SVivien Didelot u32 high = 0; 789dfafe449SAndrew Lunn u16 reg = 0; 7900e7b9925SAndrew Lunn int err; 791fad09c73SVivien Didelot u64 value; 792fad09c73SVivien Didelot 793fad09c73SVivien Didelot switch (s->type) { 794dfafe449SAndrew Lunn case STATS_TYPE_PORT: 7950e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg, ®); 7960e7b9925SAndrew Lunn if (err) 7976c3442f5SJisheng Zhang return U64_MAX; 798fad09c73SVivien Didelot 7990e7b9925SAndrew Lunn low = reg; 800cda9f4aaSAndrew Lunn if (s->size == 4) { 8010e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg + 1, ®); 8020e7b9925SAndrew Lunn if (err) 8036c3442f5SJisheng Zhang return U64_MAX; 80484b3fd1fSRasmus Villemoes low |= ((u32)reg) << 16; 805fad09c73SVivien Didelot } 806fad09c73SVivien Didelot break; 807dfafe449SAndrew Lunn case STATS_TYPE_BANK1: 808e0d8b615SAndrew Lunn reg = bank1_select; 809dfafe449SAndrew Lunn /* fall through */ 810dfafe449SAndrew Lunn case STATS_TYPE_BANK0: 811e0d8b615SAndrew Lunn reg |= s->reg | histogram; 8127f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg, &low); 813cda9f4aaSAndrew Lunn if (s->size == 8) 8147f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg + 1, &high); 8159fc3e4dcSGustavo A. R. Silva break; 8169fc3e4dcSGustavo A. R. Silva default: 8176c3442f5SJisheng Zhang return U64_MAX; 818fad09c73SVivien Didelot } 8196e46e2d8SAndrew Lunn value = (((u64)high) << 32) | low; 820fad09c73SVivien Didelot return value; 821fad09c73SVivien Didelot } 822fad09c73SVivien Didelot 823436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, 824dfafe449SAndrew Lunn uint8_t *data, int types) 825fad09c73SVivien Didelot { 826fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 827fad09c73SVivien Didelot int i, j; 828fad09c73SVivien Didelot 829fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 830fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 831dfafe449SAndrew Lunn if (stat->type & types) { 832fad09c73SVivien Didelot memcpy(data + j * ETH_GSTRING_LEN, stat->string, 833fad09c73SVivien Didelot ETH_GSTRING_LEN); 834fad09c73SVivien Didelot j++; 835fad09c73SVivien Didelot } 836fad09c73SVivien Didelot } 837436fe17dSAndrew Lunn 838436fe17dSAndrew Lunn return j; 839fad09c73SVivien Didelot } 840fad09c73SVivien Didelot 841436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, 842dfafe449SAndrew Lunn uint8_t *data) 843dfafe449SAndrew Lunn { 844436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 845dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT); 846dfafe449SAndrew Lunn } 847dfafe449SAndrew Lunn 8481f71836fSRasmus Villemoes static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip, 8491f71836fSRasmus Villemoes uint8_t *data) 8501f71836fSRasmus Villemoes { 8511f71836fSRasmus Villemoes return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0); 8521f71836fSRasmus Villemoes } 8531f71836fSRasmus Villemoes 854436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, 855dfafe449SAndrew Lunn uint8_t *data) 856dfafe449SAndrew Lunn { 857436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 858dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1); 859dfafe449SAndrew Lunn } 860dfafe449SAndrew Lunn 86165f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = { 86265f60e45SAndrew Lunn "atu_member_violation", 86365f60e45SAndrew Lunn "atu_miss_violation", 86465f60e45SAndrew Lunn "atu_full_violation", 86565f60e45SAndrew Lunn "vtu_member_violation", 86665f60e45SAndrew Lunn "vtu_miss_violation", 86765f60e45SAndrew Lunn }; 86865f60e45SAndrew Lunn 86965f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data) 87065f60e45SAndrew Lunn { 87165f60e45SAndrew Lunn unsigned int i; 87265f60e45SAndrew Lunn 87365f60e45SAndrew Lunn for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++) 87465f60e45SAndrew Lunn strlcpy(data + i * ETH_GSTRING_LEN, 87565f60e45SAndrew Lunn mv88e6xxx_atu_vtu_stats_strings[i], 87665f60e45SAndrew Lunn ETH_GSTRING_LEN); 87765f60e45SAndrew Lunn } 87865f60e45SAndrew Lunn 879dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, 88089f09048SFlorian Fainelli u32 stringset, uint8_t *data) 881fad09c73SVivien Didelot { 88204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 883436fe17dSAndrew Lunn int count = 0; 884dfafe449SAndrew Lunn 88589f09048SFlorian Fainelli if (stringset != ETH_SS_STATS) 88689f09048SFlorian Fainelli return; 88789f09048SFlorian Fainelli 888c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 889c6c8cd5eSAndrew Lunn 890dfafe449SAndrew Lunn if (chip->info->ops->stats_get_strings) 891436fe17dSAndrew Lunn count = chip->info->ops->stats_get_strings(chip, data); 892436fe17dSAndrew Lunn 893436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_strings) { 894436fe17dSAndrew Lunn data += count * ETH_GSTRING_LEN; 89565f60e45SAndrew Lunn count = chip->info->ops->serdes_get_strings(chip, port, data); 896436fe17dSAndrew Lunn } 897c6c8cd5eSAndrew Lunn 89865f60e45SAndrew Lunn data += count * ETH_GSTRING_LEN; 89965f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_strings(data); 90065f60e45SAndrew Lunn 901c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 902dfafe449SAndrew Lunn } 903dfafe449SAndrew Lunn 904dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip, 905dfafe449SAndrew Lunn int types) 906dfafe449SAndrew Lunn { 907fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 908fad09c73SVivien Didelot int i, j; 909fad09c73SVivien Didelot 910fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 911fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 912dfafe449SAndrew Lunn if (stat->type & types) 913fad09c73SVivien Didelot j++; 914fad09c73SVivien Didelot } 915fad09c73SVivien Didelot return j; 916fad09c73SVivien Didelot } 917fad09c73SVivien Didelot 918dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip) 919dfafe449SAndrew Lunn { 920dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 921dfafe449SAndrew Lunn STATS_TYPE_PORT); 922dfafe449SAndrew Lunn } 923dfafe449SAndrew Lunn 9241f71836fSRasmus Villemoes static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip) 9251f71836fSRasmus Villemoes { 9261f71836fSRasmus Villemoes return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0); 9271f71836fSRasmus Villemoes } 9281f71836fSRasmus Villemoes 929dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip) 930dfafe449SAndrew Lunn { 931dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 932dfafe449SAndrew Lunn STATS_TYPE_BANK1); 933dfafe449SAndrew Lunn } 934dfafe449SAndrew Lunn 93589f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset) 936dfafe449SAndrew Lunn { 937dfafe449SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 938436fe17dSAndrew Lunn int serdes_count = 0; 939436fe17dSAndrew Lunn int count = 0; 940dfafe449SAndrew Lunn 94189f09048SFlorian Fainelli if (sset != ETH_SS_STATS) 94289f09048SFlorian Fainelli return 0; 94389f09048SFlorian Fainelli 944c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 945dfafe449SAndrew Lunn if (chip->info->ops->stats_get_sset_count) 946436fe17dSAndrew Lunn count = chip->info->ops->stats_get_sset_count(chip); 947436fe17dSAndrew Lunn if (count < 0) 948436fe17dSAndrew Lunn goto out; 949436fe17dSAndrew Lunn 950436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_sset_count) 951436fe17dSAndrew Lunn serdes_count = chip->info->ops->serdes_get_sset_count(chip, 952436fe17dSAndrew Lunn port); 95365f60e45SAndrew Lunn if (serdes_count < 0) { 954436fe17dSAndrew Lunn count = serdes_count; 95565f60e45SAndrew Lunn goto out; 95665f60e45SAndrew Lunn } 957436fe17dSAndrew Lunn count += serdes_count; 95865f60e45SAndrew Lunn count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); 95965f60e45SAndrew Lunn 960436fe17dSAndrew Lunn out: 961c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 962dfafe449SAndrew Lunn 963436fe17dSAndrew Lunn return count; 964dfafe449SAndrew Lunn } 965dfafe449SAndrew Lunn 966436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 967e0d8b615SAndrew Lunn uint64_t *data, int types, 968e0d8b615SAndrew Lunn u16 bank1_select, u16 histogram) 969052f947fSAndrew Lunn { 970052f947fSAndrew Lunn struct mv88e6xxx_hw_stat *stat; 971052f947fSAndrew Lunn int i, j; 972052f947fSAndrew Lunn 973052f947fSAndrew Lunn for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 974052f947fSAndrew Lunn stat = &mv88e6xxx_hw_stats[i]; 975052f947fSAndrew Lunn if (stat->type & types) { 976c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 977e0d8b615SAndrew Lunn data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 978e0d8b615SAndrew Lunn bank1_select, 979e0d8b615SAndrew Lunn histogram); 980c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 981377cda13SAndrew Lunn 982052f947fSAndrew Lunn j++; 983052f947fSAndrew Lunn } 984052f947fSAndrew Lunn } 985436fe17dSAndrew Lunn return j; 986052f947fSAndrew Lunn } 987052f947fSAndrew Lunn 988436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 989052f947fSAndrew Lunn uint64_t *data) 990052f947fSAndrew Lunn { 991052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 992e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT, 99357d1ef38SVivien Didelot 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 994052f947fSAndrew Lunn } 995052f947fSAndrew Lunn 9961f71836fSRasmus Villemoes static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 9971f71836fSRasmus Villemoes uint64_t *data) 9981f71836fSRasmus Villemoes { 9991f71836fSRasmus Villemoes return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0, 10001f71836fSRasmus Villemoes 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 10011f71836fSRasmus Villemoes } 10021f71836fSRasmus Villemoes 1003436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1004052f947fSAndrew Lunn uint64_t *data) 1005052f947fSAndrew Lunn { 1006052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1007e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 100857d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9, 100957d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 1010e0d8b615SAndrew Lunn } 1011e0d8b615SAndrew Lunn 1012436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1013e0d8b615SAndrew Lunn uint64_t *data) 1014e0d8b615SAndrew Lunn { 1015e0d8b615SAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1016e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 101757d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10, 101857d1ef38SVivien Didelot 0); 1019052f947fSAndrew Lunn } 1020052f947fSAndrew Lunn 102165f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port, 102265f60e45SAndrew Lunn uint64_t *data) 102365f60e45SAndrew Lunn { 102465f60e45SAndrew Lunn *data++ = chip->ports[port].atu_member_violation; 102565f60e45SAndrew Lunn *data++ = chip->ports[port].atu_miss_violation; 102665f60e45SAndrew Lunn *data++ = chip->ports[port].atu_full_violation; 102765f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_member_violation; 102865f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_miss_violation; 102965f60e45SAndrew Lunn } 103065f60e45SAndrew Lunn 1031052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, 1032052f947fSAndrew Lunn uint64_t *data) 1033052f947fSAndrew Lunn { 1034436fe17dSAndrew Lunn int count = 0; 1035436fe17dSAndrew Lunn 1036052f947fSAndrew Lunn if (chip->info->ops->stats_get_stats) 1037436fe17dSAndrew Lunn count = chip->info->ops->stats_get_stats(chip, port, data); 1038436fe17dSAndrew Lunn 1039c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1040436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_stats) { 1041436fe17dSAndrew Lunn data += count; 104265f60e45SAndrew Lunn count = chip->info->ops->serdes_get_stats(chip, port, data); 1043436fe17dSAndrew Lunn } 104465f60e45SAndrew Lunn data += count; 104565f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_stats(chip, port, data); 1046c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1047052f947fSAndrew Lunn } 1048052f947fSAndrew Lunn 1049fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, 1050fad09c73SVivien Didelot uint64_t *data) 1051fad09c73SVivien Didelot { 105204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1053fad09c73SVivien Didelot int ret; 1054fad09c73SVivien Didelot 1055c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1056fad09c73SVivien Didelot 1057a605a0feSAndrew Lunn ret = mv88e6xxx_stats_snapshot(chip, port); 1058c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1059377cda13SAndrew Lunn 1060377cda13SAndrew Lunn if (ret < 0) 1061fad09c73SVivien Didelot return; 1062052f947fSAndrew Lunn 1063052f947fSAndrew Lunn mv88e6xxx_get_stats(chip, port, data); 1064fad09c73SVivien Didelot 1065fad09c73SVivien Didelot } 1066fad09c73SVivien Didelot 1067fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) 1068fad09c73SVivien Didelot { 10690d30bbd0SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 10700d30bbd0SAndrew Lunn int len; 10710d30bbd0SAndrew Lunn 10720d30bbd0SAndrew Lunn len = 32 * sizeof(u16); 10730d30bbd0SAndrew Lunn if (chip->info->ops->serdes_get_regs_len) 10740d30bbd0SAndrew Lunn len += chip->info->ops->serdes_get_regs_len(chip, port); 10750d30bbd0SAndrew Lunn 10760d30bbd0SAndrew Lunn return len; 1077fad09c73SVivien Didelot } 1078fad09c73SVivien Didelot 1079fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, 1080fad09c73SVivien Didelot struct ethtool_regs *regs, void *_p) 1081fad09c73SVivien Didelot { 108204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 10830e7b9925SAndrew Lunn int err; 10840e7b9925SAndrew Lunn u16 reg; 1085fad09c73SVivien Didelot u16 *p = _p; 1086fad09c73SVivien Didelot int i; 1087fad09c73SVivien Didelot 1088a5f39326SVivien Didelot regs->version = chip->info->prod_num; 1089fad09c73SVivien Didelot 1090fad09c73SVivien Didelot memset(p, 0xff, 32 * sizeof(u16)); 1091fad09c73SVivien Didelot 1092c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1093fad09c73SVivien Didelot 1094fad09c73SVivien Didelot for (i = 0; i < 32; i++) { 1095fad09c73SVivien Didelot 10960e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, i, ®); 10970e7b9925SAndrew Lunn if (!err) 10980e7b9925SAndrew Lunn p[i] = reg; 1099fad09c73SVivien Didelot } 1100fad09c73SVivien Didelot 11010d30bbd0SAndrew Lunn if (chip->info->ops->serdes_get_regs) 11020d30bbd0SAndrew Lunn chip->info->ops->serdes_get_regs(chip, port, &p[i]); 11030d30bbd0SAndrew Lunn 1104c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1105fad09c73SVivien Didelot } 1106fad09c73SVivien Didelot 110708f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port, 1108fad09c73SVivien Didelot struct ethtool_eee *e) 1109fad09c73SVivien Didelot { 11105480db69SVivien Didelot /* Nothing to do on the port's MAC */ 11115480db69SVivien Didelot return 0; 1112fad09c73SVivien Didelot } 1113fad09c73SVivien Didelot 111408f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port, 111546587e4aSVivien Didelot struct ethtool_eee *e) 1116fad09c73SVivien Didelot { 11175480db69SVivien Didelot /* Nothing to do on the port's MAC */ 11185480db69SVivien Didelot return 0; 1119fad09c73SVivien Didelot } 1120fad09c73SVivien Didelot 11219dc8b13eSVivien Didelot /* Mask of the local ports allowed to receive frames from a given fabric port */ 1122e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port) 1123fad09c73SVivien Didelot { 11249dc8b13eSVivien Didelot struct dsa_switch *ds = chip->ds; 11259dc8b13eSVivien Didelot struct dsa_switch_tree *dst = ds->dst; 1126e5887a2aSVivien Didelot struct net_device *br; 11279dc8b13eSVivien Didelot struct dsa_port *dp; 11289dc8b13eSVivien Didelot bool found = false; 1129e5887a2aSVivien Didelot u16 pvlan; 1130fad09c73SVivien Didelot 11319dc8b13eSVivien Didelot list_for_each_entry(dp, &dst->ports, list) { 11329dc8b13eSVivien Didelot if (dp->ds->index == dev && dp->index == port) { 11339dc8b13eSVivien Didelot found = true; 11349dc8b13eSVivien Didelot break; 11359dc8b13eSVivien Didelot } 11369dc8b13eSVivien Didelot } 1137fad09c73SVivien Didelot 1138e5887a2aSVivien Didelot /* Prevent frames from unknown switch or port */ 11399dc8b13eSVivien Didelot if (!found) 1140e5887a2aSVivien Didelot return 0; 1141e5887a2aSVivien Didelot 1142e5887a2aSVivien Didelot /* Frames from DSA links and CPU ports can egress any local port */ 11439dc8b13eSVivien Didelot if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA) 1144e5887a2aSVivien Didelot return mv88e6xxx_port_mask(chip); 1145e5887a2aSVivien Didelot 11469dc8b13eSVivien Didelot br = dp->bridge_dev; 1147e5887a2aSVivien Didelot pvlan = 0; 1148e5887a2aSVivien Didelot 1149e5887a2aSVivien Didelot /* Frames from user ports can egress any local DSA links and CPU ports, 1150e5887a2aSVivien Didelot * as well as any local member of their bridge group. 1151e5887a2aSVivien Didelot */ 11529dc8b13eSVivien Didelot list_for_each_entry(dp, &dst->ports, list) 11539dc8b13eSVivien Didelot if (dp->ds == ds && 11549dc8b13eSVivien Didelot (dp->type == DSA_PORT_TYPE_CPU || 11559dc8b13eSVivien Didelot dp->type == DSA_PORT_TYPE_DSA || 11569dc8b13eSVivien Didelot (br && dp->bridge_dev == br))) 11579dc8b13eSVivien Didelot pvlan |= BIT(dp->index); 1158e5887a2aSVivien Didelot 1159e5887a2aSVivien Didelot return pvlan; 1160fad09c73SVivien Didelot } 1161e5887a2aSVivien Didelot 1162240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port) 1163e5887a2aSVivien Didelot { 1164e5887a2aSVivien Didelot u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port); 1165fad09c73SVivien Didelot 1166fad09c73SVivien Didelot /* prevent frames from going back out of the port they came in on */ 1167fad09c73SVivien Didelot output_ports &= ~BIT(port); 1168fad09c73SVivien Didelot 11695a7921f4SVivien Didelot return mv88e6xxx_port_set_vlan_map(chip, port, output_ports); 1170fad09c73SVivien Didelot } 1171fad09c73SVivien Didelot 1172fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, 1173fad09c73SVivien Didelot u8 state) 1174fad09c73SVivien Didelot { 117504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1176fad09c73SVivien Didelot int err; 1177fad09c73SVivien Didelot 1178c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1179f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, port, state); 1180c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1181fad09c73SVivien Didelot 1182fad09c73SVivien Didelot if (err) 1183774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to update state\n", port); 1184fad09c73SVivien Didelot } 1185fad09c73SVivien Didelot 118693e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip) 118793e18d61SVivien Didelot { 118893e18d61SVivien Didelot int err; 118993e18d61SVivien Didelot 119093e18d61SVivien Didelot if (chip->info->ops->ieee_pri_map) { 119193e18d61SVivien Didelot err = chip->info->ops->ieee_pri_map(chip); 119293e18d61SVivien Didelot if (err) 119393e18d61SVivien Didelot return err; 119493e18d61SVivien Didelot } 119593e18d61SVivien Didelot 119693e18d61SVivien Didelot if (chip->info->ops->ip_pri_map) { 119793e18d61SVivien Didelot err = chip->info->ops->ip_pri_map(chip); 119893e18d61SVivien Didelot if (err) 119993e18d61SVivien Didelot return err; 120093e18d61SVivien Didelot } 120193e18d61SVivien Didelot 120293e18d61SVivien Didelot return 0; 120393e18d61SVivien Didelot } 120493e18d61SVivien Didelot 1205c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) 1206c7f047b6SVivien Didelot { 1207c5f51765SVivien Didelot struct dsa_switch *ds = chip->ds; 1208c7f047b6SVivien Didelot int target, port; 1209c7f047b6SVivien Didelot int err; 1210c7f047b6SVivien Didelot 1211c7f047b6SVivien Didelot if (!chip->info->global2_addr) 1212c7f047b6SVivien Didelot return 0; 1213c7f047b6SVivien Didelot 1214c7f047b6SVivien Didelot /* Initialize the routing port to the 32 possible target devices */ 1215c7f047b6SVivien Didelot for (target = 0; target < 32; target++) { 1216c5f51765SVivien Didelot port = dsa_routing_port(ds, target); 1217c5f51765SVivien Didelot if (port == ds->num_ports) 1218c7f047b6SVivien Didelot port = 0x1f; 1219c7f047b6SVivien Didelot 1220c7f047b6SVivien Didelot err = mv88e6xxx_g2_device_mapping_write(chip, target, port); 1221c7f047b6SVivien Didelot if (err) 1222c7f047b6SVivien Didelot return err; 1223c7f047b6SVivien Didelot } 1224c7f047b6SVivien Didelot 122502317e68SVivien Didelot if (chip->info->ops->set_cascade_port) { 122602317e68SVivien Didelot port = MV88E6XXX_CASCADE_PORT_MULTIPLE; 122702317e68SVivien Didelot err = chip->info->ops->set_cascade_port(chip, port); 122802317e68SVivien Didelot if (err) 122902317e68SVivien Didelot return err; 123002317e68SVivien Didelot } 123102317e68SVivien Didelot 123223c98919SVivien Didelot err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index); 123323c98919SVivien Didelot if (err) 123423c98919SVivien Didelot return err; 123523c98919SVivien Didelot 1236c7f047b6SVivien Didelot return 0; 1237c7f047b6SVivien Didelot } 1238c7f047b6SVivien Didelot 1239b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip) 1240b28f872dSVivien Didelot { 1241b28f872dSVivien Didelot /* Clear all trunk masks and mapping */ 1242b28f872dSVivien Didelot if (chip->info->global2_addr) 1243b28f872dSVivien Didelot return mv88e6xxx_g2_trunk_clear(chip); 1244b28f872dSVivien Didelot 1245b28f872dSVivien Didelot return 0; 1246b28f872dSVivien Didelot } 1247b28f872dSVivien Didelot 12489e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip) 12499e5baf9bSVivien Didelot { 12509e5baf9bSVivien Didelot if (chip->info->ops->rmu_disable) 12519e5baf9bSVivien Didelot return chip->info->ops->rmu_disable(chip); 12529e5baf9bSVivien Didelot 12539e5baf9bSVivien Didelot return 0; 12549e5baf9bSVivien Didelot } 12559e5baf9bSVivien Didelot 12569e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip) 12579e907d73SVivien Didelot { 12589e907d73SVivien Didelot if (chip->info->ops->pot_clear) 12599e907d73SVivien Didelot return chip->info->ops->pot_clear(chip); 12609e907d73SVivien Didelot 12619e907d73SVivien Didelot return 0; 12629e907d73SVivien Didelot } 12639e907d73SVivien Didelot 126451c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip) 126551c901a7SVivien Didelot { 126651c901a7SVivien Didelot if (chip->info->ops->mgmt_rsvd2cpu) 126751c901a7SVivien Didelot return chip->info->ops->mgmt_rsvd2cpu(chip); 126851c901a7SVivien Didelot 126951c901a7SVivien Didelot return 0; 127051c901a7SVivien Didelot } 127151c901a7SVivien Didelot 1272a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) 1273a2ac29d2SVivien Didelot { 1274c3a7d4adSVivien Didelot int err; 1275c3a7d4adSVivien Didelot 1276daefc943SVivien Didelot err = mv88e6xxx_g1_atu_flush(chip, 0, true); 1277daefc943SVivien Didelot if (err) 1278daefc943SVivien Didelot return err; 1279daefc943SVivien Didelot 1280c3a7d4adSVivien Didelot err = mv88e6xxx_g1_atu_set_learn2all(chip, true); 1281c3a7d4adSVivien Didelot if (err) 1282c3a7d4adSVivien Didelot return err; 1283c3a7d4adSVivien Didelot 1284a2ac29d2SVivien Didelot return mv88e6xxx_g1_atu_set_age_time(chip, 300000); 1285a2ac29d2SVivien Didelot } 1286a2ac29d2SVivien Didelot 1287cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip) 1288cd8da8bbSVivien Didelot { 1289cd8da8bbSVivien Didelot int port; 1290cd8da8bbSVivien Didelot int err; 1291cd8da8bbSVivien Didelot 1292cd8da8bbSVivien Didelot if (!chip->info->ops->irl_init_all) 1293cd8da8bbSVivien Didelot return 0; 1294cd8da8bbSVivien Didelot 1295cd8da8bbSVivien Didelot for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 1296cd8da8bbSVivien Didelot /* Disable ingress rate limiting by resetting all per port 1297cd8da8bbSVivien Didelot * ingress rate limit resources to their initial state. 1298cd8da8bbSVivien Didelot */ 1299cd8da8bbSVivien Didelot err = chip->info->ops->irl_init_all(chip, port); 1300cd8da8bbSVivien Didelot if (err) 1301cd8da8bbSVivien Didelot return err; 1302cd8da8bbSVivien Didelot } 1303cd8da8bbSVivien Didelot 1304cd8da8bbSVivien Didelot return 0; 1305cd8da8bbSVivien Didelot } 1306cd8da8bbSVivien Didelot 130704a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip) 130804a69a17SVivien Didelot { 130904a69a17SVivien Didelot if (chip->info->ops->set_switch_mac) { 131004a69a17SVivien Didelot u8 addr[ETH_ALEN]; 131104a69a17SVivien Didelot 131204a69a17SVivien Didelot eth_random_addr(addr); 131304a69a17SVivien Didelot 131404a69a17SVivien Didelot return chip->info->ops->set_switch_mac(chip, addr); 131504a69a17SVivien Didelot } 131604a69a17SVivien Didelot 131704a69a17SVivien Didelot return 0; 131804a69a17SVivien Didelot } 131904a69a17SVivien Didelot 132017a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port) 132117a1594eSVivien Didelot { 132217a1594eSVivien Didelot u16 pvlan = 0; 132317a1594eSVivien Didelot 132417a1594eSVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1325d14939beSVivien Didelot return 0; 132617a1594eSVivien Didelot 132717a1594eSVivien Didelot /* Skip the local source device, which uses in-chip port VLAN */ 132817a1594eSVivien Didelot if (dev != chip->ds->index) 1329aec5ac88SVivien Didelot pvlan = mv88e6xxx_port_vlan(chip, dev, port); 133017a1594eSVivien Didelot 133117a1594eSVivien Didelot return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan); 133217a1594eSVivien Didelot } 133317a1594eSVivien Didelot 133481228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip) 133581228996SVivien Didelot { 133617a1594eSVivien Didelot int dev, port; 133717a1594eSVivien Didelot int err; 133817a1594eSVivien Didelot 133981228996SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 134081228996SVivien Didelot return 0; 134181228996SVivien Didelot 134281228996SVivien Didelot /* Clear 5 Bit Port for usage with Marvell Link Street devices: 134381228996SVivien Didelot * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev. 134481228996SVivien Didelot */ 134517a1594eSVivien Didelot err = mv88e6xxx_g2_misc_4_bit_port(chip); 134617a1594eSVivien Didelot if (err) 134717a1594eSVivien Didelot return err; 134817a1594eSVivien Didelot 134917a1594eSVivien Didelot for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) { 135017a1594eSVivien Didelot for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) { 135117a1594eSVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 135217a1594eSVivien Didelot if (err) 135317a1594eSVivien Didelot return err; 135417a1594eSVivien Didelot } 135517a1594eSVivien Didelot } 135617a1594eSVivien Didelot 135717a1594eSVivien Didelot return 0; 135881228996SVivien Didelot } 135981228996SVivien Didelot 1360749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port) 1361749efcb8SVivien Didelot { 1362749efcb8SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1363749efcb8SVivien Didelot int err; 1364749efcb8SVivien Didelot 1365c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1366e606ca36SVivien Didelot err = mv88e6xxx_g1_atu_remove(chip, 0, port, false); 1367c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1368749efcb8SVivien Didelot 1369749efcb8SVivien Didelot if (err) 1370774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to flush ATU\n", port); 1371749efcb8SVivien Didelot } 1372749efcb8SVivien Didelot 1373b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip) 1374b486d7c9SVivien Didelot { 1375b486d7c9SVivien Didelot if (!chip->info->max_vid) 1376b486d7c9SVivien Didelot return 0; 1377b486d7c9SVivien Didelot 1378b486d7c9SVivien Didelot return mv88e6xxx_g1_vtu_flush(chip); 1379b486d7c9SVivien Didelot } 1380b486d7c9SVivien Didelot 1381f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip, 1382f1394b78SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 1383f1394b78SVivien Didelot { 1384f1394b78SVivien Didelot if (!chip->info->ops->vtu_getnext) 1385f1394b78SVivien Didelot return -EOPNOTSUPP; 1386f1394b78SVivien Didelot 1387f1394b78SVivien Didelot return chip->info->ops->vtu_getnext(chip, entry); 1388f1394b78SVivien Didelot } 1389f1394b78SVivien Didelot 13900ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, 13910ad5daf6SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 13920ad5daf6SVivien Didelot { 13930ad5daf6SVivien Didelot if (!chip->info->ops->vtu_loadpurge) 13940ad5daf6SVivien Didelot return -EOPNOTSUPP; 13950ad5daf6SVivien Didelot 13960ad5daf6SVivien Didelot return chip->info->ops->vtu_loadpurge(chip, entry); 13970ad5daf6SVivien Didelot } 13980ad5daf6SVivien Didelot 1399d7f435f9SVivien Didelot static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) 1400fad09c73SVivien Didelot { 1401fad09c73SVivien Didelot DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); 1402425d2d37SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1403fad09c73SVivien Didelot int i, err; 1404fad09c73SVivien Didelot 1405fad09c73SVivien Didelot bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); 1406fad09c73SVivien Didelot 1407fad09c73SVivien Didelot /* Set every FID bit used by the (un)bridged ports */ 1408370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1409b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, i, fid); 1410fad09c73SVivien Didelot if (err) 1411fad09c73SVivien Didelot return err; 1412fad09c73SVivien Didelot 1413fad09c73SVivien Didelot set_bit(*fid, fid_bitmap); 1414fad09c73SVivien Didelot } 1415fad09c73SVivien Didelot 1416fad09c73SVivien Didelot /* Set every FID bit used by the VLAN entries */ 1417425d2d37SVivien Didelot vlan.vid = chip->info->max_vid; 1418425d2d37SVivien Didelot vlan.valid = false; 1419425d2d37SVivien Didelot 1420fad09c73SVivien Didelot do { 1421f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1422fad09c73SVivien Didelot if (err) 1423fad09c73SVivien Didelot return err; 1424fad09c73SVivien Didelot 1425fad09c73SVivien Didelot if (!vlan.valid) 1426fad09c73SVivien Didelot break; 1427fad09c73SVivien Didelot 1428fad09c73SVivien Didelot set_bit(vlan.fid, fid_bitmap); 14293cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 1430fad09c73SVivien Didelot 1431fad09c73SVivien Didelot /* The reset value 0x000 is used to indicate that multiple address 1432fad09c73SVivien Didelot * databases are not needed. Return the next positive available. 1433fad09c73SVivien Didelot */ 1434fad09c73SVivien Didelot *fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1); 1435fad09c73SVivien Didelot if (unlikely(*fid >= mv88e6xxx_num_databases(chip))) 1436fad09c73SVivien Didelot return -ENOSPC; 1437fad09c73SVivien Didelot 1438fad09c73SVivien Didelot /* Clear the database */ 1439daefc943SVivien Didelot return mv88e6xxx_g1_atu_flush(chip, *fid, true); 1440fad09c73SVivien Didelot } 1441fad09c73SVivien Didelot 144223e8b470SAndrew Lunn static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash) 144323e8b470SAndrew Lunn { 144423e8b470SAndrew Lunn if (chip->info->ops->atu_get_hash) 144523e8b470SAndrew Lunn return chip->info->ops->atu_get_hash(chip, hash); 144623e8b470SAndrew Lunn 144723e8b470SAndrew Lunn return -EOPNOTSUPP; 144823e8b470SAndrew Lunn } 144923e8b470SAndrew Lunn 145023e8b470SAndrew Lunn static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash) 145123e8b470SAndrew Lunn { 145223e8b470SAndrew Lunn if (chip->info->ops->atu_set_hash) 145323e8b470SAndrew Lunn return chip->info->ops->atu_set_hash(chip, hash); 145423e8b470SAndrew Lunn 145523e8b470SAndrew Lunn return -EOPNOTSUPP; 145623e8b470SAndrew Lunn } 145723e8b470SAndrew Lunn 1458fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, 1459fad09c73SVivien Didelot u16 vid_begin, u16 vid_end) 1460fad09c73SVivien Didelot { 146104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1462425d2d37SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1463fad09c73SVivien Didelot int i, err; 1464fad09c73SVivien Didelot 1465db06ae41SAndrew Lunn /* DSA and CPU ports have to be members of multiple vlans */ 1466db06ae41SAndrew Lunn if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 1467db06ae41SAndrew Lunn return 0; 1468db06ae41SAndrew Lunn 1469fad09c73SVivien Didelot if (!vid_begin) 1470fad09c73SVivien Didelot return -EOPNOTSUPP; 1471fad09c73SVivien Didelot 1472425d2d37SVivien Didelot vlan.vid = vid_begin - 1; 1473425d2d37SVivien Didelot vlan.valid = false; 1474425d2d37SVivien Didelot 1475fad09c73SVivien Didelot do { 1476f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1477fad09c73SVivien Didelot if (err) 14787095a4c4SVivien Didelot return err; 1479fad09c73SVivien Didelot 1480fad09c73SVivien Didelot if (!vlan.valid) 1481fad09c73SVivien Didelot break; 1482fad09c73SVivien Didelot 1483fad09c73SVivien Didelot if (vlan.vid > vid_end) 1484fad09c73SVivien Didelot break; 1485fad09c73SVivien Didelot 1486370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1487fad09c73SVivien Didelot if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i)) 1488fad09c73SVivien Didelot continue; 1489fad09c73SVivien Didelot 149068bb8ea8SVivien Didelot if (!dsa_to_port(ds, i)->slave) 149166e2809dSAndrew Lunn continue; 149266e2809dSAndrew Lunn 1493bd00e053SVivien Didelot if (vlan.member[i] == 14947ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1495fad09c73SVivien Didelot continue; 1496fad09c73SVivien Didelot 1497c8652c83SVivien Didelot if (dsa_to_port(ds, i)->bridge_dev == 149868bb8ea8SVivien Didelot dsa_to_port(ds, port)->bridge_dev) 1499fad09c73SVivien Didelot break; /* same bridge, check next VLAN */ 1500fad09c73SVivien Didelot 1501c8652c83SVivien Didelot if (!dsa_to_port(ds, i)->bridge_dev) 150266e2809dSAndrew Lunn continue; 150366e2809dSAndrew Lunn 1504743fcc28SAndrew Lunn dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n", 1505743fcc28SAndrew Lunn port, vlan.vid, i, 1506c8652c83SVivien Didelot netdev_name(dsa_to_port(ds, i)->bridge_dev)); 15077095a4c4SVivien Didelot return -EOPNOTSUPP; 1508fad09c73SVivien Didelot } 1509fad09c73SVivien Didelot } while (vlan.vid < vid_end); 1510fad09c73SVivien Didelot 15117095a4c4SVivien Didelot return 0; 1512fad09c73SVivien Didelot } 1513fad09c73SVivien Didelot 1514fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, 1515fad09c73SVivien Didelot bool vlan_filtering) 1516fad09c73SVivien Didelot { 151704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 151881c6edb2SVivien Didelot u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE : 151981c6edb2SVivien Didelot MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED; 15200e7b9925SAndrew Lunn int err; 1521fad09c73SVivien Didelot 15223cf3c846SVivien Didelot if (!chip->info->max_vid) 1523fad09c73SVivien Didelot return -EOPNOTSUPP; 1524fad09c73SVivien Didelot 1525c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1526385a0995SVivien Didelot err = mv88e6xxx_port_set_8021q_mode(chip, port, mode); 1527c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1528fad09c73SVivien Didelot 15290e7b9925SAndrew Lunn return err; 1530fad09c73SVivien Didelot } 1531fad09c73SVivien Didelot 1532fad09c73SVivien Didelot static int 1533fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, 153480e02360SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1535fad09c73SVivien Didelot { 153604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1537fad09c73SVivien Didelot int err; 1538fad09c73SVivien Didelot 15393cf3c846SVivien Didelot if (!chip->info->max_vid) 1540fad09c73SVivien Didelot return -EOPNOTSUPP; 1541fad09c73SVivien Didelot 1542fad09c73SVivien Didelot /* If the requested port doesn't belong to the same bridge as the VLAN 1543fad09c73SVivien Didelot * members, do not support it (yet) and fallback to software VLAN. 1544fad09c73SVivien Didelot */ 15457095a4c4SVivien Didelot mv88e6xxx_reg_lock(chip); 1546fad09c73SVivien Didelot err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin, 1547fad09c73SVivien Didelot vlan->vid_end); 15487095a4c4SVivien Didelot mv88e6xxx_reg_unlock(chip); 1549fad09c73SVivien Didelot 1550fad09c73SVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 1551fad09c73SVivien Didelot * so skip the prepare phase. 1552fad09c73SVivien Didelot */ 15537095a4c4SVivien Didelot return err; 1554fad09c73SVivien Didelot } 1555fad09c73SVivien Didelot 1556a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, 1557a4c93ae1SAndrew Lunn const unsigned char *addr, u16 vid, 1558a4c93ae1SAndrew Lunn u8 state) 1559a4c93ae1SAndrew Lunn { 1560a4c93ae1SAndrew Lunn struct mv88e6xxx_atu_entry entry; 15615ef8d249SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 15625ef8d249SVivien Didelot u16 fid; 1563a4c93ae1SAndrew Lunn int err; 1564a4c93ae1SAndrew Lunn 1565a4c93ae1SAndrew Lunn /* Null VLAN ID corresponds to the port private database */ 15665ef8d249SVivien Didelot if (vid == 0) { 15675ef8d249SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &fid); 1568a4c93ae1SAndrew Lunn if (err) 1569a4c93ae1SAndrew Lunn return err; 15705ef8d249SVivien Didelot } else { 15715ef8d249SVivien Didelot vlan.vid = vid - 1; 15725ef8d249SVivien Didelot vlan.valid = false; 15735ef8d249SVivien Didelot 15745ef8d249SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 15755ef8d249SVivien Didelot if (err) 15765ef8d249SVivien Didelot return err; 15775ef8d249SVivien Didelot 15785ef8d249SVivien Didelot /* switchdev expects -EOPNOTSUPP to honor software VLANs */ 15795ef8d249SVivien Didelot if (vlan.vid != vid || !vlan.valid) 15805ef8d249SVivien Didelot return -EOPNOTSUPP; 15815ef8d249SVivien Didelot 15825ef8d249SVivien Didelot fid = vlan.fid; 15835ef8d249SVivien Didelot } 1584a4c93ae1SAndrew Lunn 1585d8291a95SVivien Didelot entry.state = 0; 1586a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 1587a4c93ae1SAndrew Lunn eth_addr_dec(entry.mac); 1588a4c93ae1SAndrew Lunn 15895ef8d249SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry); 1590a4c93ae1SAndrew Lunn if (err) 1591a4c93ae1SAndrew Lunn return err; 1592a4c93ae1SAndrew Lunn 1593a4c93ae1SAndrew Lunn /* Initialize a fresh ATU entry if it isn't found */ 1594d8291a95SVivien Didelot if (!entry.state || !ether_addr_equal(entry.mac, addr)) { 1595a4c93ae1SAndrew Lunn memset(&entry, 0, sizeof(entry)); 1596a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 1597a4c93ae1SAndrew Lunn } 1598a4c93ae1SAndrew Lunn 1599a4c93ae1SAndrew Lunn /* Purge the ATU entry only if no port is using it anymore */ 1600d8291a95SVivien Didelot if (!state) { 1601a4c93ae1SAndrew Lunn entry.portvec &= ~BIT(port); 1602a4c93ae1SAndrew Lunn if (!entry.portvec) 1603d8291a95SVivien Didelot entry.state = 0; 1604a4c93ae1SAndrew Lunn } else { 1605a4c93ae1SAndrew Lunn entry.portvec |= BIT(port); 1606a4c93ae1SAndrew Lunn entry.state = state; 1607a4c93ae1SAndrew Lunn } 1608a4c93ae1SAndrew Lunn 16095ef8d249SVivien Didelot return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry); 1610a4c93ae1SAndrew Lunn } 1611a4c93ae1SAndrew Lunn 1612da7dc875SVivien Didelot static int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port, 1613da7dc875SVivien Didelot const struct mv88e6xxx_policy *policy) 1614da7dc875SVivien Didelot { 1615da7dc875SVivien Didelot enum mv88e6xxx_policy_mapping mapping = policy->mapping; 1616da7dc875SVivien Didelot enum mv88e6xxx_policy_action action = policy->action; 1617da7dc875SVivien Didelot const u8 *addr = policy->addr; 1618da7dc875SVivien Didelot u16 vid = policy->vid; 1619da7dc875SVivien Didelot u8 state; 1620da7dc875SVivien Didelot int err; 1621da7dc875SVivien Didelot int id; 1622da7dc875SVivien Didelot 1623da7dc875SVivien Didelot if (!chip->info->ops->port_set_policy) 1624da7dc875SVivien Didelot return -EOPNOTSUPP; 1625da7dc875SVivien Didelot 1626da7dc875SVivien Didelot switch (mapping) { 1627da7dc875SVivien Didelot case MV88E6XXX_POLICY_MAPPING_DA: 1628da7dc875SVivien Didelot case MV88E6XXX_POLICY_MAPPING_SA: 1629da7dc875SVivien Didelot if (action == MV88E6XXX_POLICY_ACTION_NORMAL) 1630da7dc875SVivien Didelot state = 0; /* Dissociate the port and address */ 1631da7dc875SVivien Didelot else if (action == MV88E6XXX_POLICY_ACTION_DISCARD && 1632da7dc875SVivien Didelot is_multicast_ether_addr(addr)) 1633da7dc875SVivien Didelot state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY; 1634da7dc875SVivien Didelot else if (action == MV88E6XXX_POLICY_ACTION_DISCARD && 1635da7dc875SVivien Didelot is_unicast_ether_addr(addr)) 1636da7dc875SVivien Didelot state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY; 1637da7dc875SVivien Didelot else 1638da7dc875SVivien Didelot return -EOPNOTSUPP; 1639da7dc875SVivien Didelot 1640da7dc875SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 1641da7dc875SVivien Didelot state); 1642da7dc875SVivien Didelot if (err) 1643da7dc875SVivien Didelot return err; 1644da7dc875SVivien Didelot break; 1645da7dc875SVivien Didelot default: 1646da7dc875SVivien Didelot return -EOPNOTSUPP; 1647da7dc875SVivien Didelot } 1648da7dc875SVivien Didelot 1649da7dc875SVivien Didelot /* Skip the port's policy clearing if the mapping is still in use */ 1650da7dc875SVivien Didelot if (action == MV88E6XXX_POLICY_ACTION_NORMAL) 1651da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 1652da7dc875SVivien Didelot if (policy->port == port && 1653da7dc875SVivien Didelot policy->mapping == mapping && 1654da7dc875SVivien Didelot policy->action != action) 1655da7dc875SVivien Didelot return 0; 1656da7dc875SVivien Didelot 1657da7dc875SVivien Didelot return chip->info->ops->port_set_policy(chip, port, mapping, action); 1658da7dc875SVivien Didelot } 1659da7dc875SVivien Didelot 1660da7dc875SVivien Didelot static int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port, 1661da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs) 1662da7dc875SVivien Didelot { 1663da7dc875SVivien Didelot struct ethhdr *mac_entry = &fs->h_u.ether_spec; 1664da7dc875SVivien Didelot struct ethhdr *mac_mask = &fs->m_u.ether_spec; 1665da7dc875SVivien Didelot enum mv88e6xxx_policy_mapping mapping; 1666da7dc875SVivien Didelot enum mv88e6xxx_policy_action action; 1667da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 1668da7dc875SVivien Didelot u16 vid = 0; 1669da7dc875SVivien Didelot u8 *addr; 1670da7dc875SVivien Didelot int err; 1671da7dc875SVivien Didelot int id; 1672da7dc875SVivien Didelot 1673da7dc875SVivien Didelot if (fs->location != RX_CLS_LOC_ANY) 1674da7dc875SVivien Didelot return -EINVAL; 1675da7dc875SVivien Didelot 1676da7dc875SVivien Didelot if (fs->ring_cookie == RX_CLS_FLOW_DISC) 1677da7dc875SVivien Didelot action = MV88E6XXX_POLICY_ACTION_DISCARD; 1678da7dc875SVivien Didelot else 1679da7dc875SVivien Didelot return -EOPNOTSUPP; 1680da7dc875SVivien Didelot 1681da7dc875SVivien Didelot switch (fs->flow_type & ~FLOW_EXT) { 1682da7dc875SVivien Didelot case ETHER_FLOW: 1683da7dc875SVivien Didelot if (!is_zero_ether_addr(mac_mask->h_dest) && 1684da7dc875SVivien Didelot is_zero_ether_addr(mac_mask->h_source)) { 1685da7dc875SVivien Didelot mapping = MV88E6XXX_POLICY_MAPPING_DA; 1686da7dc875SVivien Didelot addr = mac_entry->h_dest; 1687da7dc875SVivien Didelot } else if (is_zero_ether_addr(mac_mask->h_dest) && 1688da7dc875SVivien Didelot !is_zero_ether_addr(mac_mask->h_source)) { 1689da7dc875SVivien Didelot mapping = MV88E6XXX_POLICY_MAPPING_SA; 1690da7dc875SVivien Didelot addr = mac_entry->h_source; 1691da7dc875SVivien Didelot } else { 1692da7dc875SVivien Didelot /* Cannot support DA and SA mapping in the same rule */ 1693da7dc875SVivien Didelot return -EOPNOTSUPP; 1694da7dc875SVivien Didelot } 1695da7dc875SVivien Didelot break; 1696da7dc875SVivien Didelot default: 1697da7dc875SVivien Didelot return -EOPNOTSUPP; 1698da7dc875SVivien Didelot } 1699da7dc875SVivien Didelot 1700da7dc875SVivien Didelot if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) { 1701da7dc875SVivien Didelot if (fs->m_ext.vlan_tci != 0xffff) 1702da7dc875SVivien Didelot return -EOPNOTSUPP; 1703da7dc875SVivien Didelot vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK; 1704da7dc875SVivien Didelot } 1705da7dc875SVivien Didelot 1706da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) { 1707da7dc875SVivien Didelot if (policy->port == port && policy->mapping == mapping && 1708da7dc875SVivien Didelot policy->action == action && policy->vid == vid && 1709da7dc875SVivien Didelot ether_addr_equal(policy->addr, addr)) 1710da7dc875SVivien Didelot return -EEXIST; 1711da7dc875SVivien Didelot } 1712da7dc875SVivien Didelot 1713da7dc875SVivien Didelot policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL); 1714da7dc875SVivien Didelot if (!policy) 1715da7dc875SVivien Didelot return -ENOMEM; 1716da7dc875SVivien Didelot 1717da7dc875SVivien Didelot fs->location = 0; 1718da7dc875SVivien Didelot err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff, 1719da7dc875SVivien Didelot GFP_KERNEL); 1720da7dc875SVivien Didelot if (err) { 1721da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 1722da7dc875SVivien Didelot return err; 1723da7dc875SVivien Didelot } 1724da7dc875SVivien Didelot 1725da7dc875SVivien Didelot memcpy(&policy->fs, fs, sizeof(*fs)); 1726da7dc875SVivien Didelot ether_addr_copy(policy->addr, addr); 1727da7dc875SVivien Didelot policy->mapping = mapping; 1728da7dc875SVivien Didelot policy->action = action; 1729da7dc875SVivien Didelot policy->port = port; 1730da7dc875SVivien Didelot policy->vid = vid; 1731da7dc875SVivien Didelot 1732da7dc875SVivien Didelot err = mv88e6xxx_policy_apply(chip, port, policy); 1733da7dc875SVivien Didelot if (err) { 1734da7dc875SVivien Didelot idr_remove(&chip->policies, fs->location); 1735da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 1736da7dc875SVivien Didelot return err; 1737da7dc875SVivien Didelot } 1738da7dc875SVivien Didelot 1739da7dc875SVivien Didelot return 0; 1740da7dc875SVivien Didelot } 1741da7dc875SVivien Didelot 1742da7dc875SVivien Didelot static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port, 1743da7dc875SVivien Didelot struct ethtool_rxnfc *rxnfc, u32 *rule_locs) 1744da7dc875SVivien Didelot { 1745da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs = &rxnfc->fs; 1746da7dc875SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1747da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 1748da7dc875SVivien Didelot int err; 1749da7dc875SVivien Didelot int id; 1750da7dc875SVivien Didelot 1751da7dc875SVivien Didelot mv88e6xxx_reg_lock(chip); 1752da7dc875SVivien Didelot 1753da7dc875SVivien Didelot switch (rxnfc->cmd) { 1754da7dc875SVivien Didelot case ETHTOOL_GRXCLSRLCNT: 1755da7dc875SVivien Didelot rxnfc->data = 0; 1756da7dc875SVivien Didelot rxnfc->data |= RX_CLS_LOC_SPECIAL; 1757da7dc875SVivien Didelot rxnfc->rule_cnt = 0; 1758da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 1759da7dc875SVivien Didelot if (policy->port == port) 1760da7dc875SVivien Didelot rxnfc->rule_cnt++; 1761da7dc875SVivien Didelot err = 0; 1762da7dc875SVivien Didelot break; 1763da7dc875SVivien Didelot case ETHTOOL_GRXCLSRULE: 1764da7dc875SVivien Didelot err = -ENOENT; 1765da7dc875SVivien Didelot policy = idr_find(&chip->policies, fs->location); 1766da7dc875SVivien Didelot if (policy) { 1767da7dc875SVivien Didelot memcpy(fs, &policy->fs, sizeof(*fs)); 1768da7dc875SVivien Didelot err = 0; 1769da7dc875SVivien Didelot } 1770da7dc875SVivien Didelot break; 1771da7dc875SVivien Didelot case ETHTOOL_GRXCLSRLALL: 1772da7dc875SVivien Didelot rxnfc->data = 0; 1773da7dc875SVivien Didelot rxnfc->rule_cnt = 0; 1774da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 1775da7dc875SVivien Didelot if (policy->port == port) 1776da7dc875SVivien Didelot rule_locs[rxnfc->rule_cnt++] = id; 1777da7dc875SVivien Didelot err = 0; 1778da7dc875SVivien Didelot break; 1779da7dc875SVivien Didelot default: 1780da7dc875SVivien Didelot err = -EOPNOTSUPP; 1781da7dc875SVivien Didelot break; 1782da7dc875SVivien Didelot } 1783da7dc875SVivien Didelot 1784da7dc875SVivien Didelot mv88e6xxx_reg_unlock(chip); 1785da7dc875SVivien Didelot 1786da7dc875SVivien Didelot return err; 1787da7dc875SVivien Didelot } 1788da7dc875SVivien Didelot 1789da7dc875SVivien Didelot static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port, 1790da7dc875SVivien Didelot struct ethtool_rxnfc *rxnfc) 1791da7dc875SVivien Didelot { 1792da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs = &rxnfc->fs; 1793da7dc875SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1794da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 1795da7dc875SVivien Didelot int err; 1796da7dc875SVivien Didelot 1797da7dc875SVivien Didelot mv88e6xxx_reg_lock(chip); 1798da7dc875SVivien Didelot 1799da7dc875SVivien Didelot switch (rxnfc->cmd) { 1800da7dc875SVivien Didelot case ETHTOOL_SRXCLSRLINS: 1801da7dc875SVivien Didelot err = mv88e6xxx_policy_insert(chip, port, fs); 1802da7dc875SVivien Didelot break; 1803da7dc875SVivien Didelot case ETHTOOL_SRXCLSRLDEL: 1804da7dc875SVivien Didelot err = -ENOENT; 1805da7dc875SVivien Didelot policy = idr_remove(&chip->policies, fs->location); 1806da7dc875SVivien Didelot if (policy) { 1807da7dc875SVivien Didelot policy->action = MV88E6XXX_POLICY_ACTION_NORMAL; 1808da7dc875SVivien Didelot err = mv88e6xxx_policy_apply(chip, port, policy); 1809da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 1810da7dc875SVivien Didelot } 1811da7dc875SVivien Didelot break; 1812da7dc875SVivien Didelot default: 1813da7dc875SVivien Didelot err = -EOPNOTSUPP; 1814da7dc875SVivien Didelot break; 1815da7dc875SVivien Didelot } 1816da7dc875SVivien Didelot 1817da7dc875SVivien Didelot mv88e6xxx_reg_unlock(chip); 1818da7dc875SVivien Didelot 1819da7dc875SVivien Didelot return err; 1820da7dc875SVivien Didelot } 1821da7dc875SVivien Didelot 182287fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port, 182387fa886eSAndrew Lunn u16 vid) 182487fa886eSAndrew Lunn { 182587fa886eSAndrew Lunn const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 182687fa886eSAndrew Lunn u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC; 182787fa886eSAndrew Lunn 182887fa886eSAndrew Lunn return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state); 182987fa886eSAndrew Lunn } 183087fa886eSAndrew Lunn 183187fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid) 183287fa886eSAndrew Lunn { 183387fa886eSAndrew Lunn int port; 183487fa886eSAndrew Lunn int err; 183587fa886eSAndrew Lunn 183687fa886eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 183787fa886eSAndrew Lunn err = mv88e6xxx_port_add_broadcast(chip, port, vid); 183887fa886eSAndrew Lunn if (err) 183987fa886eSAndrew Lunn return err; 184087fa886eSAndrew Lunn } 184187fa886eSAndrew Lunn 184287fa886eSAndrew Lunn return 0; 184387fa886eSAndrew Lunn } 184487fa886eSAndrew Lunn 1845b1ac6fb4SVivien Didelot static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port, 1846933b4425SRussell King u16 vid, u8 member, bool warn) 1847fad09c73SVivien Didelot { 1848b1ac6fb4SVivien Didelot const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 1849b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1850b1ac6fb4SVivien Didelot int i, err; 1851fad09c73SVivien Didelot 1852b1ac6fb4SVivien Didelot if (!vid) 1853b1ac6fb4SVivien Didelot return -EOPNOTSUPP; 1854b1ac6fb4SVivien Didelot 1855b1ac6fb4SVivien Didelot vlan.vid = vid - 1; 1856b1ac6fb4SVivien Didelot vlan.valid = false; 1857b1ac6fb4SVivien Didelot 1858b1ac6fb4SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1859fad09c73SVivien Didelot if (err) 1860fad09c73SVivien Didelot return err; 1861fad09c73SVivien Didelot 1862b1ac6fb4SVivien Didelot if (vlan.vid != vid || !vlan.valid) { 1863b1ac6fb4SVivien Didelot memset(&vlan, 0, sizeof(vlan)); 1864b1ac6fb4SVivien Didelot 1865b1ac6fb4SVivien Didelot err = mv88e6xxx_atu_new(chip, &vlan.fid); 1866b1ac6fb4SVivien Didelot if (err) 1867b1ac6fb4SVivien Didelot return err; 1868b1ac6fb4SVivien Didelot 1869b1ac6fb4SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 1870b1ac6fb4SVivien Didelot if (i == port) 1871b1ac6fb4SVivien Didelot vlan.member[i] = member; 1872b1ac6fb4SVivien Didelot else 1873b1ac6fb4SVivien Didelot vlan.member[i] = non_member; 1874b1ac6fb4SVivien Didelot 1875b1ac6fb4SVivien Didelot vlan.vid = vid; 18761cb9dfcaSRasmus Villemoes vlan.valid = true; 1877fad09c73SVivien Didelot 187887fa886eSAndrew Lunn err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 187987fa886eSAndrew Lunn if (err) 188087fa886eSAndrew Lunn return err; 188187fa886eSAndrew Lunn 1882b1ac6fb4SVivien Didelot err = mv88e6xxx_broadcast_setup(chip, vlan.vid); 1883b1ac6fb4SVivien Didelot if (err) 1884b1ac6fb4SVivien Didelot return err; 1885b1ac6fb4SVivien Didelot } else if (vlan.member[port] != member) { 1886b1ac6fb4SVivien Didelot vlan.member[port] = member; 1887b1ac6fb4SVivien Didelot 1888b1ac6fb4SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 1889b1ac6fb4SVivien Didelot if (err) 1890b1ac6fb4SVivien Didelot return err; 1891933b4425SRussell King } else if (warn) { 1892b1ac6fb4SVivien Didelot dev_info(chip->dev, "p%d: already a member of VLAN %d\n", 1893b1ac6fb4SVivien Didelot port, vid); 1894b1ac6fb4SVivien Didelot } 1895b1ac6fb4SVivien Didelot 1896b1ac6fb4SVivien Didelot return 0; 1897fad09c73SVivien Didelot } 1898fad09c73SVivien Didelot 1899fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, 190080e02360SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1901fad09c73SVivien Didelot { 190204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1903fad09c73SVivien Didelot bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; 1904fad09c73SVivien Didelot bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 1905933b4425SRussell King bool warn; 1906c91498e1SVivien Didelot u8 member; 1907fad09c73SVivien Didelot u16 vid; 1908fad09c73SVivien Didelot 19093cf3c846SVivien Didelot if (!chip->info->max_vid) 1910fad09c73SVivien Didelot return; 1911fad09c73SVivien Didelot 1912c91498e1SVivien Didelot if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 19137ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED; 1914c91498e1SVivien Didelot else if (untagged) 19157ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED; 1916c91498e1SVivien Didelot else 19177ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED; 1918c91498e1SVivien Didelot 1919933b4425SRussell King /* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port 1920933b4425SRussell King * and then the CPU port. Do not warn for duplicates for the CPU port. 1921933b4425SRussell King */ 1922933b4425SRussell King warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port); 1923933b4425SRussell King 1924c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1925fad09c73SVivien Didelot 1926fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) 1927933b4425SRussell King if (mv88e6xxx_port_vlan_join(chip, port, vid, member, warn)) 1928774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port, 1929fad09c73SVivien Didelot vid, untagged ? 'u' : 't'); 1930fad09c73SVivien Didelot 193177064f37SVivien Didelot if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end)) 1932774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to set PVID %d\n", port, 1933fad09c73SVivien Didelot vlan->vid_end); 1934fad09c73SVivien Didelot 1935c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1936fad09c73SVivien Didelot } 1937fad09c73SVivien Didelot 193852109892SVivien Didelot static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip, 1939fad09c73SVivien Didelot int port, u16 vid) 1940fad09c73SVivien Didelot { 1941b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1942fad09c73SVivien Didelot int i, err; 1943fad09c73SVivien Didelot 194452109892SVivien Didelot if (!vid) 194552109892SVivien Didelot return -EOPNOTSUPP; 194652109892SVivien Didelot 194752109892SVivien Didelot vlan.vid = vid - 1; 194852109892SVivien Didelot vlan.valid = false; 194952109892SVivien Didelot 195052109892SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1951fad09c73SVivien Didelot if (err) 1952fad09c73SVivien Didelot return err; 1953fad09c73SVivien Didelot 195452109892SVivien Didelot /* If the VLAN doesn't exist in hardware or the port isn't a member, 195552109892SVivien Didelot * tell switchdev that this VLAN is likely handled in software. 195652109892SVivien Didelot */ 195752109892SVivien Didelot if (vlan.vid != vid || !vlan.valid || 195852109892SVivien Didelot vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1959fad09c73SVivien Didelot return -EOPNOTSUPP; 1960fad09c73SVivien Didelot 19617ec60d6eSVivien Didelot vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 1962fad09c73SVivien Didelot 1963fad09c73SVivien Didelot /* keep the VLAN unless all ports are excluded */ 1964fad09c73SVivien Didelot vlan.valid = false; 1965370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 19667ec60d6eSVivien Didelot if (vlan.member[i] != 19677ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) { 1968fad09c73SVivien Didelot vlan.valid = true; 1969fad09c73SVivien Didelot break; 1970fad09c73SVivien Didelot } 1971fad09c73SVivien Didelot } 1972fad09c73SVivien Didelot 19730ad5daf6SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 1974fad09c73SVivien Didelot if (err) 1975fad09c73SVivien Didelot return err; 1976fad09c73SVivien Didelot 1977e606ca36SVivien Didelot return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); 1978fad09c73SVivien Didelot } 1979fad09c73SVivien Didelot 1980fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, 1981fad09c73SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1982fad09c73SVivien Didelot { 198304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1984fad09c73SVivien Didelot u16 pvid, vid; 1985fad09c73SVivien Didelot int err = 0; 1986fad09c73SVivien Didelot 19873cf3c846SVivien Didelot if (!chip->info->max_vid) 1988fad09c73SVivien Didelot return -EOPNOTSUPP; 1989fad09c73SVivien Didelot 1990c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1991fad09c73SVivien Didelot 199277064f37SVivien Didelot err = mv88e6xxx_port_get_pvid(chip, port, &pvid); 1993fad09c73SVivien Didelot if (err) 1994fad09c73SVivien Didelot goto unlock; 1995fad09c73SVivien Didelot 1996fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { 199752109892SVivien Didelot err = mv88e6xxx_port_vlan_leave(chip, port, vid); 1998fad09c73SVivien Didelot if (err) 1999fad09c73SVivien Didelot goto unlock; 2000fad09c73SVivien Didelot 2001fad09c73SVivien Didelot if (vid == pvid) { 200277064f37SVivien Didelot err = mv88e6xxx_port_set_pvid(chip, port, 0); 2003fad09c73SVivien Didelot if (err) 2004fad09c73SVivien Didelot goto unlock; 2005fad09c73SVivien Didelot } 2006fad09c73SVivien Didelot } 2007fad09c73SVivien Didelot 2008fad09c73SVivien Didelot unlock: 2009c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2010fad09c73SVivien Didelot 2011fad09c73SVivien Didelot return err; 2012fad09c73SVivien Didelot } 2013fad09c73SVivien Didelot 20141b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, 20156c2c1dcbSArkadi Sharshevsky const unsigned char *addr, u16 vid) 2016fad09c73SVivien Didelot { 201704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 20181b6dd556SArkadi Sharshevsky int err; 2019fad09c73SVivien Didelot 2020c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 20211b6dd556SArkadi Sharshevsky err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 20221b6dd556SArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 2023c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 20241b6dd556SArkadi Sharshevsky 20251b6dd556SArkadi Sharshevsky return err; 2026fad09c73SVivien Didelot } 2027fad09c73SVivien Didelot 2028fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, 20296c2c1dcbSArkadi Sharshevsky const unsigned char *addr, u16 vid) 2030fad09c73SVivien Didelot { 203104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 203283dabd1fSVivien Didelot int err; 2033fad09c73SVivien Didelot 2034c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2035d8291a95SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0); 2036c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2037fad09c73SVivien Didelot 203883dabd1fSVivien Didelot return err; 2039fad09c73SVivien Didelot } 2040fad09c73SVivien Didelot 204183dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, 2042fad09c73SVivien Didelot u16 fid, u16 vid, int port, 20432bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 2044fad09c73SVivien Didelot { 2045dabc1a96SVivien Didelot struct mv88e6xxx_atu_entry addr; 20462bedde1aSArkadi Sharshevsky bool is_static; 2047fad09c73SVivien Didelot int err; 2048fad09c73SVivien Didelot 2049d8291a95SVivien Didelot addr.state = 0; 2050dabc1a96SVivien Didelot eth_broadcast_addr(addr.mac); 2051fad09c73SVivien Didelot 2052fad09c73SVivien Didelot do { 2053dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); 2054fad09c73SVivien Didelot if (err) 205583dabd1fSVivien Didelot return err; 2056fad09c73SVivien Didelot 2057d8291a95SVivien Didelot if (!addr.state) 2058fad09c73SVivien Didelot break; 2059fad09c73SVivien Didelot 206001bd96c8SVivien Didelot if (addr.trunk || (addr.portvec & BIT(port)) == 0) 206183dabd1fSVivien Didelot continue; 2062fad09c73SVivien Didelot 206383dabd1fSVivien Didelot if (!is_unicast_ether_addr(addr.mac)) 206483dabd1fSVivien Didelot continue; 206583dabd1fSVivien Didelot 20662bedde1aSArkadi Sharshevsky is_static = (addr.state == 20672bedde1aSArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 20682bedde1aSArkadi Sharshevsky err = cb(addr.mac, vid, is_static, data); 206983dabd1fSVivien Didelot if (err) 207083dabd1fSVivien Didelot return err; 2071fad09c73SVivien Didelot } while (!is_broadcast_ether_addr(addr.mac)); 2072fad09c73SVivien Didelot 2073fad09c73SVivien Didelot return err; 2074fad09c73SVivien Didelot } 2075fad09c73SVivien Didelot 207683dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, 20772bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 207883dabd1fSVivien Didelot { 2079425d2d37SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 208083dabd1fSVivien Didelot u16 fid; 208183dabd1fSVivien Didelot int err; 208283dabd1fSVivien Didelot 208383dabd1fSVivien Didelot /* Dump port's default Filtering Information Database (VLAN ID 0) */ 2084b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &fid); 208583dabd1fSVivien Didelot if (err) 208683dabd1fSVivien Didelot return err; 208783dabd1fSVivien Didelot 20882bedde1aSArkadi Sharshevsky err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data); 208983dabd1fSVivien Didelot if (err) 209083dabd1fSVivien Didelot return err; 209183dabd1fSVivien Didelot 209283dabd1fSVivien Didelot /* Dump VLANs' Filtering Information Databases */ 2093425d2d37SVivien Didelot vlan.vid = chip->info->max_vid; 2094425d2d37SVivien Didelot vlan.valid = false; 2095425d2d37SVivien Didelot 209683dabd1fSVivien Didelot do { 2097f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 209883dabd1fSVivien Didelot if (err) 209983dabd1fSVivien Didelot return err; 210083dabd1fSVivien Didelot 210183dabd1fSVivien Didelot if (!vlan.valid) 210283dabd1fSVivien Didelot break; 210383dabd1fSVivien Didelot 210483dabd1fSVivien Didelot err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port, 21052bedde1aSArkadi Sharshevsky cb, data); 210683dabd1fSVivien Didelot if (err) 210783dabd1fSVivien Didelot return err; 21083cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 210983dabd1fSVivien Didelot 211083dabd1fSVivien Didelot return err; 211183dabd1fSVivien Didelot } 211283dabd1fSVivien Didelot 2113fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, 21142bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 2115fad09c73SVivien Didelot { 211604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2117fcf15367SVivien Didelot int err; 2118fad09c73SVivien Didelot 2119c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2120fcf15367SVivien Didelot err = mv88e6xxx_port_db_dump(chip, port, cb, data); 2121c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2122fcf15367SVivien Didelot 2123fcf15367SVivien Didelot return err; 2124fad09c73SVivien Didelot } 2125fad09c73SVivien Didelot 2126240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, 2127240ea3efSVivien Didelot struct net_device *br) 2128240ea3efSVivien Didelot { 2129ef2025ecSVivien Didelot struct dsa_switch *ds = chip->ds; 2130ef2025ecSVivien Didelot struct dsa_switch_tree *dst = ds->dst; 2131ef2025ecSVivien Didelot struct dsa_port *dp; 2132240ea3efSVivien Didelot int err; 2133240ea3efSVivien Didelot 2134ef2025ecSVivien Didelot list_for_each_entry(dp, &dst->ports, list) { 2135ef2025ecSVivien Didelot if (dp->bridge_dev == br) { 2136ef2025ecSVivien Didelot if (dp->ds == ds) { 2137ef2025ecSVivien Didelot /* This is a local bridge group member, 2138ef2025ecSVivien Didelot * remap its Port VLAN Map. 2139ef2025ecSVivien Didelot */ 2140ef2025ecSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, dp->index); 2141240ea3efSVivien Didelot if (err) 2142240ea3efSVivien Didelot return err; 2143ef2025ecSVivien Didelot } else { 2144ef2025ecSVivien Didelot /* This is an external bridge group member, 2145ef2025ecSVivien Didelot * remap its cross-chip Port VLAN Table entry. 2146ef2025ecSVivien Didelot */ 2147ef2025ecSVivien Didelot err = mv88e6xxx_pvt_map(chip, dp->ds->index, 2148ef2025ecSVivien Didelot dp->index); 2149e96a6e02SVivien Didelot if (err) 2150e96a6e02SVivien Didelot return err; 2151e96a6e02SVivien Didelot } 2152e96a6e02SVivien Didelot } 2153e96a6e02SVivien Didelot } 2154e96a6e02SVivien Didelot 2155240ea3efSVivien Didelot return 0; 2156240ea3efSVivien Didelot } 2157240ea3efSVivien Didelot 2158fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, 2159fae8a25eSVivien Didelot struct net_device *br) 2160fad09c73SVivien Didelot { 216104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2162240ea3efSVivien Didelot int err; 2163fad09c73SVivien Didelot 2164c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2165240ea3efSVivien Didelot err = mv88e6xxx_bridge_map(chip, br); 2166c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2167fad09c73SVivien Didelot 2168fad09c73SVivien Didelot return err; 2169fad09c73SVivien Didelot } 2170fad09c73SVivien Didelot 2171f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, 2172f123f2fbSVivien Didelot struct net_device *br) 2173fad09c73SVivien Didelot { 217404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2175fad09c73SVivien Didelot 2176c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2177240ea3efSVivien Didelot if (mv88e6xxx_bridge_map(chip, br) || 2178240ea3efSVivien Didelot mv88e6xxx_port_vlan_map(chip, port)) 2179240ea3efSVivien Didelot dev_err(ds->dev, "failed to remap in-chip Port VLAN\n"); 2180c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2181fad09c73SVivien Didelot } 2182fad09c73SVivien Didelot 2183aec5ac88SVivien Didelot static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev, 2184aec5ac88SVivien Didelot int port, struct net_device *br) 2185aec5ac88SVivien Didelot { 2186aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2187aec5ac88SVivien Didelot int err; 2188aec5ac88SVivien Didelot 2189c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2190aec5ac88SVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 2191c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2192aec5ac88SVivien Didelot 2193aec5ac88SVivien Didelot return err; 2194aec5ac88SVivien Didelot } 2195aec5ac88SVivien Didelot 2196aec5ac88SVivien Didelot static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev, 2197aec5ac88SVivien Didelot int port, struct net_device *br) 2198aec5ac88SVivien Didelot { 2199aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2200aec5ac88SVivien Didelot 2201c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2202aec5ac88SVivien Didelot if (mv88e6xxx_pvt_map(chip, dev, port)) 2203aec5ac88SVivien Didelot dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); 2204c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2205aec5ac88SVivien Didelot } 2206aec5ac88SVivien Didelot 220717e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip) 220817e708baSVivien Didelot { 220917e708baSVivien Didelot if (chip->info->ops->reset) 221017e708baSVivien Didelot return chip->info->ops->reset(chip); 221117e708baSVivien Didelot 221217e708baSVivien Didelot return 0; 221317e708baSVivien Didelot } 221417e708baSVivien Didelot 2215309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) 2216309eca6dSVivien Didelot { 2217309eca6dSVivien Didelot struct gpio_desc *gpiod = chip->reset; 2218309eca6dSVivien Didelot 2219309eca6dSVivien Didelot /* If there is a GPIO connected to the reset pin, toggle it */ 2220309eca6dSVivien Didelot if (gpiod) { 2221309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 1); 2222309eca6dSVivien Didelot usleep_range(10000, 20000); 2223309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 0); 2224309eca6dSVivien Didelot usleep_range(10000, 20000); 2225309eca6dSVivien Didelot } 2226309eca6dSVivien Didelot } 2227309eca6dSVivien Didelot 22284ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip) 22294ac4b5a6SVivien Didelot { 22304ac4b5a6SVivien Didelot int i, err; 22314ac4b5a6SVivien Didelot 22324ac4b5a6SVivien Didelot /* Set all ports to the Disabled state */ 22334ac4b5a6SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 2234f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED); 22354ac4b5a6SVivien Didelot if (err) 22364ac4b5a6SVivien Didelot return err; 22374ac4b5a6SVivien Didelot } 22384ac4b5a6SVivien Didelot 22394ac4b5a6SVivien Didelot /* Wait for transmit queues to drain, 22404ac4b5a6SVivien Didelot * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps. 22414ac4b5a6SVivien Didelot */ 22424ac4b5a6SVivien Didelot usleep_range(2000, 4000); 22434ac4b5a6SVivien Didelot 22444ac4b5a6SVivien Didelot return 0; 22454ac4b5a6SVivien Didelot } 22464ac4b5a6SVivien Didelot 2247fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip) 2248fad09c73SVivien Didelot { 2249a935c052SVivien Didelot int err; 2250fad09c73SVivien Didelot 22514ac4b5a6SVivien Didelot err = mv88e6xxx_disable_ports(chip); 22520e7b9925SAndrew Lunn if (err) 22530e7b9925SAndrew Lunn return err; 2254fad09c73SVivien Didelot 2255309eca6dSVivien Didelot mv88e6xxx_hardware_reset(chip); 2256fad09c73SVivien Didelot 225717e708baSVivien Didelot return mv88e6xxx_software_reset(chip); 2258fad09c73SVivien Didelot } 2259fad09c73SVivien Didelot 22604314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, 226131bef4e9SVivien Didelot enum mv88e6xxx_frame_mode frame, 226231bef4e9SVivien Didelot enum mv88e6xxx_egress_mode egress, u16 etype) 226356995cbcSAndrew Lunn { 226456995cbcSAndrew Lunn int err; 226556995cbcSAndrew Lunn 22664314557cSVivien Didelot if (!chip->info->ops->port_set_frame_mode) 22674314557cSVivien Didelot return -EOPNOTSUPP; 22684314557cSVivien Didelot 22694314557cSVivien Didelot err = mv88e6xxx_port_set_egress_mode(chip, port, egress); 227056995cbcSAndrew Lunn if (err) 227156995cbcSAndrew Lunn return err; 227256995cbcSAndrew Lunn 22734314557cSVivien Didelot err = chip->info->ops->port_set_frame_mode(chip, port, frame); 22744314557cSVivien Didelot if (err) 22754314557cSVivien Didelot return err; 22764314557cSVivien Didelot 22774314557cSVivien Didelot if (chip->info->ops->port_set_ether_type) 22784314557cSVivien Didelot return chip->info->ops->port_set_ether_type(chip, port, etype); 22794314557cSVivien Didelot 22804314557cSVivien Didelot return 0; 22814314557cSVivien Didelot } 22824314557cSVivien Didelot 22834314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port) 22844314557cSVivien Didelot { 22854314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL, 228631bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 2287b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 22884314557cSVivien Didelot } 22894314557cSVivien Didelot 22904314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port) 22914314557cSVivien Didelot { 22924314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA, 229331bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 2294b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 22954314557cSVivien Didelot } 22964314557cSVivien Didelot 22974314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port) 22984314557cSVivien Didelot { 22994314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, 23004314557cSVivien Didelot MV88E6XXX_FRAME_MODE_ETHERTYPE, 230131bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_ETHERTYPE, 230231bef4e9SVivien Didelot ETH_P_EDSA); 23034314557cSVivien Didelot } 23044314557cSVivien Didelot 23054314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port) 23064314557cSVivien Didelot { 23074314557cSVivien Didelot if (dsa_is_dsa_port(chip->ds, port)) 23084314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 23094314557cSVivien Didelot 23102b3e9891SVivien Didelot if (dsa_is_user_port(chip->ds, port)) 23114314557cSVivien Didelot return mv88e6xxx_set_port_mode_normal(chip, port); 23124314557cSVivien Didelot 23134314557cSVivien Didelot /* Setup CPU port mode depending on its supported tag format */ 23144314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA) 23154314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 23164314557cSVivien Didelot 23174314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA) 23184314557cSVivien Didelot return mv88e6xxx_set_port_mode_edsa(chip, port); 23194314557cSVivien Didelot 23204314557cSVivien Didelot return -EINVAL; 23214314557cSVivien Didelot } 23224314557cSVivien Didelot 2323ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port) 2324ea698f4fSVivien Didelot { 2325ea698f4fSVivien Didelot bool message = dsa_is_dsa_port(chip->ds, port); 2326ea698f4fSVivien Didelot 2327ea698f4fSVivien Didelot return mv88e6xxx_port_set_message_port(chip, port, message); 2328ea698f4fSVivien Didelot } 2329ea698f4fSVivien Didelot 2330601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) 2331601aeed3SVivien Didelot { 23323ee50cbfSVivien Didelot struct dsa_switch *ds = chip->ds; 2333407308f6SDavid S. Miller bool flood; 2334601aeed3SVivien Didelot 2335407308f6SDavid S. Miller /* Upstream ports flood frames with unknown unicast or multicast DA */ 2336407308f6SDavid S. Miller flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port); 2337407308f6SDavid S. Miller if (chip->info->ops->port_set_egress_floods) 2338407308f6SDavid S. Miller return chip->info->ops->port_set_egress_floods(chip, port, 2339407308f6SDavid S. Miller flood, flood); 2340407308f6SDavid S. Miller 2341601aeed3SVivien Didelot return 0; 2342601aeed3SVivien Didelot } 2343601aeed3SVivien Didelot 234445de77ffSVivien Didelot static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id) 234545de77ffSVivien Didelot { 234645de77ffSVivien Didelot struct mv88e6xxx_port *mvp = dev_id; 234745de77ffSVivien Didelot struct mv88e6xxx_chip *chip = mvp->chip; 234845de77ffSVivien Didelot irqreturn_t ret = IRQ_NONE; 234945de77ffSVivien Didelot int port = mvp->port; 235045de77ffSVivien Didelot u8 lane; 235145de77ffSVivien Didelot 235245de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 235345de77ffSVivien Didelot lane = mv88e6xxx_serdes_get_lane(chip, port); 235445de77ffSVivien Didelot if (lane) 235545de77ffSVivien Didelot ret = mv88e6xxx_serdes_irq_status(chip, port, lane); 235645de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 235745de77ffSVivien Didelot 235845de77ffSVivien Didelot return ret; 235945de77ffSVivien Didelot } 236045de77ffSVivien Didelot 236145de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port, 236245de77ffSVivien Didelot u8 lane) 236345de77ffSVivien Didelot { 236445de77ffSVivien Didelot struct mv88e6xxx_port *dev_id = &chip->ports[port]; 236545de77ffSVivien Didelot unsigned int irq; 236645de77ffSVivien Didelot int err; 236745de77ffSVivien Didelot 236845de77ffSVivien Didelot /* Nothing to request if this SERDES port has no IRQ */ 236945de77ffSVivien Didelot irq = mv88e6xxx_serdes_irq_mapping(chip, port); 237045de77ffSVivien Didelot if (!irq) 237145de77ffSVivien Didelot return 0; 237245de77ffSVivien Didelot 2373e6f2f6b8SAndrew Lunn snprintf(dev_id->serdes_irq_name, sizeof(dev_id->serdes_irq_name), 2374e6f2f6b8SAndrew Lunn "mv88e6xxx-%s-serdes-%d", dev_name(chip->dev), port); 2375e6f2f6b8SAndrew Lunn 237645de77ffSVivien Didelot /* Requesting the IRQ will trigger IRQ callbacks, so release the lock */ 237745de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 237845de77ffSVivien Didelot err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn, 2379e6f2f6b8SAndrew Lunn IRQF_ONESHOT, dev_id->serdes_irq_name, 2380e6f2f6b8SAndrew Lunn dev_id); 238145de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 238245de77ffSVivien Didelot if (err) 238345de77ffSVivien Didelot return err; 238445de77ffSVivien Didelot 238545de77ffSVivien Didelot dev_id->serdes_irq = irq; 238645de77ffSVivien Didelot 238745de77ffSVivien Didelot return mv88e6xxx_serdes_irq_enable(chip, port, lane); 238845de77ffSVivien Didelot } 238945de77ffSVivien Didelot 239045de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port, 239145de77ffSVivien Didelot u8 lane) 239245de77ffSVivien Didelot { 239345de77ffSVivien Didelot struct mv88e6xxx_port *dev_id = &chip->ports[port]; 239445de77ffSVivien Didelot unsigned int irq = dev_id->serdes_irq; 239545de77ffSVivien Didelot int err; 239645de77ffSVivien Didelot 239745de77ffSVivien Didelot /* Nothing to free if no IRQ has been requested */ 239845de77ffSVivien Didelot if (!irq) 239945de77ffSVivien Didelot return 0; 240045de77ffSVivien Didelot 240145de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_disable(chip, port, lane); 240245de77ffSVivien Didelot 240345de77ffSVivien Didelot /* Freeing the IRQ will trigger IRQ callbacks, so release the lock */ 240445de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 240545de77ffSVivien Didelot free_irq(irq, dev_id); 240645de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 240745de77ffSVivien Didelot 240845de77ffSVivien Didelot dev_id->serdes_irq = 0; 240945de77ffSVivien Didelot 241045de77ffSVivien Didelot return err; 241145de77ffSVivien Didelot } 241245de77ffSVivien Didelot 24136d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, 24146d91782fSAndrew Lunn bool on) 24156d91782fSAndrew Lunn { 2416dc272f60SVivien Didelot u8 lane; 2417fc0bc019SVivien Didelot int err; 24186d91782fSAndrew Lunn 2419dc272f60SVivien Didelot lane = mv88e6xxx_serdes_get_lane(chip, port); 2420dc272f60SVivien Didelot if (!lane) 2421523a8904SVivien Didelot return 0; 2422fc0bc019SVivien Didelot 2423fc0bc019SVivien Didelot if (on) { 2424dc272f60SVivien Didelot err = mv88e6xxx_serdes_power_up(chip, port, lane); 2425fc0bc019SVivien Didelot if (err) 2426fc0bc019SVivien Didelot return err; 2427fc0bc019SVivien Didelot 242845de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_request(chip, port, lane); 2429fc0bc019SVivien Didelot } else { 243045de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_free(chip, port, lane); 243145de77ffSVivien Didelot if (err) 243245de77ffSVivien Didelot return err; 2433fc0bc019SVivien Didelot 2434dc272f60SVivien Didelot err = mv88e6xxx_serdes_power_down(chip, port, lane); 2435fc0bc019SVivien Didelot } 2436fc0bc019SVivien Didelot 2437fc0bc019SVivien Didelot return err; 24386d91782fSAndrew Lunn } 24396d91782fSAndrew Lunn 2440fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) 2441fa371c80SVivien Didelot { 2442fa371c80SVivien Didelot struct dsa_switch *ds = chip->ds; 2443fa371c80SVivien Didelot int upstream_port; 2444fa371c80SVivien Didelot int err; 2445fa371c80SVivien Didelot 244607073c79SVivien Didelot upstream_port = dsa_upstream_port(ds, port); 2447fa371c80SVivien Didelot if (chip->info->ops->port_set_upstream_port) { 2448fa371c80SVivien Didelot err = chip->info->ops->port_set_upstream_port(chip, port, 2449fa371c80SVivien Didelot upstream_port); 2450fa371c80SVivien Didelot if (err) 2451fa371c80SVivien Didelot return err; 2452fa371c80SVivien Didelot } 2453fa371c80SVivien Didelot 24540ea54ddaSVivien Didelot if (port == upstream_port) { 24550ea54ddaSVivien Didelot if (chip->info->ops->set_cpu_port) { 24560ea54ddaSVivien Didelot err = chip->info->ops->set_cpu_port(chip, 24570ea54ddaSVivien Didelot upstream_port); 24580ea54ddaSVivien Didelot if (err) 24590ea54ddaSVivien Didelot return err; 24600ea54ddaSVivien Didelot } 24610ea54ddaSVivien Didelot 24620ea54ddaSVivien Didelot if (chip->info->ops->set_egress_port) { 24630ea54ddaSVivien Didelot err = chip->info->ops->set_egress_port(chip, 24645c74c54cSIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS, 24655c74c54cSIwan R Timmer upstream_port); 24665c74c54cSIwan R Timmer if (err) 24675c74c54cSIwan R Timmer return err; 24685c74c54cSIwan R Timmer 24695c74c54cSIwan R Timmer err = chip->info->ops->set_egress_port(chip, 24705c74c54cSIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS, 24710ea54ddaSVivien Didelot upstream_port); 24720ea54ddaSVivien Didelot if (err) 24730ea54ddaSVivien Didelot return err; 24740ea54ddaSVivien Didelot } 24750ea54ddaSVivien Didelot } 24760ea54ddaSVivien Didelot 2477fa371c80SVivien Didelot return 0; 2478fa371c80SVivien Didelot } 2479fa371c80SVivien Didelot 2480fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) 2481fad09c73SVivien Didelot { 2482fad09c73SVivien Didelot struct dsa_switch *ds = chip->ds; 24830e7b9925SAndrew Lunn int err; 2484fad09c73SVivien Didelot u16 reg; 2485fad09c73SVivien Didelot 24867b898469SAndrew Lunn chip->ports[port].chip = chip; 24877b898469SAndrew Lunn chip->ports[port].port = port; 24887b898469SAndrew Lunn 2489d78343d2SVivien Didelot /* MAC Forcing register: don't force link, speed, duplex or flow control 2490d78343d2SVivien Didelot * state to any particular values on physical ports, but force the CPU 2491d78343d2SVivien Didelot * port and all DSA ports to their maximum bandwidth and full duplex. 2492fad09c73SVivien Didelot */ 2493d78343d2SVivien Didelot if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) 2494d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP, 2495d78343d2SVivien Didelot SPEED_MAX, DUPLEX_FULL, 249654186b91SAndrew Lunn PAUSE_OFF, 2497d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 2498fad09c73SVivien Didelot else 2499d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, 2500d78343d2SVivien Didelot SPEED_UNFORCED, DUPLEX_UNFORCED, 250154186b91SAndrew Lunn PAUSE_ON, 2502d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 25030e7b9925SAndrew Lunn if (err) 25040e7b9925SAndrew Lunn return err; 2505fad09c73SVivien Didelot 2506fad09c73SVivien Didelot /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, 2507fad09c73SVivien Didelot * disable Header mode, enable IGMP/MLD snooping, disable VLAN 2508fad09c73SVivien Didelot * tunneling, determine priority by looking at 802.1p and IP 2509fad09c73SVivien Didelot * priority fields (IP prio has precedence), and set STP state 2510fad09c73SVivien Didelot * to Forwarding. 2511fad09c73SVivien Didelot * 2512fad09c73SVivien Didelot * If this is the CPU link, use DSA or EDSA tagging depending 2513fad09c73SVivien Didelot * on which tagging mode was configured. 2514fad09c73SVivien Didelot * 2515fad09c73SVivien Didelot * If this is a link to another switch, use DSA tagging mode. 2516fad09c73SVivien Didelot * 2517fad09c73SVivien Didelot * If this is the upstream port for this switch, enable 2518fad09c73SVivien Didelot * forwarding of unknown unicasts and multicasts. 2519fad09c73SVivien Didelot */ 2520a89b433bSVivien Didelot reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP | 2521a89b433bSVivien Didelot MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | 2522a89b433bSVivien Didelot MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 2523a89b433bSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 25240e7b9925SAndrew Lunn if (err) 25250e7b9925SAndrew Lunn return err; 252656995cbcSAndrew Lunn 2527601aeed3SVivien Didelot err = mv88e6xxx_setup_port_mode(chip, port); 252856995cbcSAndrew Lunn if (err) 252956995cbcSAndrew Lunn return err; 2530fad09c73SVivien Didelot 2531601aeed3SVivien Didelot err = mv88e6xxx_setup_egress_floods(chip, port); 25324314557cSVivien Didelot if (err) 25334314557cSVivien Didelot return err; 25344314557cSVivien Didelot 2535fad09c73SVivien Didelot /* Port Control 2: don't force a good FCS, set the maximum frame size to 2536fad09c73SVivien Didelot * 10240 bytes, disable 802.1q tags checking, don't discard tagged or 2537fad09c73SVivien Didelot * untagged frames on this port, do a destination address lookup on all 2538fad09c73SVivien Didelot * received packets as usual, disable ARP mirroring and don't send a 2539fad09c73SVivien Didelot * copy of all transmitted/received frames on this port to the CPU. 2540fad09c73SVivien Didelot */ 2541a23b2961SAndrew Lunn err = mv88e6xxx_port_set_map_da(chip, port); 2542a23b2961SAndrew Lunn if (err) 2543a23b2961SAndrew Lunn return err; 2544a23b2961SAndrew Lunn 2545fa371c80SVivien Didelot err = mv88e6xxx_setup_upstream_port(chip, port); 25460e7b9925SAndrew Lunn if (err) 25470e7b9925SAndrew Lunn return err; 2548fad09c73SVivien Didelot 2549a23b2961SAndrew Lunn err = mv88e6xxx_port_set_8021q_mode(chip, port, 255081c6edb2SVivien Didelot MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED); 2551a23b2961SAndrew Lunn if (err) 2552a23b2961SAndrew Lunn return err; 2553a23b2961SAndrew Lunn 2554cd782656SVivien Didelot if (chip->info->ops->port_set_jumbo_size) { 2555cd782656SVivien Didelot err = chip->info->ops->port_set_jumbo_size(chip, port, 10240); 25565f436666SAndrew Lunn if (err) 25575f436666SAndrew Lunn return err; 25585f436666SAndrew Lunn } 25595f436666SAndrew Lunn 2560fad09c73SVivien Didelot /* Port Association Vector: when learning source addresses 2561fad09c73SVivien Didelot * of packets, add the address to the address database using 2562fad09c73SVivien Didelot * a port bitmap that has only the bit for this port set and 2563fad09c73SVivien Didelot * the other bits clear. 2564fad09c73SVivien Didelot */ 2565fad09c73SVivien Didelot reg = 1 << port; 2566fad09c73SVivien Didelot /* Disable learning for CPU port */ 2567fad09c73SVivien Didelot if (dsa_is_cpu_port(ds, port)) 2568fad09c73SVivien Didelot reg = 0; 2569fad09c73SVivien Didelot 25702a4614e4SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, 25712a4614e4SVivien Didelot reg); 25720e7b9925SAndrew Lunn if (err) 25730e7b9925SAndrew Lunn return err; 2574fad09c73SVivien Didelot 2575fad09c73SVivien Didelot /* Egress rate control 2: disable egress rate control. */ 25762cb8cb14SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2, 25772cb8cb14SVivien Didelot 0x0000); 25780e7b9925SAndrew Lunn if (err) 25790e7b9925SAndrew Lunn return err; 2580fad09c73SVivien Didelot 25810898432cSVivien Didelot if (chip->info->ops->port_pause_limit) { 25820898432cSVivien Didelot err = chip->info->ops->port_pause_limit(chip, port, 0, 0); 2583b35d322aSAndrew Lunn if (err) 2584b35d322aSAndrew Lunn return err; 2585b35d322aSAndrew Lunn } 2586b35d322aSAndrew Lunn 2587c8c94891SVivien Didelot if (chip->info->ops->port_disable_learn_limit) { 2588c8c94891SVivien Didelot err = chip->info->ops->port_disable_learn_limit(chip, port); 2589c8c94891SVivien Didelot if (err) 2590c8c94891SVivien Didelot return err; 2591c8c94891SVivien Didelot } 2592c8c94891SVivien Didelot 25939dbfb4e1SVivien Didelot if (chip->info->ops->port_disable_pri_override) { 25949dbfb4e1SVivien Didelot err = chip->info->ops->port_disable_pri_override(chip, port); 25950e7b9925SAndrew Lunn if (err) 25960e7b9925SAndrew Lunn return err; 2597ef0a7318SAndrew Lunn } 25982bbb33beSAndrew Lunn 2599ef0a7318SAndrew Lunn if (chip->info->ops->port_tag_remap) { 2600ef0a7318SAndrew Lunn err = chip->info->ops->port_tag_remap(chip, port); 26010e7b9925SAndrew Lunn if (err) 26020e7b9925SAndrew Lunn return err; 2603fad09c73SVivien Didelot } 2604fad09c73SVivien Didelot 2605ef70b111SAndrew Lunn if (chip->info->ops->port_egress_rate_limiting) { 2606ef70b111SAndrew Lunn err = chip->info->ops->port_egress_rate_limiting(chip, port); 26070e7b9925SAndrew Lunn if (err) 26080e7b9925SAndrew Lunn return err; 2609fad09c73SVivien Didelot } 2610fad09c73SVivien Didelot 2611121b8fe2SHubert Feurstein if (chip->info->ops->port_setup_message_port) { 2612121b8fe2SHubert Feurstein err = chip->info->ops->port_setup_message_port(chip, port); 26130e7b9925SAndrew Lunn if (err) 26140e7b9925SAndrew Lunn return err; 2615121b8fe2SHubert Feurstein } 2616fad09c73SVivien Didelot 2617fad09c73SVivien Didelot /* Port based VLAN map: give each port the same default address 2618fad09c73SVivien Didelot * database, and allow bidirectional communication between the 2619fad09c73SVivien Didelot * CPU and DSA port(s), and the other ports. 2620fad09c73SVivien Didelot */ 2621b4e48c50SVivien Didelot err = mv88e6xxx_port_set_fid(chip, port, 0); 26220e7b9925SAndrew Lunn if (err) 26230e7b9925SAndrew Lunn return err; 2624fad09c73SVivien Didelot 2625240ea3efSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, port); 26260e7b9925SAndrew Lunn if (err) 26270e7b9925SAndrew Lunn return err; 2628fad09c73SVivien Didelot 2629fad09c73SVivien Didelot /* Default VLAN ID and priority: don't set a default VLAN 2630fad09c73SVivien Didelot * ID, and set the default packet priority to zero. 2631fad09c73SVivien Didelot */ 2632b7929fb3SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0); 2633fad09c73SVivien Didelot } 2634fad09c73SVivien Didelot 263504aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port, 263604aca993SAndrew Lunn struct phy_device *phydev) 263704aca993SAndrew Lunn { 263804aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 2639523a8904SVivien Didelot int err; 264004aca993SAndrew Lunn 2641c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2642523a8904SVivien Didelot err = mv88e6xxx_serdes_power(chip, port, true); 2643c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 264404aca993SAndrew Lunn 264504aca993SAndrew Lunn return err; 264604aca993SAndrew Lunn } 264704aca993SAndrew Lunn 264875104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port) 264904aca993SAndrew Lunn { 265004aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 265104aca993SAndrew Lunn 2652c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2653523a8904SVivien Didelot if (mv88e6xxx_serdes_power(chip, port, false)) 2654523a8904SVivien Didelot dev_err(chip->dev, "failed to power off SERDES\n"); 2655c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 265604aca993SAndrew Lunn } 265704aca993SAndrew Lunn 26582cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, 26592cfcd964SVivien Didelot unsigned int ageing_time) 26602cfcd964SVivien Didelot { 266104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 26622cfcd964SVivien Didelot int err; 26632cfcd964SVivien Didelot 2664c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2665720c6343SVivien Didelot err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time); 2666c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 26672cfcd964SVivien Didelot 26682cfcd964SVivien Didelot return err; 26692cfcd964SVivien Didelot } 26702cfcd964SVivien Didelot 2671447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip) 2672fad09c73SVivien Didelot { 2673fad09c73SVivien Didelot int err; 2674fad09c73SVivien Didelot 2675de227387SAndrew Lunn /* Initialize the statistics unit */ 2676447b1bb8SVivien Didelot if (chip->info->ops->stats_set_histogram) { 2677447b1bb8SVivien Didelot err = chip->info->ops->stats_set_histogram(chip); 2678de227387SAndrew Lunn if (err) 2679de227387SAndrew Lunn return err; 2680447b1bb8SVivien Didelot } 2681de227387SAndrew Lunn 268240cff8fcSAndrew Lunn return mv88e6xxx_g1_stats_clear(chip); 26839729934cSVivien Didelot } 26849729934cSVivien Didelot 2685ea89098eSAndrew Lunn /* Check if the errata has already been applied. */ 2686ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip) 2687ea89098eSAndrew Lunn { 2688ea89098eSAndrew Lunn int port; 2689ea89098eSAndrew Lunn int err; 2690ea89098eSAndrew Lunn u16 val; 2691ea89098eSAndrew Lunn 2692ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 269360907013SMarek Behún err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val); 2694ea89098eSAndrew Lunn if (err) { 2695ea89098eSAndrew Lunn dev_err(chip->dev, 2696ea89098eSAndrew Lunn "Error reading hidden register: %d\n", err); 2697ea89098eSAndrew Lunn return false; 2698ea89098eSAndrew Lunn } 2699ea89098eSAndrew Lunn if (val != 0x01c0) 2700ea89098eSAndrew Lunn return false; 2701ea89098eSAndrew Lunn } 2702ea89098eSAndrew Lunn 2703ea89098eSAndrew Lunn return true; 2704ea89098eSAndrew Lunn } 2705ea89098eSAndrew Lunn 2706ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic 2707ea89098eSAndrew Lunn * values into undocumented hidden registers and then performing a 2708ea89098eSAndrew Lunn * software reset. 2709ea89098eSAndrew Lunn */ 2710ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) 2711ea89098eSAndrew Lunn { 2712ea89098eSAndrew Lunn int port; 2713ea89098eSAndrew Lunn int err; 2714ea89098eSAndrew Lunn 2715ea89098eSAndrew Lunn if (mv88e6390_setup_errata_applied(chip)) 2716ea89098eSAndrew Lunn return 0; 2717ea89098eSAndrew Lunn 2718ea89098eSAndrew Lunn /* Set the ports into blocking mode */ 2719ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 2720ea89098eSAndrew Lunn err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED); 2721ea89098eSAndrew Lunn if (err) 2722ea89098eSAndrew Lunn return err; 2723ea89098eSAndrew Lunn } 2724ea89098eSAndrew Lunn 2725ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 272660907013SMarek Behún err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0); 2727ea89098eSAndrew Lunn if (err) 2728ea89098eSAndrew Lunn return err; 2729ea89098eSAndrew Lunn } 2730ea89098eSAndrew Lunn 2731ea89098eSAndrew Lunn return mv88e6xxx_software_reset(chip); 2732ea89098eSAndrew Lunn } 2733ea89098eSAndrew Lunn 273423e8b470SAndrew Lunn enum mv88e6xxx_devlink_param_id { 273523e8b470SAndrew Lunn MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, 273623e8b470SAndrew Lunn MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH, 273723e8b470SAndrew Lunn }; 273823e8b470SAndrew Lunn 273923e8b470SAndrew Lunn static int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id, 274023e8b470SAndrew Lunn struct devlink_param_gset_ctx *ctx) 274123e8b470SAndrew Lunn { 274223e8b470SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 274323e8b470SAndrew Lunn int err; 274423e8b470SAndrew Lunn 274523e8b470SAndrew Lunn mv88e6xxx_reg_lock(chip); 274623e8b470SAndrew Lunn 274723e8b470SAndrew Lunn switch (id) { 274823e8b470SAndrew Lunn case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH: 274923e8b470SAndrew Lunn err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8); 275023e8b470SAndrew Lunn break; 275123e8b470SAndrew Lunn default: 275223e8b470SAndrew Lunn err = -EOPNOTSUPP; 275323e8b470SAndrew Lunn break; 275423e8b470SAndrew Lunn } 275523e8b470SAndrew Lunn 275623e8b470SAndrew Lunn mv88e6xxx_reg_unlock(chip); 275723e8b470SAndrew Lunn 275823e8b470SAndrew Lunn return err; 275923e8b470SAndrew Lunn } 276023e8b470SAndrew Lunn 276123e8b470SAndrew Lunn static int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id, 276223e8b470SAndrew Lunn struct devlink_param_gset_ctx *ctx) 276323e8b470SAndrew Lunn { 276423e8b470SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 276523e8b470SAndrew Lunn int err; 276623e8b470SAndrew Lunn 276723e8b470SAndrew Lunn mv88e6xxx_reg_lock(chip); 276823e8b470SAndrew Lunn 276923e8b470SAndrew Lunn switch (id) { 277023e8b470SAndrew Lunn case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH: 277123e8b470SAndrew Lunn err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8); 277223e8b470SAndrew Lunn break; 277323e8b470SAndrew Lunn default: 277423e8b470SAndrew Lunn err = -EOPNOTSUPP; 277523e8b470SAndrew Lunn break; 277623e8b470SAndrew Lunn } 277723e8b470SAndrew Lunn 277823e8b470SAndrew Lunn mv88e6xxx_reg_unlock(chip); 277923e8b470SAndrew Lunn 278023e8b470SAndrew Lunn return err; 278123e8b470SAndrew Lunn } 278223e8b470SAndrew Lunn 278323e8b470SAndrew Lunn static const struct devlink_param mv88e6xxx_devlink_params[] = { 278423e8b470SAndrew Lunn DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH, 278523e8b470SAndrew Lunn "ATU_hash", DEVLINK_PARAM_TYPE_U8, 278623e8b470SAndrew Lunn BIT(DEVLINK_PARAM_CMODE_RUNTIME)), 278723e8b470SAndrew Lunn }; 278823e8b470SAndrew Lunn 278923e8b470SAndrew Lunn static int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds) 279023e8b470SAndrew Lunn { 279123e8b470SAndrew Lunn return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params, 279223e8b470SAndrew Lunn ARRAY_SIZE(mv88e6xxx_devlink_params)); 279323e8b470SAndrew Lunn } 279423e8b470SAndrew Lunn 279523e8b470SAndrew Lunn static void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds) 279623e8b470SAndrew Lunn { 279723e8b470SAndrew Lunn dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params, 279823e8b470SAndrew Lunn ARRAY_SIZE(mv88e6xxx_devlink_params)); 279923e8b470SAndrew Lunn } 280023e8b470SAndrew Lunn 2801e0c69ca7SAndrew Lunn enum mv88e6xxx_devlink_resource_id { 2802e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2803e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_0, 2804e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_1, 2805e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_2, 2806e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_3, 2807e0c69ca7SAndrew Lunn }; 2808e0c69ca7SAndrew Lunn 2809e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip, 2810e0c69ca7SAndrew Lunn u16 bin) 2811e0c69ca7SAndrew Lunn { 2812e0c69ca7SAndrew Lunn u16 occupancy = 0; 2813e0c69ca7SAndrew Lunn int err; 2814e0c69ca7SAndrew Lunn 2815e0c69ca7SAndrew Lunn mv88e6xxx_reg_lock(chip); 2816e0c69ca7SAndrew Lunn 2817e0c69ca7SAndrew Lunn err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL, 2818e0c69ca7SAndrew Lunn bin); 2819e0c69ca7SAndrew Lunn if (err) { 2820e0c69ca7SAndrew Lunn dev_err(chip->dev, "failed to set ATU stats kind/bin\n"); 2821e0c69ca7SAndrew Lunn goto unlock; 2822e0c69ca7SAndrew Lunn } 2823e0c69ca7SAndrew Lunn 2824e0c69ca7SAndrew Lunn err = mv88e6xxx_g1_atu_get_next(chip, 0); 2825e0c69ca7SAndrew Lunn if (err) { 2826e0c69ca7SAndrew Lunn dev_err(chip->dev, "failed to perform ATU get next\n"); 2827e0c69ca7SAndrew Lunn goto unlock; 2828e0c69ca7SAndrew Lunn } 2829e0c69ca7SAndrew Lunn 2830e0c69ca7SAndrew Lunn err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy); 2831e0c69ca7SAndrew Lunn if (err) { 2832e0c69ca7SAndrew Lunn dev_err(chip->dev, "failed to get ATU stats\n"); 2833e0c69ca7SAndrew Lunn goto unlock; 2834e0c69ca7SAndrew Lunn } 2835e0c69ca7SAndrew Lunn 2836012fc745SAndrew Lunn occupancy &= MV88E6XXX_G2_ATU_STATS_MASK; 2837012fc745SAndrew Lunn 2838e0c69ca7SAndrew Lunn unlock: 2839e0c69ca7SAndrew Lunn mv88e6xxx_reg_unlock(chip); 2840e0c69ca7SAndrew Lunn 2841e0c69ca7SAndrew Lunn return occupancy; 2842e0c69ca7SAndrew Lunn } 2843e0c69ca7SAndrew Lunn 2844e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv) 2845e0c69ca7SAndrew Lunn { 2846e0c69ca7SAndrew Lunn struct mv88e6xxx_chip *chip = priv; 2847e0c69ca7SAndrew Lunn 2848e0c69ca7SAndrew Lunn return mv88e6xxx_devlink_atu_bin_get(chip, 2849e0c69ca7SAndrew Lunn MV88E6XXX_G2_ATU_STATS_BIN_0); 2850e0c69ca7SAndrew Lunn } 2851e0c69ca7SAndrew Lunn 2852e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv) 2853e0c69ca7SAndrew Lunn { 2854e0c69ca7SAndrew Lunn struct mv88e6xxx_chip *chip = priv; 2855e0c69ca7SAndrew Lunn 2856e0c69ca7SAndrew Lunn return mv88e6xxx_devlink_atu_bin_get(chip, 2857e0c69ca7SAndrew Lunn MV88E6XXX_G2_ATU_STATS_BIN_1); 2858e0c69ca7SAndrew Lunn } 2859e0c69ca7SAndrew Lunn 2860e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv) 2861e0c69ca7SAndrew Lunn { 2862e0c69ca7SAndrew Lunn struct mv88e6xxx_chip *chip = priv; 2863e0c69ca7SAndrew Lunn 2864e0c69ca7SAndrew Lunn return mv88e6xxx_devlink_atu_bin_get(chip, 2865e0c69ca7SAndrew Lunn MV88E6XXX_G2_ATU_STATS_BIN_2); 2866e0c69ca7SAndrew Lunn } 2867e0c69ca7SAndrew Lunn 2868e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv) 2869e0c69ca7SAndrew Lunn { 2870e0c69ca7SAndrew Lunn struct mv88e6xxx_chip *chip = priv; 2871e0c69ca7SAndrew Lunn 2872e0c69ca7SAndrew Lunn return mv88e6xxx_devlink_atu_bin_get(chip, 2873e0c69ca7SAndrew Lunn MV88E6XXX_G2_ATU_STATS_BIN_3); 2874e0c69ca7SAndrew Lunn } 2875e0c69ca7SAndrew Lunn 2876e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_get(void *priv) 2877e0c69ca7SAndrew Lunn { 2878e0c69ca7SAndrew Lunn return mv88e6xxx_devlink_atu_bin_0_get(priv) + 2879e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_1_get(priv) + 2880e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_2_get(priv) + 2881e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_3_get(priv); 2882e0c69ca7SAndrew Lunn } 2883e0c69ca7SAndrew Lunn 2884e0c69ca7SAndrew Lunn static int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds) 2885e0c69ca7SAndrew Lunn { 2886e0c69ca7SAndrew Lunn struct devlink_resource_size_params size_params; 2887e0c69ca7SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 2888e0c69ca7SAndrew Lunn int err; 2889e0c69ca7SAndrew Lunn 2890e0c69ca7SAndrew Lunn devlink_resource_size_params_init(&size_params, 2891e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip), 2892e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip), 2893e0c69ca7SAndrew Lunn 1, DEVLINK_RESOURCE_UNIT_ENTRY); 2894e0c69ca7SAndrew Lunn 2895e0c69ca7SAndrew Lunn err = dsa_devlink_resource_register(ds, "ATU", 2896e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip), 2897e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2898e0c69ca7SAndrew Lunn DEVLINK_RESOURCE_ID_PARENT_TOP, 2899e0c69ca7SAndrew Lunn &size_params); 2900e0c69ca7SAndrew Lunn if (err) 2901e0c69ca7SAndrew Lunn goto out; 2902e0c69ca7SAndrew Lunn 2903e0c69ca7SAndrew Lunn devlink_resource_size_params_init(&size_params, 2904e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip) / 4, 2905e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip) / 4, 2906e0c69ca7SAndrew Lunn 1, DEVLINK_RESOURCE_UNIT_ENTRY); 2907e0c69ca7SAndrew Lunn 2908e0c69ca7SAndrew Lunn err = dsa_devlink_resource_register(ds, "ATU_bin_0", 2909e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip) / 4, 2910e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_0, 2911e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2912e0c69ca7SAndrew Lunn &size_params); 2913e0c69ca7SAndrew Lunn if (err) 2914e0c69ca7SAndrew Lunn goto out; 2915e0c69ca7SAndrew Lunn 2916e0c69ca7SAndrew Lunn err = dsa_devlink_resource_register(ds, "ATU_bin_1", 2917e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip) / 4, 2918e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_1, 2919e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2920e0c69ca7SAndrew Lunn &size_params); 2921e0c69ca7SAndrew Lunn if (err) 2922e0c69ca7SAndrew Lunn goto out; 2923e0c69ca7SAndrew Lunn 2924e0c69ca7SAndrew Lunn err = dsa_devlink_resource_register(ds, "ATU_bin_2", 2925e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip) / 4, 2926e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_2, 2927e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2928e0c69ca7SAndrew Lunn &size_params); 2929e0c69ca7SAndrew Lunn if (err) 2930e0c69ca7SAndrew Lunn goto out; 2931e0c69ca7SAndrew Lunn 2932e0c69ca7SAndrew Lunn err = dsa_devlink_resource_register(ds, "ATU_bin_3", 2933e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip) / 4, 2934e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_3, 2935e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2936e0c69ca7SAndrew Lunn &size_params); 2937e0c69ca7SAndrew Lunn if (err) 2938e0c69ca7SAndrew Lunn goto out; 2939e0c69ca7SAndrew Lunn 2940e0c69ca7SAndrew Lunn dsa_devlink_resource_occ_get_register(ds, 2941e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2942e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_get, 2943e0c69ca7SAndrew Lunn chip); 2944e0c69ca7SAndrew Lunn 2945e0c69ca7SAndrew Lunn dsa_devlink_resource_occ_get_register(ds, 2946e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_0, 2947e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_0_get, 2948e0c69ca7SAndrew Lunn chip); 2949e0c69ca7SAndrew Lunn 2950e0c69ca7SAndrew Lunn dsa_devlink_resource_occ_get_register(ds, 2951e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_1, 2952e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_1_get, 2953e0c69ca7SAndrew Lunn chip); 2954e0c69ca7SAndrew Lunn 2955e0c69ca7SAndrew Lunn dsa_devlink_resource_occ_get_register(ds, 2956e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_2, 2957e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_2_get, 2958e0c69ca7SAndrew Lunn chip); 2959e0c69ca7SAndrew Lunn 2960e0c69ca7SAndrew Lunn dsa_devlink_resource_occ_get_register(ds, 2961e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_3, 2962e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_3_get, 2963e0c69ca7SAndrew Lunn chip); 2964e0c69ca7SAndrew Lunn 2965e0c69ca7SAndrew Lunn return 0; 2966e0c69ca7SAndrew Lunn 2967e0c69ca7SAndrew Lunn out: 2968e0c69ca7SAndrew Lunn dsa_devlink_resources_unregister(ds); 2969e0c69ca7SAndrew Lunn return err; 2970e0c69ca7SAndrew Lunn } 2971e0c69ca7SAndrew Lunn 297223e8b470SAndrew Lunn static void mv88e6xxx_teardown(struct dsa_switch *ds) 297323e8b470SAndrew Lunn { 297423e8b470SAndrew Lunn mv88e6xxx_teardown_devlink_params(ds); 2975e0c69ca7SAndrew Lunn dsa_devlink_resources_unregister(ds); 297623e8b470SAndrew Lunn } 297723e8b470SAndrew Lunn 2978fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds) 2979fad09c73SVivien Didelot { 298004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 29812d2e1dd2SAndrew Lunn u8 cmode; 2982fad09c73SVivien Didelot int err; 2983fad09c73SVivien Didelot int i; 2984fad09c73SVivien Didelot 2985fad09c73SVivien Didelot chip->ds = ds; 2986a3c53be5SAndrew Lunn ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); 2987fad09c73SVivien Didelot 2988c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2989fad09c73SVivien Didelot 2990ea89098eSAndrew Lunn if (chip->info->ops->setup_errata) { 2991ea89098eSAndrew Lunn err = chip->info->ops->setup_errata(chip); 2992ea89098eSAndrew Lunn if (err) 2993ea89098eSAndrew Lunn goto unlock; 2994ea89098eSAndrew Lunn } 2995ea89098eSAndrew Lunn 29962d2e1dd2SAndrew Lunn /* Cache the cmode of each port. */ 29972d2e1dd2SAndrew Lunn for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 29982d2e1dd2SAndrew Lunn if (chip->info->ops->port_get_cmode) { 29992d2e1dd2SAndrew Lunn err = chip->info->ops->port_get_cmode(chip, i, &cmode); 30002d2e1dd2SAndrew Lunn if (err) 3001e29129fcSDan Carpenter goto unlock; 30022d2e1dd2SAndrew Lunn 30032d2e1dd2SAndrew Lunn chip->ports[i].cmode = cmode; 30042d2e1dd2SAndrew Lunn } 30052d2e1dd2SAndrew Lunn } 30062d2e1dd2SAndrew Lunn 30079729934cSVivien Didelot /* Setup Switch Port Registers */ 3008370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 3009b759f528SVivien Didelot if (dsa_is_unused_port(ds, i)) 3010b759f528SVivien Didelot continue; 3011b759f528SVivien Didelot 3012c857486aSHubert Feurstein /* Prevent the use of an invalid port. */ 3013b759f528SVivien Didelot if (mv88e6xxx_is_invalid_port(chip, i)) { 3014c857486aSHubert Feurstein dev_err(chip->dev, "port %d is invalid\n", i); 3015c857486aSHubert Feurstein err = -EINVAL; 3016c857486aSHubert Feurstein goto unlock; 3017c857486aSHubert Feurstein } 3018c857486aSHubert Feurstein 30199729934cSVivien Didelot err = mv88e6xxx_setup_port(chip, i); 30209729934cSVivien Didelot if (err) 30219729934cSVivien Didelot goto unlock; 30229729934cSVivien Didelot } 30239729934cSVivien Didelot 3024cd8da8bbSVivien Didelot err = mv88e6xxx_irl_setup(chip); 3025cd8da8bbSVivien Didelot if (err) 3026cd8da8bbSVivien Didelot goto unlock; 3027cd8da8bbSVivien Didelot 302804a69a17SVivien Didelot err = mv88e6xxx_mac_setup(chip); 302904a69a17SVivien Didelot if (err) 303004a69a17SVivien Didelot goto unlock; 303104a69a17SVivien Didelot 30321b17aedfSVivien Didelot err = mv88e6xxx_phy_setup(chip); 30331b17aedfSVivien Didelot if (err) 30341b17aedfSVivien Didelot goto unlock; 30351b17aedfSVivien Didelot 3036b486d7c9SVivien Didelot err = mv88e6xxx_vtu_setup(chip); 3037b486d7c9SVivien Didelot if (err) 3038b486d7c9SVivien Didelot goto unlock; 3039b486d7c9SVivien Didelot 304081228996SVivien Didelot err = mv88e6xxx_pvt_setup(chip); 304181228996SVivien Didelot if (err) 304281228996SVivien Didelot goto unlock; 304381228996SVivien Didelot 3044a2ac29d2SVivien Didelot err = mv88e6xxx_atu_setup(chip); 3045a2ac29d2SVivien Didelot if (err) 3046a2ac29d2SVivien Didelot goto unlock; 3047a2ac29d2SVivien Didelot 304887fa886eSAndrew Lunn err = mv88e6xxx_broadcast_setup(chip, 0); 304987fa886eSAndrew Lunn if (err) 305087fa886eSAndrew Lunn goto unlock; 305187fa886eSAndrew Lunn 30529e907d73SVivien Didelot err = mv88e6xxx_pot_setup(chip); 30539e907d73SVivien Didelot if (err) 30549e907d73SVivien Didelot goto unlock; 30559e907d73SVivien Didelot 30569e5baf9bSVivien Didelot err = mv88e6xxx_rmu_setup(chip); 30579e5baf9bSVivien Didelot if (err) 30589e5baf9bSVivien Didelot goto unlock; 30599e5baf9bSVivien Didelot 306051c901a7SVivien Didelot err = mv88e6xxx_rsvd2cpu_setup(chip); 30616e55f698SAndrew Lunn if (err) 30626e55f698SAndrew Lunn goto unlock; 30636e55f698SAndrew Lunn 3064b28f872dSVivien Didelot err = mv88e6xxx_trunk_setup(chip); 3065b28f872dSVivien Didelot if (err) 3066b28f872dSVivien Didelot goto unlock; 3067b28f872dSVivien Didelot 3068c7f047b6SVivien Didelot err = mv88e6xxx_devmap_setup(chip); 3069c7f047b6SVivien Didelot if (err) 3070c7f047b6SVivien Didelot goto unlock; 3071c7f047b6SVivien Didelot 307293e18d61SVivien Didelot err = mv88e6xxx_pri_setup(chip); 307393e18d61SVivien Didelot if (err) 307493e18d61SVivien Didelot goto unlock; 307593e18d61SVivien Didelot 3076c6fe0ad2SBrandon Streiff /* Setup PTP Hardware Clock and timestamping */ 30772fa8d3afSBrandon Streiff if (chip->info->ptp_support) { 30782fa8d3afSBrandon Streiff err = mv88e6xxx_ptp_setup(chip); 30792fa8d3afSBrandon Streiff if (err) 30802fa8d3afSBrandon Streiff goto unlock; 3081c6fe0ad2SBrandon Streiff 3082c6fe0ad2SBrandon Streiff err = mv88e6xxx_hwtstamp_setup(chip); 3083c6fe0ad2SBrandon Streiff if (err) 3084c6fe0ad2SBrandon Streiff goto unlock; 30852fa8d3afSBrandon Streiff } 30862fa8d3afSBrandon Streiff 3087447b1bb8SVivien Didelot err = mv88e6xxx_stats_setup(chip); 3088447b1bb8SVivien Didelot if (err) 3089447b1bb8SVivien Didelot goto unlock; 3090447b1bb8SVivien Didelot 3091fad09c73SVivien Didelot unlock: 3092c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3093fad09c73SVivien Didelot 3094e0c69ca7SAndrew Lunn if (err) 3095e0c69ca7SAndrew Lunn return err; 3096e0c69ca7SAndrew Lunn 3097e0c69ca7SAndrew Lunn /* Have to be called without holding the register lock, since 3098e0c69ca7SAndrew Lunn * they take the devlink lock, and we later take the locks in 3099e0c69ca7SAndrew Lunn * the reverse order when getting/setting parameters or 3100e0c69ca7SAndrew Lunn * resource occupancy. 310123e8b470SAndrew Lunn */ 3102e0c69ca7SAndrew Lunn err = mv88e6xxx_setup_devlink_resources(ds); 3103e0c69ca7SAndrew Lunn if (err) 3104e0c69ca7SAndrew Lunn return err; 3105e0c69ca7SAndrew Lunn 3106e0c69ca7SAndrew Lunn err = mv88e6xxx_setup_devlink_params(ds); 3107e0c69ca7SAndrew Lunn if (err) 3108e0c69ca7SAndrew Lunn dsa_devlink_resources_unregister(ds); 3109e0c69ca7SAndrew Lunn 3110e0c69ca7SAndrew Lunn return err; 3111fad09c73SVivien Didelot } 3112fad09c73SVivien Didelot 3113e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) 3114fad09c73SVivien Didelot { 31150dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 31160dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 3117e57e5e77SVivien Didelot u16 val; 3118e57e5e77SVivien Didelot int err; 3119fad09c73SVivien Didelot 3120ee26a228SAndrew Lunn if (!chip->info->ops->phy_read) 3121ee26a228SAndrew Lunn return -EOPNOTSUPP; 3122ee26a228SAndrew Lunn 3123c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3124ee26a228SAndrew Lunn err = chip->info->ops->phy_read(chip, bus, phy, reg, &val); 3125c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3126e57e5e77SVivien Didelot 3127da9f3301SAndrew Lunn if (reg == MII_PHYSID2) { 3128ddc49acbSAndrew Lunn /* Some internal PHYs don't have a model number. */ 3129ddc49acbSAndrew Lunn if (chip->info->family != MV88E6XXX_FAMILY_6165) 3130ddc49acbSAndrew Lunn /* Then there is the 6165 family. It gets is 3131ddc49acbSAndrew Lunn * PHYs correct. But it can also have two 3132ddc49acbSAndrew Lunn * SERDES interfaces in the PHY address 3133ddc49acbSAndrew Lunn * space. And these don't have a model 3134ddc49acbSAndrew Lunn * number. But they are not PHYs, so we don't 3135ddc49acbSAndrew Lunn * want to give them something a PHY driver 3136ddc49acbSAndrew Lunn * will recognise. 3137ddc49acbSAndrew Lunn * 3138ddc49acbSAndrew Lunn * Use the mv88e6390 family model number 3139ddc49acbSAndrew Lunn * instead, for anything which really could be 3140ddc49acbSAndrew Lunn * a PHY, 3141da9f3301SAndrew Lunn */ 3142da9f3301SAndrew Lunn if (!(val & 0x3f0)) 3143107fcc10SVivien Didelot val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4; 3144da9f3301SAndrew Lunn } 3145da9f3301SAndrew Lunn 3146e57e5e77SVivien Didelot return err ? err : val; 3147fad09c73SVivien Didelot } 3148fad09c73SVivien Didelot 3149e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 3150fad09c73SVivien Didelot { 31510dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 31520dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 3153e57e5e77SVivien Didelot int err; 3154fad09c73SVivien Didelot 3155ee26a228SAndrew Lunn if (!chip->info->ops->phy_write) 3156ee26a228SAndrew Lunn return -EOPNOTSUPP; 3157ee26a228SAndrew Lunn 3158c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3159ee26a228SAndrew Lunn err = chip->info->ops->phy_write(chip, bus, phy, reg, val); 3160c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3161e57e5e77SVivien Didelot 3162e57e5e77SVivien Didelot return err; 3163fad09c73SVivien Didelot } 3164fad09c73SVivien Didelot 3165fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, 3166a3c53be5SAndrew Lunn struct device_node *np, 3167a3c53be5SAndrew Lunn bool external) 3168fad09c73SVivien Didelot { 3169fad09c73SVivien Didelot static int index; 31700dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 3171fad09c73SVivien Didelot struct mii_bus *bus; 3172fad09c73SVivien Didelot int err; 3173fad09c73SVivien Didelot 31742510babcSAndrew Lunn if (external) { 3175c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 31762510babcSAndrew Lunn err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true); 3177c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 31782510babcSAndrew Lunn 31792510babcSAndrew Lunn if (err) 31802510babcSAndrew Lunn return err; 31812510babcSAndrew Lunn } 31822510babcSAndrew Lunn 31830dd12d54SAndrew Lunn bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus)); 3184fad09c73SVivien Didelot if (!bus) 3185fad09c73SVivien Didelot return -ENOMEM; 3186fad09c73SVivien Didelot 31870dd12d54SAndrew Lunn mdio_bus = bus->priv; 3188a3c53be5SAndrew Lunn mdio_bus->bus = bus; 31890dd12d54SAndrew Lunn mdio_bus->chip = chip; 3190a3c53be5SAndrew Lunn INIT_LIST_HEAD(&mdio_bus->list); 3191a3c53be5SAndrew Lunn mdio_bus->external = external; 31920dd12d54SAndrew Lunn 3193fad09c73SVivien Didelot if (np) { 3194fad09c73SVivien Didelot bus->name = np->full_name; 3195f7ce9103SRob Herring snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np); 3196fad09c73SVivien Didelot } else { 3197fad09c73SVivien Didelot bus->name = "mv88e6xxx SMI"; 3198fad09c73SVivien Didelot snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++); 3199fad09c73SVivien Didelot } 3200fad09c73SVivien Didelot 3201fad09c73SVivien Didelot bus->read = mv88e6xxx_mdio_read; 3202fad09c73SVivien Didelot bus->write = mv88e6xxx_mdio_write; 3203fad09c73SVivien Didelot bus->parent = chip->dev; 3204fad09c73SVivien Didelot 32056f88284fSAndrew Lunn if (!external) { 32066f88284fSAndrew Lunn err = mv88e6xxx_g2_irq_mdio_setup(chip, bus); 32076f88284fSAndrew Lunn if (err) 32086f88284fSAndrew Lunn return err; 32096f88284fSAndrew Lunn } 32106f88284fSAndrew Lunn 3211a3c53be5SAndrew Lunn err = of_mdiobus_register(bus, np); 3212fad09c73SVivien Didelot if (err) { 3213fad09c73SVivien Didelot dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err); 32146f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 3215fad09c73SVivien Didelot return err; 3216fad09c73SVivien Didelot } 3217fad09c73SVivien Didelot 3218a3c53be5SAndrew Lunn if (external) 3219a3c53be5SAndrew Lunn list_add_tail(&mdio_bus->list, &chip->mdios); 3220a3c53be5SAndrew Lunn else 3221a3c53be5SAndrew Lunn list_add(&mdio_bus->list, &chip->mdios); 3222a3c53be5SAndrew Lunn 3223a3c53be5SAndrew Lunn return 0; 3224a3c53be5SAndrew Lunn } 3225a3c53be5SAndrew Lunn 3226a3c53be5SAndrew Lunn static const struct of_device_id mv88e6xxx_mdio_external_match[] = { 3227a3c53be5SAndrew Lunn { .compatible = "marvell,mv88e6xxx-mdio-external", 3228a3c53be5SAndrew Lunn .data = (void *)true }, 3229a3c53be5SAndrew Lunn { }, 3230a3c53be5SAndrew Lunn }; 3231a3c53be5SAndrew Lunn 32323126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) 32333126aeecSAndrew Lunn 32343126aeecSAndrew Lunn { 32353126aeecSAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 32363126aeecSAndrew Lunn struct mii_bus *bus; 32373126aeecSAndrew Lunn 32383126aeecSAndrew Lunn list_for_each_entry(mdio_bus, &chip->mdios, list) { 32393126aeecSAndrew Lunn bus = mdio_bus->bus; 32403126aeecSAndrew Lunn 32416f88284fSAndrew Lunn if (!mdio_bus->external) 32426f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 32436f88284fSAndrew Lunn 32443126aeecSAndrew Lunn mdiobus_unregister(bus); 32453126aeecSAndrew Lunn } 32463126aeecSAndrew Lunn } 32473126aeecSAndrew Lunn 3248a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, 3249a3c53be5SAndrew Lunn struct device_node *np) 3250a3c53be5SAndrew Lunn { 3251a3c53be5SAndrew Lunn const struct of_device_id *match; 3252a3c53be5SAndrew Lunn struct device_node *child; 3253a3c53be5SAndrew Lunn int err; 3254a3c53be5SAndrew Lunn 3255a3c53be5SAndrew Lunn /* Always register one mdio bus for the internal/default mdio 3256a3c53be5SAndrew Lunn * bus. This maybe represented in the device tree, but is 3257a3c53be5SAndrew Lunn * optional. 3258a3c53be5SAndrew Lunn */ 3259a3c53be5SAndrew Lunn child = of_get_child_by_name(np, "mdio"); 3260a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, false); 3261a3c53be5SAndrew Lunn if (err) 3262a3c53be5SAndrew Lunn return err; 3263a3c53be5SAndrew Lunn 3264a3c53be5SAndrew Lunn /* Walk the device tree, and see if there are any other nodes 3265a3c53be5SAndrew Lunn * which say they are compatible with the external mdio 3266a3c53be5SAndrew Lunn * bus. 3267a3c53be5SAndrew Lunn */ 3268a3c53be5SAndrew Lunn for_each_available_child_of_node(np, child) { 3269a3c53be5SAndrew Lunn match = of_match_node(mv88e6xxx_mdio_external_match, child); 3270a3c53be5SAndrew Lunn if (match) { 3271a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, true); 32723126aeecSAndrew Lunn if (err) { 32733126aeecSAndrew Lunn mv88e6xxx_mdios_unregister(chip); 327478e42040SNishka Dasgupta of_node_put(child); 3275a3c53be5SAndrew Lunn return err; 3276a3c53be5SAndrew Lunn } 3277a3c53be5SAndrew Lunn } 32783126aeecSAndrew Lunn } 3279a3c53be5SAndrew Lunn 3280a3c53be5SAndrew Lunn return 0; 3281a3c53be5SAndrew Lunn } 3282a3c53be5SAndrew Lunn 3283855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) 3284855b1932SVivien Didelot { 328504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3286855b1932SVivien Didelot 3287855b1932SVivien Didelot return chip->eeprom_len; 3288855b1932SVivien Didelot } 3289855b1932SVivien Didelot 3290855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds, 3291855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 3292855b1932SVivien Didelot { 329304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3294855b1932SVivien Didelot int err; 3295855b1932SVivien Didelot 3296ee4dc2e7SVivien Didelot if (!chip->info->ops->get_eeprom) 3297ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 3298ee4dc2e7SVivien Didelot 3299c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3300ee4dc2e7SVivien Didelot err = chip->info->ops->get_eeprom(chip, eeprom, data); 3301c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3302855b1932SVivien Didelot 3303855b1932SVivien Didelot if (err) 3304855b1932SVivien Didelot return err; 3305855b1932SVivien Didelot 3306855b1932SVivien Didelot eeprom->magic = 0xc3ec4951; 3307855b1932SVivien Didelot 3308855b1932SVivien Didelot return 0; 3309855b1932SVivien Didelot } 3310855b1932SVivien Didelot 3311855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, 3312855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 3313855b1932SVivien Didelot { 331404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3315855b1932SVivien Didelot int err; 3316855b1932SVivien Didelot 3317ee4dc2e7SVivien Didelot if (!chip->info->ops->set_eeprom) 3318ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 3319ee4dc2e7SVivien Didelot 3320855b1932SVivien Didelot if (eeprom->magic != 0xc3ec4951) 3321855b1932SVivien Didelot return -EINVAL; 3322855b1932SVivien Didelot 3323c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3324ee4dc2e7SVivien Didelot err = chip->info->ops->set_eeprom(chip, eeprom, data); 3325c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3326855b1932SVivien Didelot 3327855b1932SVivien Didelot return err; 3328855b1932SVivien Didelot } 3329855b1932SVivien Didelot 3330b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = { 33314b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6097 */ 333293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 333393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3334cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3335b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 33367e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 33377e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 333808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 33397f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 334096a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3341ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 334256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3343601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 334456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3345ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 33460898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3347c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 33489dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 33496c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 33502d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3351121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3352a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 335340cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3354dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3355dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3356052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3357fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3358fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3359fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 336051c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 33619e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 3362a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 3363a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 336417e708baSVivien Didelot .reset = mv88e6185_g1_reset, 33659e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 3366f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 33670ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 33686c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3369b3469dd8SVivien Didelot }; 3370b3469dd8SVivien Didelot 3371b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = { 33724b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6095 */ 337393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 337493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3375b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 33767e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 33777e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 337808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 33797f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 338096a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 338156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 3382601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 3383a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 33846c422e34SRussell King .port_link_state = mv88e6185_port_link_state, 33852d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3386121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3387a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 338840cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3389dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3390dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3391052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 339251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 3393a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 3394a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 339517e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3396f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 33970ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 33986c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3399b3469dd8SVivien Didelot }; 3400b3469dd8SVivien Didelot 34017d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = { 340215da3cc8SStefan Eichenberger /* MV88E6XXX_FAMILY_6097 */ 340393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 340493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3405cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 34067d381a02SStefan Eichenberger .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 34077d381a02SStefan Eichenberger .phy_read = mv88e6xxx_g2_smi_phy_read, 34087d381a02SStefan Eichenberger .phy_write = mv88e6xxx_g2_smi_phy_write, 34097d381a02SStefan Eichenberger .port_set_link = mv88e6xxx_port_set_link, 34107d381a02SStefan Eichenberger .port_set_duplex = mv88e6xxx_port_set_duplex, 34117d381a02SStefan Eichenberger .port_set_speed = mv88e6185_port_set_speed, 3412ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 341356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3414601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 341556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3416cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3417ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 34180898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3419c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 34209dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 34216c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 34222d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3423121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 34247d381a02SStefan Eichenberger .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 342540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 34267d381a02SStefan Eichenberger .stats_get_sset_count = mv88e6095_stats_get_sset_count, 34277d381a02SStefan Eichenberger .stats_get_strings = mv88e6095_stats_get_strings, 34287d381a02SStefan Eichenberger .stats_get_stats = mv88e6095_stats_get_stats, 3429fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3430fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 343191eaa475SVolodymyr Bendiuga .watchdog_ops = &mv88e6097_watchdog_ops, 343251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 34339e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 343417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 34359e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 3436f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 34370ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 34386c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 34397d381a02SStefan Eichenberger }; 34407d381a02SStefan Eichenberger 3441b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = { 34424b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 344393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 344493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3445cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3446b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3447ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 3448ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 344908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 34507f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 345196a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 345256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 3453601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 3454c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 34559dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 34566c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 34572d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3458121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 34590ac64c39SAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 346040cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3461dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3462dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3463052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3464fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3465fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3466fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 346751c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 34689e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 346917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 347023e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 347123e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3472f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 34730ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 34746c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3475b3469dd8SVivien Didelot }; 3476b3469dd8SVivien Didelot 3477b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = { 34784b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 347993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 348093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3481b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 34827e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 34837e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 348408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 34857f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 348696a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3487ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 348856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3489601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 349056995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3491a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 3492cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3493ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 34940898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 349554186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 34966c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 34972d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3498121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3499a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 350040cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3501dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3502dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3503052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3504fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3505fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3506fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 350751c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 3508a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 350902317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 3510a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 351117e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3512f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 35130ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 35146c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3515b3469dd8SVivien Didelot }; 3516b3469dd8SVivien Didelot 3517990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = { 3518990e27b0SVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 351993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 352093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3521cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3522990e27b0SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 3523990e27b0SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 3524990e27b0SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3525990e27b0SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3526990e27b0SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 3527990e27b0SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3528990e27b0SVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3529990e27b0SVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 353026422340SMarek Behún .port_set_speed = mv88e6341_port_set_speed, 35317cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6341_port_max_speed_mode, 3532990e27b0SVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 3533990e27b0SVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3534990e27b0SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 3535990e27b0SVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 3536cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3537990e27b0SVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 35380898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3539990e27b0SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 3540990e27b0SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 35416c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 35422d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 35437a3007d2SMarek Behún .port_set_cmode = mv88e6341_port_set_cmode, 3544121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3545990e27b0SVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 354640cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3547990e27b0SVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3548990e27b0SVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 3549990e27b0SVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 3550fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3551fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 3552990e27b0SVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 3553990e27b0SVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 35549e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 3555990e27b0SVivien Didelot .reset = mv88e6352_g1_reset, 3556f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 35570ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3558d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 3559d3cf7d8fSMarek Behún .serdes_get_lane = mv88e6341_serdes_get_lane, 35604241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 356161a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 3562907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 3563a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 3564e3af71a3SMarek Behún .phylink_validate = mv88e6341_phylink_validate, 3565990e27b0SVivien Didelot }; 3566990e27b0SVivien Didelot 3567b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = { 35684b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 356993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 357093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3571cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3572b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3573ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 3574ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 357508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 35767f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 357796a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3578ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 357956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3580601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 358156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3582cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3583ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 35840898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3585c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 35869dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 35876c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 35882d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3589121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3590a6da21bbSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 359140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3592dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3593dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3594052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3595fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3596fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3597fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 359851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 35999e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 360017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 360123e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 360223e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3603f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 36040ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3605a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 3606dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 36076c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3608b3469dd8SVivien Didelot }; 3609b3469dd8SVivien Didelot 3610b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = { 36114b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 361293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 361393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3614cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3615b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3616efb3e74dSAndrew Lunn .phy_read = mv88e6165_phy_read, 3617efb3e74dSAndrew Lunn .phy_write = mv88e6165_phy_write, 361808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 36197f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 362096a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3621c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 36229dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 36236c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 36242d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3625121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3626a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 362740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3628dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3629dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3630052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3631fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3632fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3633fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 363451c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 36359e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 363617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 363723e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 363823e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3639f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 36400ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3641a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 3642dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 36436c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3644b3469dd8SVivien Didelot }; 3645b3469dd8SVivien Didelot 3646b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = { 36474b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 364893e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 364993e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3650cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3651b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3652b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3653b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 365408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 36557f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 365694d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 365796a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3658ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 365956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3660601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 366156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3662cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3663ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 36640898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3665c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 36669dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 36676c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 36682d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3669121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3670a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 367140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3672dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3673dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3674052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3675fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3676fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3677fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 367851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 36799e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 368017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 368123e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 368223e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3683f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 36840ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 36856c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3686b3469dd8SVivien Didelot }; 3687b3469dd8SVivien Didelot 3688b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = { 36894b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 369093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 369193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3692cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3693ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3694ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3695b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3696b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3697b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 369808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 36997f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3700a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 370196a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 3702ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 3703f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 370456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3705601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 370656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3707cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3708ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 37090898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3710c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 37119dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 37126c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 37132d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3714121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3715a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 371640cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3717dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3718dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3719052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3720fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3721fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3722fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 372351c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 37249e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 372517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 37269e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 372723e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 372823e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3729f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 37300ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 37319db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 37326d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 3733d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 3734d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 3735a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 37366c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3737b3469dd8SVivien Didelot }; 3738b3469dd8SVivien Didelot 3739b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = { 37404b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 374193e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 374293e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3743cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3744b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3745b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3746b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 374708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 37487f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 374994d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 375096a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3751ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 375256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3753601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 375456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3755cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3756ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 37570898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3758c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 37599dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 37606c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 37612d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3762121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3763a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 376440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3765dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3766dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3767052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3768fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3769fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3770fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 377151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 37729e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 377317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 377423e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 377523e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3776f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 37770ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 37786c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3779b3469dd8SVivien Didelot }; 3780b3469dd8SVivien Didelot 3781b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = { 37824b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 378393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 378493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3785cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3786ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3787ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3788b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3789b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3790b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 379108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 37927f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3793a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 379496a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 3795ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 3796f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 379756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3798601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 379956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3800cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3801ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 38020898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3803c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 38049dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 38056c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 38062d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3807121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3808a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 380940cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3810dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3811dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3812052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3813fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3814fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3815fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 381651c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 38179e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 381817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 38199e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 382023e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 382123e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3822f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 38230ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 38249db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 38256d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 38264241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 382761a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 3828907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 3829d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 3830d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 3831a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 38326c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3833b3469dd8SVivien Didelot }; 3834b3469dd8SVivien Didelot 3835b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = { 38364b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 383793e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 383893e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3839b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 38407e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 38417e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 384208ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 38437f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 384496a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 384556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 3846601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 3847ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 3848a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 384954186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 38506c422e34SRussell King .port_link_state = mv88e6185_port_link_state, 38512d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3852121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3853a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 385440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3855dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3856dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3857052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3858fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3859fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3860fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 386151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 386202317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 3863a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 3864a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 386517e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3866f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 38670ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 38686c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3869b3469dd8SVivien Didelot }; 3870b3469dd8SVivien Didelot 38711a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = { 38724b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3873ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3874cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 387598fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 387698fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 38771a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 38781a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 38791a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 38801a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 38811a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 38821a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 38831a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 38847cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 3885ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 3886f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 388756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3888601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 388956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 38900898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3891c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 38929dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 38936c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 38942d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3895fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 3896121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 389779523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3898de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3899dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3900dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3901e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3902fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3903fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 390461303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 39056e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 39069e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 390717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 39089e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 390923e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 391023e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3911931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3912931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 39136335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 391417deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 39154241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 391661a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 3917907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 39184262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 39194262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 3920bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 3921bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 39224262c38dSAndrew Lunn .phylink_validate = mv88e6390_phylink_validate, 3923a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 39246c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 39251a3b39ecSAndrew Lunn }; 39261a3b39ecSAndrew Lunn 39271a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = { 39284b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3929ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3930cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 393198fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 393298fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 39331a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 39341a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 39351a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 39361a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 39371a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 39381a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 39391a3b39ecSAndrew Lunn .port_set_speed = mv88e6390x_port_set_speed, 39407cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 3941ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 3942f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 394356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3944601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 394556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 39460898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3947c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 39489dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 39496c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 39502d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3951fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 3952121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 395379523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3954de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3955dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3956dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3957e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3958fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3959fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 396061303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 39616e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 39629e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 396317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 39649e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 396523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 396623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3967931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3968931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 3969d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 397017deaf5cSMarek Behún .serdes_get_lane = mv88e6390x_serdes_get_lane, 39714241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 397261a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 3973907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 39744262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 39754262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 3976bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 3977bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 39784262c38dSAndrew Lunn .phylink_validate = mv88e6390_phylink_validate, 3979a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 39806c422e34SRussell King .phylink_validate = mv88e6390x_phylink_validate, 39811a3b39ecSAndrew Lunn }; 39821a3b39ecSAndrew Lunn 39831a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = { 39844b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3985ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3986cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 398798fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 398898fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 39891a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 39901a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 39911a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 39921a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 39931a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 39941a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 39951a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 39967cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 3997ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 399856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3999601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 400056995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 40010898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4002c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 40039dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 40046c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 40052d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4006fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4007121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 400879523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4009de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4010dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4011dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4012e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4013fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4014fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 401561303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 40166e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 40179e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 401817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 40199e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 402023e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 402123e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4022931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4023931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 40246335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 402517deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 40264241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 402761a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4028907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 40294262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 40304262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4031bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4032bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 40334262c38dSAndrew Lunn .phylink_validate = mv88e6390_phylink_validate, 40346d2ac8eeSAndrew Lunn .avb_ops = &mv88e6390_avb_ops, 40356d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 40366c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 40371a3b39ecSAndrew Lunn }; 40381a3b39ecSAndrew Lunn 4039b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = { 40404b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 404193e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 404293e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4043cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4044ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4045ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4046b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4047b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4048b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 404908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 40507f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 4051a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 405296a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 4053ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 4054f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 405556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4056601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 405756995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4058cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4059ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 40600898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4061c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 40629dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 40636c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 40642d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4065121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4066a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 406740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4068dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4069dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4070052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4071fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4072fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4073fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 407451c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 40759e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 407617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 40779e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 407823e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 407923e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4080f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 40810ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 40829db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 40836d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 40844241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 408561a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 4086907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 4087d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 4088d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 4089a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 40900d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 40916d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 40926c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 4093b3469dd8SVivien Didelot }; 4094b3469dd8SVivien Didelot 40951f71836fSRasmus Villemoes static const struct mv88e6xxx_ops mv88e6250_ops = { 40961f71836fSRasmus Villemoes /* MV88E6XXX_FAMILY_6250 */ 40971f71836fSRasmus Villemoes .ieee_pri_map = mv88e6250_g1_ieee_pri_map, 40981f71836fSRasmus Villemoes .ip_pri_map = mv88e6085_g1_ip_pri_map, 40991f71836fSRasmus Villemoes .irl_init_all = mv88e6352_g2_irl_init_all, 41001f71836fSRasmus Villemoes .get_eeprom = mv88e6xxx_g2_get_eeprom16, 41011f71836fSRasmus Villemoes .set_eeprom = mv88e6xxx_g2_set_eeprom16, 41021f71836fSRasmus Villemoes .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 41031f71836fSRasmus Villemoes .phy_read = mv88e6xxx_g2_smi_phy_read, 41041f71836fSRasmus Villemoes .phy_write = mv88e6xxx_g2_smi_phy_write, 41051f71836fSRasmus Villemoes .port_set_link = mv88e6xxx_port_set_link, 41061f71836fSRasmus Villemoes .port_set_duplex = mv88e6xxx_port_set_duplex, 41071f71836fSRasmus Villemoes .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 41081f71836fSRasmus Villemoes .port_set_speed = mv88e6250_port_set_speed, 41091f71836fSRasmus Villemoes .port_tag_remap = mv88e6095_port_tag_remap, 41101f71836fSRasmus Villemoes .port_set_frame_mode = mv88e6351_port_set_frame_mode, 41111f71836fSRasmus Villemoes .port_set_egress_floods = mv88e6352_port_set_egress_floods, 41121f71836fSRasmus Villemoes .port_set_ether_type = mv88e6351_port_set_ether_type, 41131f71836fSRasmus Villemoes .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 41141f71836fSRasmus Villemoes .port_pause_limit = mv88e6097_port_pause_limit, 41151f71836fSRasmus Villemoes .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 41161f71836fSRasmus Villemoes .port_link_state = mv88e6250_port_link_state, 41171f71836fSRasmus Villemoes .stats_snapshot = mv88e6320_g1_stats_snapshot, 41181f71836fSRasmus Villemoes .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 41191f71836fSRasmus Villemoes .stats_get_sset_count = mv88e6250_stats_get_sset_count, 41201f71836fSRasmus Villemoes .stats_get_strings = mv88e6250_stats_get_strings, 41211f71836fSRasmus Villemoes .stats_get_stats = mv88e6250_stats_get_stats, 41221f71836fSRasmus Villemoes .set_cpu_port = mv88e6095_g1_set_cpu_port, 41231f71836fSRasmus Villemoes .set_egress_port = mv88e6095_g1_set_egress_port, 41241f71836fSRasmus Villemoes .watchdog_ops = &mv88e6250_watchdog_ops, 41251f71836fSRasmus Villemoes .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 41261f71836fSRasmus Villemoes .pot_clear = mv88e6xxx_g2_pot_clear, 41271f71836fSRasmus Villemoes .reset = mv88e6250_g1_reset, 41281f71836fSRasmus Villemoes .vtu_getnext = mv88e6250_g1_vtu_getnext, 41291f71836fSRasmus Villemoes .vtu_loadpurge = mv88e6250_g1_vtu_loadpurge, 413071509614SHubert Feurstein .avb_ops = &mv88e6352_avb_ops, 413171509614SHubert Feurstein .ptp_ops = &mv88e6250_ptp_ops, 41321f71836fSRasmus Villemoes .phylink_validate = mv88e6065_phylink_validate, 41331f71836fSRasmus Villemoes }; 41341f71836fSRasmus Villemoes 41351a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = { 41364b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4137ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4138cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 413998fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 414098fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 41411a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 41421a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 41431a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 41441a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 41451a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 41461a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 41471a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 41487cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4149ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4150f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 415156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4152601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 415356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 41540898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4155c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 41569dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 41576c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 41582d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4159fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4160121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 416179523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4162de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4163dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4164dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4165e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4166fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4167fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 416861303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 41696e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 41709e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 417117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 41729e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 417323e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 417423e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4175931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4176931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 41776335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 417817deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 41794241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 418061a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4181907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 41824262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 41834262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4184bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4185bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 41864262c38dSAndrew Lunn .phylink_validate = mv88e6390_phylink_validate, 4187a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 41880d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 41896d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 41906c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 41911a3b39ecSAndrew Lunn }; 41921a3b39ecSAndrew Lunn 4193b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = { 41944b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6320 */ 419593e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 419693e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4197cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4198ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4199ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4200b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4201b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4202b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 420308ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 42047f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 420596a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 4206ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 420756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4208601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 420956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4210cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4211ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 42120898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4213c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 42149dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 42156c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 42162d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4217121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4218a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 421940cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4220dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4221dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4222052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 4223fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4224fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 42259c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 422651c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 42279e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 422817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 4229f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 42300ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 4231a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 42320d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 42336d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 42346c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4235b3469dd8SVivien Didelot }; 4236b3469dd8SVivien Didelot 4237b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = { 4238bd807204SVivien Didelot /* MV88E6XXX_FAMILY_6320 */ 423993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 424093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4241cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4242ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4243ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4244b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4245b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4246b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 424708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 42487f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 424996a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 4250ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 425156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4252601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 425356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4254cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4255ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 42560898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4257c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 42589dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 42596c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 42602d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4261121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4262a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 426340cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4264dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4265dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4266052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 4267fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4268fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 42699c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 427017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 4271f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 42720ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 4273a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 42740d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 42756d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 42766c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4277b3469dd8SVivien Didelot }; 4278b3469dd8SVivien Didelot 427916e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = { 428016e329aeSVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 428193e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 428293e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4283cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 428416e329aeSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 428516e329aeSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 428616e329aeSVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 428716e329aeSVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 428816e329aeSVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 428916e329aeSVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 429016e329aeSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 429116e329aeSVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 429226422340SMarek Behún .port_set_speed = mv88e6341_port_set_speed, 42937cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6341_port_max_speed_mode, 429416e329aeSVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 429516e329aeSVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 429616e329aeSVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 429716e329aeSVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 4298cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 429916e329aeSVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 43000898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 430116e329aeSVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 430216e329aeSVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 43036c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 43042d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 43057a3007d2SMarek Behún .port_set_cmode = mv88e6341_port_set_cmode, 4306121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 430716e329aeSVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 430840cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 430916e329aeSVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 431016e329aeSVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 431116e329aeSVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 4312fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4313fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 431416e329aeSVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 431516e329aeSVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 43169e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 431716e329aeSVivien Didelot .reset = mv88e6352_g1_reset, 4318f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 43190ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4320d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 4321d3cf7d8fSMarek Behún .serdes_get_lane = mv88e6341_serdes_get_lane, 43224241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 432361a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4324907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 4325a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 43260d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 43276d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 4328e3af71a3SMarek Behún .phylink_validate = mv88e6341_phylink_validate, 432916e329aeSVivien Didelot }; 433016e329aeSVivien Didelot 4331b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = { 43324b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 433393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 433493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4335cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4336b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4337b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4338b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 433908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 43407f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 434194d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 434296a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 4343ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 434456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4345601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 434656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4347cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4348ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 43490898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4350c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 43519dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 43526c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 43532d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4354121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4355a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 435640cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4357dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4358dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4359052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4360fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4361fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4362fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 436351c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 43649e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 436517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 436623e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 436723e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4368f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 43690ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 43706c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4371b3469dd8SVivien Didelot }; 4372b3469dd8SVivien Didelot 4373b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = { 43744b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 437593e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 437693e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4377cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4378b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4379b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4380b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 438108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 43827f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 438394d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 438496a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 4385ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 438656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4387601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 438856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4389cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4390ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 43910898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4392c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 43939dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 43946c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 43952d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4396121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4397a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 439840cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4399dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4400dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4401052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4402fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4403fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4404fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 440551c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 44069e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 440717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 440823e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 440923e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4410f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 44110ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 44120d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 44136d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 44146c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4415b3469dd8SVivien Didelot }; 4416b3469dd8SVivien Didelot 4417b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = { 44184b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 441993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 442093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4421cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4422ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4423ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4424b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4425b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4426b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 442708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 44287f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 4429a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 443096a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 4431ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 4432f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 443356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4434601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 443556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4436cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4437ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 44380898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4439c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 44409dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 44416c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 44422d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4443121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4444a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 444540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4446dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4447dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4448052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4449fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4450fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4451fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 445251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 44539e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 445417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 44559e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 445623e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 445723e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4458f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 44590ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 44609db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 44616d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 44624241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 446361a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 4464907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 4465a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 44660d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 44676d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 4468cda9f4aaSAndrew Lunn .serdes_get_sset_count = mv88e6352_serdes_get_sset_count, 4469cda9f4aaSAndrew Lunn .serdes_get_strings = mv88e6352_serdes_get_strings, 4470cda9f4aaSAndrew Lunn .serdes_get_stats = mv88e6352_serdes_get_stats, 4471d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 4472d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 44736c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 4474b3469dd8SVivien Didelot }; 4475b3469dd8SVivien Didelot 44761a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = { 44774b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4478ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4479cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 448098fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 448198fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 44821a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 44831a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 44841a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 44851a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 44861a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 44871a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 44881a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 44897cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4490ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4491f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 449256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4493601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 449456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4495cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4496ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 44970898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4498c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 44999dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 45006c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 45012d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4502fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4503121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 450479523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4505de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4506dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4507dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4508e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4509fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4510fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 451161303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 45126e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 45139e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 451417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 45159e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 451623e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 451723e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4518931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4519931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 45206335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 452117deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 45224241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 452361a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4524907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 4525a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 45260d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 45276d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 45280df95287SNikita Yushchenko .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 45290df95287SNikita Yushchenko .serdes_get_strings = mv88e6390_serdes_get_strings, 45300df95287SNikita Yushchenko .serdes_get_stats = mv88e6390_serdes_get_stats, 4531bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4532bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 45336c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 45341a3b39ecSAndrew Lunn }; 45351a3b39ecSAndrew Lunn 45361a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = { 45374b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4538ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4539cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 454098fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 454198fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 45421a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 45431a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 45441a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 45451a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 45461a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 45471a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 45481a3b39ecSAndrew Lunn .port_set_speed = mv88e6390x_port_set_speed, 45497cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 4550ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4551f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 455256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4553601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 455456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4555cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4556ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 45570898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4558c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 45599dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 45606c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 45612d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4562b3dce4daSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 4563121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 456479523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4565de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4566dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4567dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4568e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4569fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4570fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 457161303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 45726e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 45739e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 457417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 45759e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 457623e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 457723e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4578931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4579931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 4580d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 458117deaf5cSMarek Behún .serdes_get_lane = mv88e6390x_serdes_get_lane, 45824241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 458361a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4584907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 45854262c38dSAndrew Lunn .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 45864262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 45874262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4588bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4589bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 4590a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 45910d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 45926d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 45936c422e34SRussell King .phylink_validate = mv88e6390x_phylink_validate, 45941a3b39ecSAndrew Lunn }; 45951a3b39ecSAndrew Lunn 4596fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = { 4597fad09c73SVivien Didelot [MV88E6085] = { 4598107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085, 4599fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6097, 4600fad09c73SVivien Didelot .name = "Marvell 88E6085", 4601fad09c73SVivien Didelot .num_databases = 4096, 4602d9ea5620SAndrew Lunn .num_macs = 8192, 4603fad09c73SVivien Didelot .num_ports = 10, 4604bc393155SAndrew Lunn .num_internal_phys = 5, 46053cf3c846SVivien Didelot .max_vid = 4095, 4606fad09c73SVivien Didelot .port_base_addr = 0x10, 46079255bacdSAndrew Lunn .phy_base_addr = 0x0, 4608a935c052SVivien Didelot .global1_addr = 0x1b, 46099069c13aSVivien Didelot .global2_addr = 0x1c, 4610acddbd21SVivien Didelot .age_time_coeff = 15000, 4611dc30c35bSAndrew Lunn .g1_irqs = 8, 4612d6c5e6afSVivien Didelot .g2_irqs = 10, 4613e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4614f3645652SVivien Didelot .pvt = true, 4615b3e05aa1SVivien Didelot .multi_chip = true, 4616443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4617b3469dd8SVivien Didelot .ops = &mv88e6085_ops, 4618fad09c73SVivien Didelot }, 4619fad09c73SVivien Didelot 4620fad09c73SVivien Didelot [MV88E6095] = { 4621107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095, 4622fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6095, 4623fad09c73SVivien Didelot .name = "Marvell 88E6095/88E6095F", 4624fad09c73SVivien Didelot .num_databases = 256, 4625d9ea5620SAndrew Lunn .num_macs = 8192, 4626fad09c73SVivien Didelot .num_ports = 11, 4627bc393155SAndrew Lunn .num_internal_phys = 0, 46283cf3c846SVivien Didelot .max_vid = 4095, 4629fad09c73SVivien Didelot .port_base_addr = 0x10, 46309255bacdSAndrew Lunn .phy_base_addr = 0x0, 4631a935c052SVivien Didelot .global1_addr = 0x1b, 46329069c13aSVivien Didelot .global2_addr = 0x1c, 4633acddbd21SVivien Didelot .age_time_coeff = 15000, 4634dc30c35bSAndrew Lunn .g1_irqs = 8, 4635e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4636b3e05aa1SVivien Didelot .multi_chip = true, 4637443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4638b3469dd8SVivien Didelot .ops = &mv88e6095_ops, 4639fad09c73SVivien Didelot }, 4640fad09c73SVivien Didelot 46417d381a02SStefan Eichenberger [MV88E6097] = { 4642107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097, 46437d381a02SStefan Eichenberger .family = MV88E6XXX_FAMILY_6097, 46447d381a02SStefan Eichenberger .name = "Marvell 88E6097/88E6097F", 46457d381a02SStefan Eichenberger .num_databases = 4096, 4646d9ea5620SAndrew Lunn .num_macs = 8192, 46477d381a02SStefan Eichenberger .num_ports = 11, 4648bc393155SAndrew Lunn .num_internal_phys = 8, 46493cf3c846SVivien Didelot .max_vid = 4095, 46507d381a02SStefan Eichenberger .port_base_addr = 0x10, 46519255bacdSAndrew Lunn .phy_base_addr = 0x0, 46527d381a02SStefan Eichenberger .global1_addr = 0x1b, 46539069c13aSVivien Didelot .global2_addr = 0x1c, 46547d381a02SStefan Eichenberger .age_time_coeff = 15000, 4655c534178bSStefan Eichenberger .g1_irqs = 8, 4656d6c5e6afSVivien Didelot .g2_irqs = 10, 4657e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4658f3645652SVivien Didelot .pvt = true, 4659b3e05aa1SVivien Didelot .multi_chip = true, 46602bfcfcd3SStefan Eichenberger .tag_protocol = DSA_TAG_PROTO_EDSA, 46617d381a02SStefan Eichenberger .ops = &mv88e6097_ops, 46627d381a02SStefan Eichenberger }, 46637d381a02SStefan Eichenberger 4664fad09c73SVivien Didelot [MV88E6123] = { 4665107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123, 4666fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4667fad09c73SVivien Didelot .name = "Marvell 88E6123", 4668fad09c73SVivien Didelot .num_databases = 4096, 4669d9ea5620SAndrew Lunn .num_macs = 1024, 4670fad09c73SVivien Didelot .num_ports = 3, 4671bc393155SAndrew Lunn .num_internal_phys = 5, 46723cf3c846SVivien Didelot .max_vid = 4095, 4673fad09c73SVivien Didelot .port_base_addr = 0x10, 46749255bacdSAndrew Lunn .phy_base_addr = 0x0, 4675a935c052SVivien Didelot .global1_addr = 0x1b, 46769069c13aSVivien Didelot .global2_addr = 0x1c, 4677acddbd21SVivien Didelot .age_time_coeff = 15000, 4678dc30c35bSAndrew Lunn .g1_irqs = 9, 4679d6c5e6afSVivien Didelot .g2_irqs = 10, 4680e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4681f3645652SVivien Didelot .pvt = true, 4682b3e05aa1SVivien Didelot .multi_chip = true, 46835ebe31d7SAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4684b3469dd8SVivien Didelot .ops = &mv88e6123_ops, 4685fad09c73SVivien Didelot }, 4686fad09c73SVivien Didelot 4687fad09c73SVivien Didelot [MV88E6131] = { 4688107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131, 4689fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 4690fad09c73SVivien Didelot .name = "Marvell 88E6131", 4691fad09c73SVivien Didelot .num_databases = 256, 4692d9ea5620SAndrew Lunn .num_macs = 8192, 4693fad09c73SVivien Didelot .num_ports = 8, 4694bc393155SAndrew Lunn .num_internal_phys = 0, 46953cf3c846SVivien Didelot .max_vid = 4095, 4696fad09c73SVivien Didelot .port_base_addr = 0x10, 46979255bacdSAndrew Lunn .phy_base_addr = 0x0, 4698a935c052SVivien Didelot .global1_addr = 0x1b, 46999069c13aSVivien Didelot .global2_addr = 0x1c, 4700acddbd21SVivien Didelot .age_time_coeff = 15000, 4701dc30c35bSAndrew Lunn .g1_irqs = 9, 4702e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4703b3e05aa1SVivien Didelot .multi_chip = true, 4704443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4705b3469dd8SVivien Didelot .ops = &mv88e6131_ops, 4706fad09c73SVivien Didelot }, 4707fad09c73SVivien Didelot 4708990e27b0SVivien Didelot [MV88E6141] = { 4709107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141, 4710990e27b0SVivien Didelot .family = MV88E6XXX_FAMILY_6341, 471179a68b26SUwe Kleine-König .name = "Marvell 88E6141", 4712990e27b0SVivien Didelot .num_databases = 4096, 4713d9ea5620SAndrew Lunn .num_macs = 2048, 4714990e27b0SVivien Didelot .num_ports = 6, 4715bc393155SAndrew Lunn .num_internal_phys = 5, 4716a73ccd61SBrandon Streiff .num_gpio = 11, 47173cf3c846SVivien Didelot .max_vid = 4095, 4718990e27b0SVivien Didelot .port_base_addr = 0x10, 47199255bacdSAndrew Lunn .phy_base_addr = 0x10, 4720990e27b0SVivien Didelot .global1_addr = 0x1b, 47219069c13aSVivien Didelot .global2_addr = 0x1c, 4722990e27b0SVivien Didelot .age_time_coeff = 3750, 4723990e27b0SVivien Didelot .atu_move_port_mask = 0x1f, 4724adfccf11SAndrew Lunn .g1_irqs = 9, 4725d6c5e6afSVivien Didelot .g2_irqs = 10, 4726f3645652SVivien Didelot .pvt = true, 4727b3e05aa1SVivien Didelot .multi_chip = true, 4728990e27b0SVivien Didelot .tag_protocol = DSA_TAG_PROTO_EDSA, 4729990e27b0SVivien Didelot .ops = &mv88e6141_ops, 4730990e27b0SVivien Didelot }, 4731990e27b0SVivien Didelot 4732fad09c73SVivien Didelot [MV88E6161] = { 4733107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161, 4734fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4735fad09c73SVivien Didelot .name = "Marvell 88E6161", 4736fad09c73SVivien Didelot .num_databases = 4096, 4737d9ea5620SAndrew Lunn .num_macs = 1024, 4738fad09c73SVivien Didelot .num_ports = 6, 4739bc393155SAndrew Lunn .num_internal_phys = 5, 47403cf3c846SVivien Didelot .max_vid = 4095, 4741fad09c73SVivien Didelot .port_base_addr = 0x10, 47429255bacdSAndrew Lunn .phy_base_addr = 0x0, 4743a935c052SVivien Didelot .global1_addr = 0x1b, 47449069c13aSVivien Didelot .global2_addr = 0x1c, 4745acddbd21SVivien Didelot .age_time_coeff = 15000, 4746dc30c35bSAndrew Lunn .g1_irqs = 9, 4747d6c5e6afSVivien Didelot .g2_irqs = 10, 4748e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4749f3645652SVivien Didelot .pvt = true, 4750b3e05aa1SVivien Didelot .multi_chip = true, 47515ebe31d7SAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4752dfa54348SAndrew Lunn .ptp_support = true, 4753b3469dd8SVivien Didelot .ops = &mv88e6161_ops, 4754fad09c73SVivien Didelot }, 4755fad09c73SVivien Didelot 4756fad09c73SVivien Didelot [MV88E6165] = { 4757107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165, 4758fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4759fad09c73SVivien Didelot .name = "Marvell 88E6165", 4760fad09c73SVivien Didelot .num_databases = 4096, 4761d9ea5620SAndrew Lunn .num_macs = 8192, 4762fad09c73SVivien Didelot .num_ports = 6, 4763bc393155SAndrew Lunn .num_internal_phys = 0, 47643cf3c846SVivien Didelot .max_vid = 4095, 4765fad09c73SVivien Didelot .port_base_addr = 0x10, 47669255bacdSAndrew Lunn .phy_base_addr = 0x0, 4767a935c052SVivien Didelot .global1_addr = 0x1b, 47689069c13aSVivien Didelot .global2_addr = 0x1c, 4769acddbd21SVivien Didelot .age_time_coeff = 15000, 4770dc30c35bSAndrew Lunn .g1_irqs = 9, 4771d6c5e6afSVivien Didelot .g2_irqs = 10, 4772e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4773f3645652SVivien Didelot .pvt = true, 4774b3e05aa1SVivien Didelot .multi_chip = true, 4775443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4776dfa54348SAndrew Lunn .ptp_support = true, 4777b3469dd8SVivien Didelot .ops = &mv88e6165_ops, 4778fad09c73SVivien Didelot }, 4779fad09c73SVivien Didelot 4780fad09c73SVivien Didelot [MV88E6171] = { 4781107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171, 4782fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4783fad09c73SVivien Didelot .name = "Marvell 88E6171", 4784fad09c73SVivien Didelot .num_databases = 4096, 4785d9ea5620SAndrew Lunn .num_macs = 8192, 4786fad09c73SVivien Didelot .num_ports = 7, 4787bc393155SAndrew Lunn .num_internal_phys = 5, 47883cf3c846SVivien Didelot .max_vid = 4095, 4789fad09c73SVivien Didelot .port_base_addr = 0x10, 47909255bacdSAndrew Lunn .phy_base_addr = 0x0, 4791a935c052SVivien Didelot .global1_addr = 0x1b, 47929069c13aSVivien Didelot .global2_addr = 0x1c, 4793acddbd21SVivien Didelot .age_time_coeff = 15000, 4794dc30c35bSAndrew Lunn .g1_irqs = 9, 4795d6c5e6afSVivien Didelot .g2_irqs = 10, 4796e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4797f3645652SVivien Didelot .pvt = true, 4798b3e05aa1SVivien Didelot .multi_chip = true, 4799443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4800b3469dd8SVivien Didelot .ops = &mv88e6171_ops, 4801fad09c73SVivien Didelot }, 4802fad09c73SVivien Didelot 4803fad09c73SVivien Didelot [MV88E6172] = { 4804107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172, 4805fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4806fad09c73SVivien Didelot .name = "Marvell 88E6172", 4807fad09c73SVivien Didelot .num_databases = 4096, 4808d9ea5620SAndrew Lunn .num_macs = 8192, 4809fad09c73SVivien Didelot .num_ports = 7, 4810bc393155SAndrew Lunn .num_internal_phys = 5, 4811a73ccd61SBrandon Streiff .num_gpio = 15, 48123cf3c846SVivien Didelot .max_vid = 4095, 4813fad09c73SVivien Didelot .port_base_addr = 0x10, 48149255bacdSAndrew Lunn .phy_base_addr = 0x0, 4815a935c052SVivien Didelot .global1_addr = 0x1b, 48169069c13aSVivien Didelot .global2_addr = 0x1c, 4817acddbd21SVivien Didelot .age_time_coeff = 15000, 4818dc30c35bSAndrew Lunn .g1_irqs = 9, 4819d6c5e6afSVivien Didelot .g2_irqs = 10, 4820e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4821f3645652SVivien Didelot .pvt = true, 4822b3e05aa1SVivien Didelot .multi_chip = true, 4823443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4824b3469dd8SVivien Didelot .ops = &mv88e6172_ops, 4825fad09c73SVivien Didelot }, 4826fad09c73SVivien Didelot 4827fad09c73SVivien Didelot [MV88E6175] = { 4828107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175, 4829fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4830fad09c73SVivien Didelot .name = "Marvell 88E6175", 4831fad09c73SVivien Didelot .num_databases = 4096, 4832d9ea5620SAndrew Lunn .num_macs = 8192, 4833fad09c73SVivien Didelot .num_ports = 7, 4834bc393155SAndrew Lunn .num_internal_phys = 5, 48353cf3c846SVivien Didelot .max_vid = 4095, 4836fad09c73SVivien Didelot .port_base_addr = 0x10, 48379255bacdSAndrew Lunn .phy_base_addr = 0x0, 4838a935c052SVivien Didelot .global1_addr = 0x1b, 48399069c13aSVivien Didelot .global2_addr = 0x1c, 4840acddbd21SVivien Didelot .age_time_coeff = 15000, 4841dc30c35bSAndrew Lunn .g1_irqs = 9, 4842d6c5e6afSVivien Didelot .g2_irqs = 10, 4843e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4844f3645652SVivien Didelot .pvt = true, 4845b3e05aa1SVivien Didelot .multi_chip = true, 4846443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4847b3469dd8SVivien Didelot .ops = &mv88e6175_ops, 4848fad09c73SVivien Didelot }, 4849fad09c73SVivien Didelot 4850fad09c73SVivien Didelot [MV88E6176] = { 4851107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176, 4852fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4853fad09c73SVivien Didelot .name = "Marvell 88E6176", 4854fad09c73SVivien Didelot .num_databases = 4096, 4855d9ea5620SAndrew Lunn .num_macs = 8192, 4856fad09c73SVivien Didelot .num_ports = 7, 4857bc393155SAndrew Lunn .num_internal_phys = 5, 4858a73ccd61SBrandon Streiff .num_gpio = 15, 48593cf3c846SVivien Didelot .max_vid = 4095, 4860fad09c73SVivien Didelot .port_base_addr = 0x10, 48619255bacdSAndrew Lunn .phy_base_addr = 0x0, 4862a935c052SVivien Didelot .global1_addr = 0x1b, 48639069c13aSVivien Didelot .global2_addr = 0x1c, 4864acddbd21SVivien Didelot .age_time_coeff = 15000, 4865dc30c35bSAndrew Lunn .g1_irqs = 9, 4866d6c5e6afSVivien Didelot .g2_irqs = 10, 4867e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4868f3645652SVivien Didelot .pvt = true, 4869b3e05aa1SVivien Didelot .multi_chip = true, 4870443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4871b3469dd8SVivien Didelot .ops = &mv88e6176_ops, 4872fad09c73SVivien Didelot }, 4873fad09c73SVivien Didelot 4874fad09c73SVivien Didelot [MV88E6185] = { 4875107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185, 4876fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 4877fad09c73SVivien Didelot .name = "Marvell 88E6185", 4878fad09c73SVivien Didelot .num_databases = 256, 4879d9ea5620SAndrew Lunn .num_macs = 8192, 4880fad09c73SVivien Didelot .num_ports = 10, 4881bc393155SAndrew Lunn .num_internal_phys = 0, 48823cf3c846SVivien Didelot .max_vid = 4095, 4883fad09c73SVivien Didelot .port_base_addr = 0x10, 48849255bacdSAndrew Lunn .phy_base_addr = 0x0, 4885a935c052SVivien Didelot .global1_addr = 0x1b, 48869069c13aSVivien Didelot .global2_addr = 0x1c, 4887acddbd21SVivien Didelot .age_time_coeff = 15000, 4888dc30c35bSAndrew Lunn .g1_irqs = 8, 4889e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4890b3e05aa1SVivien Didelot .multi_chip = true, 4891443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4892b3469dd8SVivien Didelot .ops = &mv88e6185_ops, 4893fad09c73SVivien Didelot }, 4894fad09c73SVivien Didelot 48951a3b39ecSAndrew Lunn [MV88E6190] = { 4896107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190, 48971a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 48981a3b39ecSAndrew Lunn .name = "Marvell 88E6190", 48991a3b39ecSAndrew Lunn .num_databases = 4096, 4900d9ea5620SAndrew Lunn .num_macs = 16384, 49011a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 490295150f29SHeiner Kallweit .num_internal_phys = 9, 4903a73ccd61SBrandon Streiff .num_gpio = 16, 4904931d1822SVivien Didelot .max_vid = 8191, 49051a3b39ecSAndrew Lunn .port_base_addr = 0x0, 49069255bacdSAndrew Lunn .phy_base_addr = 0x0, 49071a3b39ecSAndrew Lunn .global1_addr = 0x1b, 49089069c13aSVivien Didelot .global2_addr = 0x1c, 4909443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4910b91e055cSAndrew Lunn .age_time_coeff = 3750, 49111a3b39ecSAndrew Lunn .g1_irqs = 9, 4912d6c5e6afSVivien Didelot .g2_irqs = 14, 4913f3645652SVivien Didelot .pvt = true, 4914b3e05aa1SVivien Didelot .multi_chip = true, 4915e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 49161a3b39ecSAndrew Lunn .ops = &mv88e6190_ops, 49171a3b39ecSAndrew Lunn }, 49181a3b39ecSAndrew Lunn 49191a3b39ecSAndrew Lunn [MV88E6190X] = { 4920107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X, 49211a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 49221a3b39ecSAndrew Lunn .name = "Marvell 88E6190X", 49231a3b39ecSAndrew Lunn .num_databases = 4096, 4924d9ea5620SAndrew Lunn .num_macs = 16384, 49251a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 492695150f29SHeiner Kallweit .num_internal_phys = 9, 4927a73ccd61SBrandon Streiff .num_gpio = 16, 4928931d1822SVivien Didelot .max_vid = 8191, 49291a3b39ecSAndrew Lunn .port_base_addr = 0x0, 49309255bacdSAndrew Lunn .phy_base_addr = 0x0, 49311a3b39ecSAndrew Lunn .global1_addr = 0x1b, 49329069c13aSVivien Didelot .global2_addr = 0x1c, 4933b91e055cSAndrew Lunn .age_time_coeff = 3750, 49341a3b39ecSAndrew Lunn .g1_irqs = 9, 4935d6c5e6afSVivien Didelot .g2_irqs = 14, 4936e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4937f3645652SVivien Didelot .pvt = true, 4938b3e05aa1SVivien Didelot .multi_chip = true, 4939443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 49401a3b39ecSAndrew Lunn .ops = &mv88e6190x_ops, 49411a3b39ecSAndrew Lunn }, 49421a3b39ecSAndrew Lunn 49431a3b39ecSAndrew Lunn [MV88E6191] = { 4944107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191, 49451a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 49461a3b39ecSAndrew Lunn .name = "Marvell 88E6191", 49471a3b39ecSAndrew Lunn .num_databases = 4096, 4948d9ea5620SAndrew Lunn .num_macs = 16384, 49491a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 495095150f29SHeiner Kallweit .num_internal_phys = 9, 4951931d1822SVivien Didelot .max_vid = 8191, 49521a3b39ecSAndrew Lunn .port_base_addr = 0x0, 49539255bacdSAndrew Lunn .phy_base_addr = 0x0, 49541a3b39ecSAndrew Lunn .global1_addr = 0x1b, 49559069c13aSVivien Didelot .global2_addr = 0x1c, 4956b91e055cSAndrew Lunn .age_time_coeff = 3750, 4957443d5a1bSAndrew Lunn .g1_irqs = 9, 4958d6c5e6afSVivien Didelot .g2_irqs = 14, 4959e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4960f3645652SVivien Didelot .pvt = true, 4961b3e05aa1SVivien Didelot .multi_chip = true, 4962443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 49632fa8d3afSBrandon Streiff .ptp_support = true, 49642cf4cefbSVivien Didelot .ops = &mv88e6191_ops, 49651a3b39ecSAndrew Lunn }, 49661a3b39ecSAndrew Lunn 496749022647SHubert Feurstein [MV88E6220] = { 496849022647SHubert Feurstein .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220, 496949022647SHubert Feurstein .family = MV88E6XXX_FAMILY_6250, 497049022647SHubert Feurstein .name = "Marvell 88E6220", 497149022647SHubert Feurstein .num_databases = 64, 497249022647SHubert Feurstein 497349022647SHubert Feurstein /* Ports 2-4 are not routed to pins 497449022647SHubert Feurstein * => usable ports 0, 1, 5, 6 497549022647SHubert Feurstein */ 497649022647SHubert Feurstein .num_ports = 7, 497749022647SHubert Feurstein .num_internal_phys = 2, 4978c857486aSHubert Feurstein .invalid_port_mask = BIT(2) | BIT(3) | BIT(4), 497949022647SHubert Feurstein .max_vid = 4095, 498049022647SHubert Feurstein .port_base_addr = 0x08, 498149022647SHubert Feurstein .phy_base_addr = 0x00, 498249022647SHubert Feurstein .global1_addr = 0x0f, 498349022647SHubert Feurstein .global2_addr = 0x07, 498449022647SHubert Feurstein .age_time_coeff = 15000, 498549022647SHubert Feurstein .g1_irqs = 9, 498649022647SHubert Feurstein .g2_irqs = 10, 498749022647SHubert Feurstein .atu_move_port_mask = 0xf, 498849022647SHubert Feurstein .dual_chip = true, 498949022647SHubert Feurstein .tag_protocol = DSA_TAG_PROTO_DSA, 499071509614SHubert Feurstein .ptp_support = true, 499149022647SHubert Feurstein .ops = &mv88e6250_ops, 499249022647SHubert Feurstein }, 499349022647SHubert Feurstein 4994fad09c73SVivien Didelot [MV88E6240] = { 4995107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240, 4996fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4997fad09c73SVivien Didelot .name = "Marvell 88E6240", 4998fad09c73SVivien Didelot .num_databases = 4096, 4999d9ea5620SAndrew Lunn .num_macs = 8192, 5000fad09c73SVivien Didelot .num_ports = 7, 5001bc393155SAndrew Lunn .num_internal_phys = 5, 5002a73ccd61SBrandon Streiff .num_gpio = 15, 50033cf3c846SVivien Didelot .max_vid = 4095, 5004fad09c73SVivien Didelot .port_base_addr = 0x10, 50059255bacdSAndrew Lunn .phy_base_addr = 0x0, 5006a935c052SVivien Didelot .global1_addr = 0x1b, 50079069c13aSVivien Didelot .global2_addr = 0x1c, 5008acddbd21SVivien Didelot .age_time_coeff = 15000, 5009dc30c35bSAndrew Lunn .g1_irqs = 9, 5010d6c5e6afSVivien Didelot .g2_irqs = 10, 5011e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5012f3645652SVivien Didelot .pvt = true, 5013b3e05aa1SVivien Didelot .multi_chip = true, 5014443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 50152fa8d3afSBrandon Streiff .ptp_support = true, 5016b3469dd8SVivien Didelot .ops = &mv88e6240_ops, 5017fad09c73SVivien Didelot }, 5018fad09c73SVivien Didelot 50191f71836fSRasmus Villemoes [MV88E6250] = { 50201f71836fSRasmus Villemoes .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250, 50211f71836fSRasmus Villemoes .family = MV88E6XXX_FAMILY_6250, 50221f71836fSRasmus Villemoes .name = "Marvell 88E6250", 50231f71836fSRasmus Villemoes .num_databases = 64, 50241f71836fSRasmus Villemoes .num_ports = 7, 50251f71836fSRasmus Villemoes .num_internal_phys = 5, 50261f71836fSRasmus Villemoes .max_vid = 4095, 50271f71836fSRasmus Villemoes .port_base_addr = 0x08, 50281f71836fSRasmus Villemoes .phy_base_addr = 0x00, 50291f71836fSRasmus Villemoes .global1_addr = 0x0f, 50301f71836fSRasmus Villemoes .global2_addr = 0x07, 50311f71836fSRasmus Villemoes .age_time_coeff = 15000, 50321f71836fSRasmus Villemoes .g1_irqs = 9, 50331f71836fSRasmus Villemoes .g2_irqs = 10, 50341f71836fSRasmus Villemoes .atu_move_port_mask = 0xf, 50351f71836fSRasmus Villemoes .dual_chip = true, 50361f71836fSRasmus Villemoes .tag_protocol = DSA_TAG_PROTO_DSA, 503771509614SHubert Feurstein .ptp_support = true, 50381f71836fSRasmus Villemoes .ops = &mv88e6250_ops, 50391f71836fSRasmus Villemoes }, 50401f71836fSRasmus Villemoes 50411a3b39ecSAndrew Lunn [MV88E6290] = { 5042107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290, 50431a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 50441a3b39ecSAndrew Lunn .name = "Marvell 88E6290", 50451a3b39ecSAndrew Lunn .num_databases = 4096, 50461a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 504795150f29SHeiner Kallweit .num_internal_phys = 9, 5048a73ccd61SBrandon Streiff .num_gpio = 16, 5049931d1822SVivien Didelot .max_vid = 8191, 50501a3b39ecSAndrew Lunn .port_base_addr = 0x0, 50519255bacdSAndrew Lunn .phy_base_addr = 0x0, 50521a3b39ecSAndrew Lunn .global1_addr = 0x1b, 50539069c13aSVivien Didelot .global2_addr = 0x1c, 5054b91e055cSAndrew Lunn .age_time_coeff = 3750, 50551a3b39ecSAndrew Lunn .g1_irqs = 9, 5056d6c5e6afSVivien Didelot .g2_irqs = 14, 5057e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5058f3645652SVivien Didelot .pvt = true, 5059b3e05aa1SVivien Didelot .multi_chip = true, 5060443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 50612fa8d3afSBrandon Streiff .ptp_support = true, 50621a3b39ecSAndrew Lunn .ops = &mv88e6290_ops, 50631a3b39ecSAndrew Lunn }, 50641a3b39ecSAndrew Lunn 5065fad09c73SVivien Didelot [MV88E6320] = { 5066107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320, 5067fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 5068fad09c73SVivien Didelot .name = "Marvell 88E6320", 5069fad09c73SVivien Didelot .num_databases = 4096, 5070d9ea5620SAndrew Lunn .num_macs = 8192, 5071fad09c73SVivien Didelot .num_ports = 7, 5072bc393155SAndrew Lunn .num_internal_phys = 5, 5073a73ccd61SBrandon Streiff .num_gpio = 15, 50743cf3c846SVivien Didelot .max_vid = 4095, 5075fad09c73SVivien Didelot .port_base_addr = 0x10, 50769255bacdSAndrew Lunn .phy_base_addr = 0x0, 5077a935c052SVivien Didelot .global1_addr = 0x1b, 50789069c13aSVivien Didelot .global2_addr = 0x1c, 5079acddbd21SVivien Didelot .age_time_coeff = 15000, 5080dc30c35bSAndrew Lunn .g1_irqs = 8, 5081bc393155SAndrew Lunn .g2_irqs = 10, 5082e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5083f3645652SVivien Didelot .pvt = true, 5084b3e05aa1SVivien Didelot .multi_chip = true, 5085443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 50862fa8d3afSBrandon Streiff .ptp_support = true, 5087b3469dd8SVivien Didelot .ops = &mv88e6320_ops, 5088fad09c73SVivien Didelot }, 5089fad09c73SVivien Didelot 5090fad09c73SVivien Didelot [MV88E6321] = { 5091107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321, 5092fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 5093fad09c73SVivien Didelot .name = "Marvell 88E6321", 5094fad09c73SVivien Didelot .num_databases = 4096, 5095d9ea5620SAndrew Lunn .num_macs = 8192, 5096fad09c73SVivien Didelot .num_ports = 7, 5097bc393155SAndrew Lunn .num_internal_phys = 5, 5098a73ccd61SBrandon Streiff .num_gpio = 15, 50993cf3c846SVivien Didelot .max_vid = 4095, 5100fad09c73SVivien Didelot .port_base_addr = 0x10, 51019255bacdSAndrew Lunn .phy_base_addr = 0x0, 5102a935c052SVivien Didelot .global1_addr = 0x1b, 51039069c13aSVivien Didelot .global2_addr = 0x1c, 5104acddbd21SVivien Didelot .age_time_coeff = 15000, 5105dc30c35bSAndrew Lunn .g1_irqs = 8, 5106bc393155SAndrew Lunn .g2_irqs = 10, 5107e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5108b3e05aa1SVivien Didelot .multi_chip = true, 5109443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 51102fa8d3afSBrandon Streiff .ptp_support = true, 5111b3469dd8SVivien Didelot .ops = &mv88e6321_ops, 5112fad09c73SVivien Didelot }, 5113fad09c73SVivien Didelot 5114a75961d0SGregory CLEMENT [MV88E6341] = { 5115107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, 5116a75961d0SGregory CLEMENT .family = MV88E6XXX_FAMILY_6341, 5117a75961d0SGregory CLEMENT .name = "Marvell 88E6341", 5118a75961d0SGregory CLEMENT .num_databases = 4096, 5119d9ea5620SAndrew Lunn .num_macs = 2048, 5120bc393155SAndrew Lunn .num_internal_phys = 5, 5121a75961d0SGregory CLEMENT .num_ports = 6, 5122a73ccd61SBrandon Streiff .num_gpio = 11, 51233cf3c846SVivien Didelot .max_vid = 4095, 5124a75961d0SGregory CLEMENT .port_base_addr = 0x10, 51259255bacdSAndrew Lunn .phy_base_addr = 0x10, 5126a75961d0SGregory CLEMENT .global1_addr = 0x1b, 51279069c13aSVivien Didelot .global2_addr = 0x1c, 5128a75961d0SGregory CLEMENT .age_time_coeff = 3750, 5129e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5130adfccf11SAndrew Lunn .g1_irqs = 9, 5131d6c5e6afSVivien Didelot .g2_irqs = 10, 5132f3645652SVivien Didelot .pvt = true, 5133b3e05aa1SVivien Didelot .multi_chip = true, 5134a75961d0SGregory CLEMENT .tag_protocol = DSA_TAG_PROTO_EDSA, 51352fa8d3afSBrandon Streiff .ptp_support = true, 5136a75961d0SGregory CLEMENT .ops = &mv88e6341_ops, 5137a75961d0SGregory CLEMENT }, 5138a75961d0SGregory CLEMENT 5139fad09c73SVivien Didelot [MV88E6350] = { 5140107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350, 5141fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 5142fad09c73SVivien Didelot .name = "Marvell 88E6350", 5143fad09c73SVivien Didelot .num_databases = 4096, 5144d9ea5620SAndrew Lunn .num_macs = 8192, 5145fad09c73SVivien Didelot .num_ports = 7, 5146bc393155SAndrew Lunn .num_internal_phys = 5, 51473cf3c846SVivien Didelot .max_vid = 4095, 5148fad09c73SVivien Didelot .port_base_addr = 0x10, 51499255bacdSAndrew Lunn .phy_base_addr = 0x0, 5150a935c052SVivien Didelot .global1_addr = 0x1b, 51519069c13aSVivien Didelot .global2_addr = 0x1c, 5152acddbd21SVivien Didelot .age_time_coeff = 15000, 5153dc30c35bSAndrew Lunn .g1_irqs = 9, 5154d6c5e6afSVivien Didelot .g2_irqs = 10, 5155e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5156f3645652SVivien Didelot .pvt = true, 5157b3e05aa1SVivien Didelot .multi_chip = true, 5158443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 5159b3469dd8SVivien Didelot .ops = &mv88e6350_ops, 5160fad09c73SVivien Didelot }, 5161fad09c73SVivien Didelot 5162fad09c73SVivien Didelot [MV88E6351] = { 5163107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351, 5164fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 5165fad09c73SVivien Didelot .name = "Marvell 88E6351", 5166fad09c73SVivien Didelot .num_databases = 4096, 5167d9ea5620SAndrew Lunn .num_macs = 8192, 5168fad09c73SVivien Didelot .num_ports = 7, 5169bc393155SAndrew Lunn .num_internal_phys = 5, 51703cf3c846SVivien Didelot .max_vid = 4095, 5171fad09c73SVivien Didelot .port_base_addr = 0x10, 51729255bacdSAndrew Lunn .phy_base_addr = 0x0, 5173a935c052SVivien Didelot .global1_addr = 0x1b, 51749069c13aSVivien Didelot .global2_addr = 0x1c, 5175acddbd21SVivien Didelot .age_time_coeff = 15000, 5176dc30c35bSAndrew Lunn .g1_irqs = 9, 5177d6c5e6afSVivien Didelot .g2_irqs = 10, 5178e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5179f3645652SVivien Didelot .pvt = true, 5180b3e05aa1SVivien Didelot .multi_chip = true, 5181443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 5182b3469dd8SVivien Didelot .ops = &mv88e6351_ops, 5183fad09c73SVivien Didelot }, 5184fad09c73SVivien Didelot 5185fad09c73SVivien Didelot [MV88E6352] = { 5186107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352, 5187fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 5188fad09c73SVivien Didelot .name = "Marvell 88E6352", 5189fad09c73SVivien Didelot .num_databases = 4096, 5190d9ea5620SAndrew Lunn .num_macs = 8192, 5191fad09c73SVivien Didelot .num_ports = 7, 5192bc393155SAndrew Lunn .num_internal_phys = 5, 5193a73ccd61SBrandon Streiff .num_gpio = 15, 51943cf3c846SVivien Didelot .max_vid = 4095, 5195fad09c73SVivien Didelot .port_base_addr = 0x10, 51969255bacdSAndrew Lunn .phy_base_addr = 0x0, 5197a935c052SVivien Didelot .global1_addr = 0x1b, 51989069c13aSVivien Didelot .global2_addr = 0x1c, 5199acddbd21SVivien Didelot .age_time_coeff = 15000, 5200dc30c35bSAndrew Lunn .g1_irqs = 9, 5201d6c5e6afSVivien Didelot .g2_irqs = 10, 5202e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5203f3645652SVivien Didelot .pvt = true, 5204b3e05aa1SVivien Didelot .multi_chip = true, 5205443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 52062fa8d3afSBrandon Streiff .ptp_support = true, 5207b3469dd8SVivien Didelot .ops = &mv88e6352_ops, 5208fad09c73SVivien Didelot }, 52091a3b39ecSAndrew Lunn [MV88E6390] = { 5210107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, 52111a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 52121a3b39ecSAndrew Lunn .name = "Marvell 88E6390", 52131a3b39ecSAndrew Lunn .num_databases = 4096, 5214d9ea5620SAndrew Lunn .num_macs = 16384, 52151a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 521695150f29SHeiner Kallweit .num_internal_phys = 9, 5217a73ccd61SBrandon Streiff .num_gpio = 16, 5218931d1822SVivien Didelot .max_vid = 8191, 52191a3b39ecSAndrew Lunn .port_base_addr = 0x0, 52209255bacdSAndrew Lunn .phy_base_addr = 0x0, 52211a3b39ecSAndrew Lunn .global1_addr = 0x1b, 52229069c13aSVivien Didelot .global2_addr = 0x1c, 5223b91e055cSAndrew Lunn .age_time_coeff = 3750, 52241a3b39ecSAndrew Lunn .g1_irqs = 9, 5225d6c5e6afSVivien Didelot .g2_irqs = 14, 5226e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5227f3645652SVivien Didelot .pvt = true, 5228b3e05aa1SVivien Didelot .multi_chip = true, 5229443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 52302fa8d3afSBrandon Streiff .ptp_support = true, 52311a3b39ecSAndrew Lunn .ops = &mv88e6390_ops, 52321a3b39ecSAndrew Lunn }, 52331a3b39ecSAndrew Lunn [MV88E6390X] = { 5234107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X, 52351a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 52361a3b39ecSAndrew Lunn .name = "Marvell 88E6390X", 52371a3b39ecSAndrew Lunn .num_databases = 4096, 5238d9ea5620SAndrew Lunn .num_macs = 16384, 52391a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 524095150f29SHeiner Kallweit .num_internal_phys = 9, 5241a73ccd61SBrandon Streiff .num_gpio = 16, 5242931d1822SVivien Didelot .max_vid = 8191, 52431a3b39ecSAndrew Lunn .port_base_addr = 0x0, 52449255bacdSAndrew Lunn .phy_base_addr = 0x0, 52451a3b39ecSAndrew Lunn .global1_addr = 0x1b, 52469069c13aSVivien Didelot .global2_addr = 0x1c, 5247b91e055cSAndrew Lunn .age_time_coeff = 3750, 52481a3b39ecSAndrew Lunn .g1_irqs = 9, 5249d6c5e6afSVivien Didelot .g2_irqs = 14, 5250e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5251f3645652SVivien Didelot .pvt = true, 5252b3e05aa1SVivien Didelot .multi_chip = true, 5253443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 52542fa8d3afSBrandon Streiff .ptp_support = true, 52551a3b39ecSAndrew Lunn .ops = &mv88e6390x_ops, 52561a3b39ecSAndrew Lunn }, 5257fad09c73SVivien Didelot }; 5258fad09c73SVivien Didelot 5259fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) 5260fad09c73SVivien Didelot { 5261fad09c73SVivien Didelot int i; 5262fad09c73SVivien Didelot 5263fad09c73SVivien Didelot for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i) 5264fad09c73SVivien Didelot if (mv88e6xxx_table[i].prod_num == prod_num) 5265fad09c73SVivien Didelot return &mv88e6xxx_table[i]; 5266fad09c73SVivien Didelot 5267fad09c73SVivien Didelot return NULL; 5268fad09c73SVivien Didelot } 5269fad09c73SVivien Didelot 5270fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip) 5271fad09c73SVivien Didelot { 5272fad09c73SVivien Didelot const struct mv88e6xxx_info *info; 52738f6345b2SVivien Didelot unsigned int prod_num, rev; 52748f6345b2SVivien Didelot u16 id; 52758f6345b2SVivien Didelot int err; 5276fad09c73SVivien Didelot 5277c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5278107fcc10SVivien Didelot err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id); 5279c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 52808f6345b2SVivien Didelot if (err) 52818f6345b2SVivien Didelot return err; 5282fad09c73SVivien Didelot 5283107fcc10SVivien Didelot prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK; 5284107fcc10SVivien Didelot rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK; 5285fad09c73SVivien Didelot 5286fad09c73SVivien Didelot info = mv88e6xxx_lookup_info(prod_num); 5287fad09c73SVivien Didelot if (!info) 5288fad09c73SVivien Didelot return -ENODEV; 5289fad09c73SVivien Didelot 5290fad09c73SVivien Didelot /* Update the compatible info with the probed one */ 5291fad09c73SVivien Didelot chip->info = info; 5292fad09c73SVivien Didelot 5293ca070c10SVivien Didelot err = mv88e6xxx_g2_require(chip); 5294ca070c10SVivien Didelot if (err) 5295ca070c10SVivien Didelot return err; 5296ca070c10SVivien Didelot 5297fad09c73SVivien Didelot dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n", 5298fad09c73SVivien Didelot chip->info->prod_num, chip->info->name, rev); 5299fad09c73SVivien Didelot 5300fad09c73SVivien Didelot return 0; 5301fad09c73SVivien Didelot } 5302fad09c73SVivien Didelot 5303fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) 5304fad09c73SVivien Didelot { 5305fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 5306fad09c73SVivien Didelot 5307fad09c73SVivien Didelot chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 5308fad09c73SVivien Didelot if (!chip) 5309fad09c73SVivien Didelot return NULL; 5310fad09c73SVivien Didelot 5311fad09c73SVivien Didelot chip->dev = dev; 5312fad09c73SVivien Didelot 5313fad09c73SVivien Didelot mutex_init(&chip->reg_lock); 5314a3c53be5SAndrew Lunn INIT_LIST_HEAD(&chip->mdios); 5315da7dc875SVivien Didelot idr_init(&chip->policies); 5316fad09c73SVivien Didelot 5317fad09c73SVivien Didelot return chip; 5318fad09c73SVivien Didelot } 5319fad09c73SVivien Didelot 53205ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds, 53214d776482SFlorian Fainelli int port, 53224d776482SFlorian Fainelli enum dsa_tag_protocol m) 53237b314362SAndrew Lunn { 532404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 53252bbb33beSAndrew Lunn 5326443d5a1bSAndrew Lunn return chip->info->tag_protocol; 53277b314362SAndrew Lunn } 53287b314362SAndrew Lunn 53297df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port, 53303709aadcSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 53317df8fbddSVivien Didelot { 53327df8fbddSVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 53337df8fbddSVivien Didelot * so skip the prepare phase. 53347df8fbddSVivien Didelot */ 53357df8fbddSVivien Didelot 53367df8fbddSVivien Didelot return 0; 53377df8fbddSVivien Didelot } 53387df8fbddSVivien Didelot 53397df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port, 53403709aadcSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 53417df8fbddSVivien Didelot { 534204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 53437df8fbddSVivien Didelot 5344c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 53457df8fbddSVivien Didelot if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 534627c0e600SVivien Didelot MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC)) 5347774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to load multicast MAC address\n", 5348774439e5SVivien Didelot port); 5349c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 53507df8fbddSVivien Didelot } 53517df8fbddSVivien Didelot 53527df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, 53537df8fbddSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 53547df8fbddSVivien Didelot { 535504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 53567df8fbddSVivien Didelot int err; 53577df8fbddSVivien Didelot 5358c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5359d8291a95SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0); 5360c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 53617df8fbddSVivien Didelot 53627df8fbddSVivien Didelot return err; 53637df8fbddSVivien Didelot } 53647df8fbddSVivien Didelot 5365f0942e00SIwan R Timmer static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port, 5366f0942e00SIwan R Timmer struct dsa_mall_mirror_tc_entry *mirror, 5367f0942e00SIwan R Timmer bool ingress) 5368f0942e00SIwan R Timmer { 5369f0942e00SIwan R Timmer enum mv88e6xxx_egress_direction direction = ingress ? 5370f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS : 5371f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS; 5372f0942e00SIwan R Timmer struct mv88e6xxx_chip *chip = ds->priv; 5373f0942e00SIwan R Timmer bool other_mirrors = false; 5374f0942e00SIwan R Timmer int i; 5375f0942e00SIwan R Timmer int err; 5376f0942e00SIwan R Timmer 5377f0942e00SIwan R Timmer if (!chip->info->ops->set_egress_port) 5378f0942e00SIwan R Timmer return -EOPNOTSUPP; 5379f0942e00SIwan R Timmer 5380f0942e00SIwan R Timmer mutex_lock(&chip->reg_lock); 5381f0942e00SIwan R Timmer if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) != 5382f0942e00SIwan R Timmer mirror->to_local_port) { 5383f0942e00SIwan R Timmer for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 5384f0942e00SIwan R Timmer other_mirrors |= ingress ? 5385f0942e00SIwan R Timmer chip->ports[i].mirror_ingress : 5386f0942e00SIwan R Timmer chip->ports[i].mirror_egress; 5387f0942e00SIwan R Timmer 5388f0942e00SIwan R Timmer /* Can't change egress port when other mirror is active */ 5389f0942e00SIwan R Timmer if (other_mirrors) { 5390f0942e00SIwan R Timmer err = -EBUSY; 5391f0942e00SIwan R Timmer goto out; 5392f0942e00SIwan R Timmer } 5393f0942e00SIwan R Timmer 5394f0942e00SIwan R Timmer err = chip->info->ops->set_egress_port(chip, 5395f0942e00SIwan R Timmer direction, 5396f0942e00SIwan R Timmer mirror->to_local_port); 5397f0942e00SIwan R Timmer if (err) 5398f0942e00SIwan R Timmer goto out; 5399f0942e00SIwan R Timmer } 5400f0942e00SIwan R Timmer 5401f0942e00SIwan R Timmer err = mv88e6xxx_port_set_mirror(chip, port, direction, true); 5402f0942e00SIwan R Timmer out: 5403f0942e00SIwan R Timmer mutex_unlock(&chip->reg_lock); 5404f0942e00SIwan R Timmer 5405f0942e00SIwan R Timmer return err; 5406f0942e00SIwan R Timmer } 5407f0942e00SIwan R Timmer 5408f0942e00SIwan R Timmer static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port, 5409f0942e00SIwan R Timmer struct dsa_mall_mirror_tc_entry *mirror) 5410f0942e00SIwan R Timmer { 5411f0942e00SIwan R Timmer enum mv88e6xxx_egress_direction direction = mirror->ingress ? 5412f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS : 5413f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS; 5414f0942e00SIwan R Timmer struct mv88e6xxx_chip *chip = ds->priv; 5415f0942e00SIwan R Timmer bool other_mirrors = false; 5416f0942e00SIwan R Timmer int i; 5417f0942e00SIwan R Timmer 5418f0942e00SIwan R Timmer mutex_lock(&chip->reg_lock); 5419f0942e00SIwan R Timmer if (mv88e6xxx_port_set_mirror(chip, port, direction, false)) 5420f0942e00SIwan R Timmer dev_err(ds->dev, "p%d: failed to disable mirroring\n", port); 5421f0942e00SIwan R Timmer 5422f0942e00SIwan R Timmer for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 5423f0942e00SIwan R Timmer other_mirrors |= mirror->ingress ? 5424f0942e00SIwan R Timmer chip->ports[i].mirror_ingress : 5425f0942e00SIwan R Timmer chip->ports[i].mirror_egress; 5426f0942e00SIwan R Timmer 5427f0942e00SIwan R Timmer /* Reset egress port when no other mirror is active */ 5428f0942e00SIwan R Timmer if (!other_mirrors) { 5429f0942e00SIwan R Timmer if (chip->info->ops->set_egress_port(chip, 5430f0942e00SIwan R Timmer direction, 5431f0942e00SIwan R Timmer dsa_upstream_port(ds, 54324e4637b1SColin Ian King port))) 5433f0942e00SIwan R Timmer dev_err(ds->dev, "failed to set egress port\n"); 5434f0942e00SIwan R Timmer } 5435f0942e00SIwan R Timmer 5436f0942e00SIwan R Timmer mutex_unlock(&chip->reg_lock); 5437f0942e00SIwan R Timmer } 5438f0942e00SIwan R Timmer 54394f85901fSRussell King static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port, 54404f85901fSRussell King bool unicast, bool multicast) 54414f85901fSRussell King { 54424f85901fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 54434f85901fSRussell King int err = -EOPNOTSUPP; 54444f85901fSRussell King 5445c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 54464f85901fSRussell King if (chip->info->ops->port_set_egress_floods) 54474f85901fSRussell King err = chip->info->ops->port_set_egress_floods(chip, port, 54484f85901fSRussell King unicast, 54494f85901fSRussell King multicast); 5450c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 54514f85901fSRussell King 54524f85901fSRussell King return err; 54534f85901fSRussell King } 54544f85901fSRussell King 5455a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = { 54567b314362SAndrew Lunn .get_tag_protocol = mv88e6xxx_get_tag_protocol, 5457fad09c73SVivien Didelot .setup = mv88e6xxx_setup, 545823e8b470SAndrew Lunn .teardown = mv88e6xxx_teardown, 5459c9a2356fSRussell King .phylink_validate = mv88e6xxx_validate, 5460c9a2356fSRussell King .phylink_mac_link_state = mv88e6xxx_link_state, 5461c9a2356fSRussell King .phylink_mac_config = mv88e6xxx_mac_config, 5462c9a2356fSRussell King .phylink_mac_link_down = mv88e6xxx_mac_link_down, 5463c9a2356fSRussell King .phylink_mac_link_up = mv88e6xxx_mac_link_up, 5464fad09c73SVivien Didelot .get_strings = mv88e6xxx_get_strings, 5465fad09c73SVivien Didelot .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, 5466fad09c73SVivien Didelot .get_sset_count = mv88e6xxx_get_sset_count, 546704aca993SAndrew Lunn .port_enable = mv88e6xxx_port_enable, 546804aca993SAndrew Lunn .port_disable = mv88e6xxx_port_disable, 546908f50061SVivien Didelot .get_mac_eee = mv88e6xxx_get_mac_eee, 547008f50061SVivien Didelot .set_mac_eee = mv88e6xxx_set_mac_eee, 5471fad09c73SVivien Didelot .get_eeprom_len = mv88e6xxx_get_eeprom_len, 5472fad09c73SVivien Didelot .get_eeprom = mv88e6xxx_get_eeprom, 5473fad09c73SVivien Didelot .set_eeprom = mv88e6xxx_set_eeprom, 5474fad09c73SVivien Didelot .get_regs_len = mv88e6xxx_get_regs_len, 5475fad09c73SVivien Didelot .get_regs = mv88e6xxx_get_regs, 5476da7dc875SVivien Didelot .get_rxnfc = mv88e6xxx_get_rxnfc, 5477da7dc875SVivien Didelot .set_rxnfc = mv88e6xxx_set_rxnfc, 54782cfcd964SVivien Didelot .set_ageing_time = mv88e6xxx_set_ageing_time, 5479fad09c73SVivien Didelot .port_bridge_join = mv88e6xxx_port_bridge_join, 5480fad09c73SVivien Didelot .port_bridge_leave = mv88e6xxx_port_bridge_leave, 54814f85901fSRussell King .port_egress_floods = mv88e6xxx_port_egress_floods, 5482fad09c73SVivien Didelot .port_stp_state_set = mv88e6xxx_port_stp_state_set, 5483749efcb8SVivien Didelot .port_fast_age = mv88e6xxx_port_fast_age, 5484fad09c73SVivien Didelot .port_vlan_filtering = mv88e6xxx_port_vlan_filtering, 5485fad09c73SVivien Didelot .port_vlan_prepare = mv88e6xxx_port_vlan_prepare, 5486fad09c73SVivien Didelot .port_vlan_add = mv88e6xxx_port_vlan_add, 5487fad09c73SVivien Didelot .port_vlan_del = mv88e6xxx_port_vlan_del, 5488fad09c73SVivien Didelot .port_fdb_add = mv88e6xxx_port_fdb_add, 5489fad09c73SVivien Didelot .port_fdb_del = mv88e6xxx_port_fdb_del, 5490fad09c73SVivien Didelot .port_fdb_dump = mv88e6xxx_port_fdb_dump, 54917df8fbddSVivien Didelot .port_mdb_prepare = mv88e6xxx_port_mdb_prepare, 54927df8fbddSVivien Didelot .port_mdb_add = mv88e6xxx_port_mdb_add, 54937df8fbddSVivien Didelot .port_mdb_del = mv88e6xxx_port_mdb_del, 5494f0942e00SIwan R Timmer .port_mirror_add = mv88e6xxx_port_mirror_add, 5495f0942e00SIwan R Timmer .port_mirror_del = mv88e6xxx_port_mirror_del, 5496aec5ac88SVivien Didelot .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join, 5497aec5ac88SVivien Didelot .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave, 5498c6fe0ad2SBrandon Streiff .port_hwtstamp_set = mv88e6xxx_port_hwtstamp_set, 5499c6fe0ad2SBrandon Streiff .port_hwtstamp_get = mv88e6xxx_port_hwtstamp_get, 5500c6fe0ad2SBrandon Streiff .port_txtstamp = mv88e6xxx_port_txtstamp, 5501c6fe0ad2SBrandon Streiff .port_rxtstamp = mv88e6xxx_port_rxtstamp, 5502c6fe0ad2SBrandon Streiff .get_ts_info = mv88e6xxx_get_ts_info, 550323e8b470SAndrew Lunn .devlink_param_get = mv88e6xxx_devlink_param_get, 550423e8b470SAndrew Lunn .devlink_param_set = mv88e6xxx_devlink_param_set, 5505fad09c73SVivien Didelot }; 5506fad09c73SVivien Didelot 550755ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) 5508fad09c73SVivien Didelot { 5509fad09c73SVivien Didelot struct device *dev = chip->dev; 5510fad09c73SVivien Didelot struct dsa_switch *ds; 5511fad09c73SVivien Didelot 55127e99e347SVivien Didelot ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); 5513fad09c73SVivien Didelot if (!ds) 5514fad09c73SVivien Didelot return -ENOMEM; 5515fad09c73SVivien Didelot 55167e99e347SVivien Didelot ds->dev = dev; 55177e99e347SVivien Didelot ds->num_ports = mv88e6xxx_num_ports(chip); 5518fad09c73SVivien Didelot ds->priv = chip; 5519877b7cb0SAndrew Lunn ds->dev = dev; 55209d490b4eSVivien Didelot ds->ops = &mv88e6xxx_switch_ops; 55219ff74f24SVivien Didelot ds->ageing_time_min = chip->info->age_time_coeff; 55229ff74f24SVivien Didelot ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; 5523fad09c73SVivien Didelot 5524fad09c73SVivien Didelot dev_set_drvdata(dev, ds); 5525fad09c73SVivien Didelot 552623c9ee49SVivien Didelot return dsa_register_switch(ds); 5527fad09c73SVivien Didelot } 5528fad09c73SVivien Didelot 5529fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip) 5530fad09c73SVivien Didelot { 5531fad09c73SVivien Didelot dsa_unregister_switch(chip->ds); 5532fad09c73SVivien Didelot } 5533fad09c73SVivien Didelot 5534877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev) 5535877b7cb0SAndrew Lunn { 5536877b7cb0SAndrew Lunn const struct of_device_id *matches = dev->driver->of_match_table; 5537877b7cb0SAndrew Lunn const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data; 5538877b7cb0SAndrew Lunn 5539877b7cb0SAndrew Lunn for (; matches->name[0] || matches->type[0] || matches->compatible[0]; 5540877b7cb0SAndrew Lunn matches++) { 5541877b7cb0SAndrew Lunn if (!strcmp(pdata->compatible, matches->compatible)) 5542877b7cb0SAndrew Lunn return matches->data; 5543877b7cb0SAndrew Lunn } 5544877b7cb0SAndrew Lunn return NULL; 5545877b7cb0SAndrew Lunn } 5546877b7cb0SAndrew Lunn 5547bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration 5548bcd3d9d9SMiquel Raynal * would be lost after a power cycle so prevent it to be suspended. 5549bcd3d9d9SMiquel Raynal */ 5550bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev) 5551bcd3d9d9SMiquel Raynal { 5552bcd3d9d9SMiquel Raynal return -EOPNOTSUPP; 5553bcd3d9d9SMiquel Raynal } 5554bcd3d9d9SMiquel Raynal 5555bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev) 5556bcd3d9d9SMiquel Raynal { 5557bcd3d9d9SMiquel Raynal return 0; 5558bcd3d9d9SMiquel Raynal } 5559bcd3d9d9SMiquel Raynal 5560bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume); 5561bcd3d9d9SMiquel Raynal 5562fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev) 5563fad09c73SVivien Didelot { 5564877b7cb0SAndrew Lunn struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data; 55657ddae24fSDavid S. Miller const struct mv88e6xxx_info *compat_info = NULL; 5566fad09c73SVivien Didelot struct device *dev = &mdiodev->dev; 5567fad09c73SVivien Didelot struct device_node *np = dev->of_node; 5568fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 5569877b7cb0SAndrew Lunn int port; 5570fad09c73SVivien Didelot int err; 5571fad09c73SVivien Didelot 55727bb8c996SAndrew Lunn if (!np && !pdata) 55737bb8c996SAndrew Lunn return -EINVAL; 55747bb8c996SAndrew Lunn 5575877b7cb0SAndrew Lunn if (np) 5576fad09c73SVivien Didelot compat_info = of_device_get_match_data(dev); 5577877b7cb0SAndrew Lunn 5578877b7cb0SAndrew Lunn if (pdata) { 5579877b7cb0SAndrew Lunn compat_info = pdata_device_get_match_data(dev); 5580877b7cb0SAndrew Lunn 5581877b7cb0SAndrew Lunn if (!pdata->netdev) 5582877b7cb0SAndrew Lunn return -EINVAL; 5583877b7cb0SAndrew Lunn 5584877b7cb0SAndrew Lunn for (port = 0; port < DSA_MAX_PORTS; port++) { 5585877b7cb0SAndrew Lunn if (!(pdata->enabled_ports & (1 << port))) 5586877b7cb0SAndrew Lunn continue; 5587877b7cb0SAndrew Lunn if (strcmp(pdata->cd.port_names[port], "cpu")) 5588877b7cb0SAndrew Lunn continue; 5589877b7cb0SAndrew Lunn pdata->cd.netdev[port] = &pdata->netdev->dev; 5590877b7cb0SAndrew Lunn break; 5591877b7cb0SAndrew Lunn } 5592877b7cb0SAndrew Lunn } 5593877b7cb0SAndrew Lunn 5594fad09c73SVivien Didelot if (!compat_info) 5595fad09c73SVivien Didelot return -EINVAL; 5596fad09c73SVivien Didelot 5597fad09c73SVivien Didelot chip = mv88e6xxx_alloc_chip(dev); 5598877b7cb0SAndrew Lunn if (!chip) { 5599877b7cb0SAndrew Lunn err = -ENOMEM; 5600877b7cb0SAndrew Lunn goto out; 5601877b7cb0SAndrew Lunn } 5602fad09c73SVivien Didelot 5603fad09c73SVivien Didelot chip->info = compat_info; 5604fad09c73SVivien Didelot 5605fad09c73SVivien Didelot err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr); 5606fad09c73SVivien Didelot if (err) 5607877b7cb0SAndrew Lunn goto out; 5608fad09c73SVivien Didelot 5609b4308f04SAndrew Lunn chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 5610877b7cb0SAndrew Lunn if (IS_ERR(chip->reset)) { 5611877b7cb0SAndrew Lunn err = PTR_ERR(chip->reset); 5612877b7cb0SAndrew Lunn goto out; 5613877b7cb0SAndrew Lunn } 56147b75e49dSBaruch Siach if (chip->reset) 56157b75e49dSBaruch Siach usleep_range(1000, 2000); 5616b4308f04SAndrew Lunn 5617fad09c73SVivien Didelot err = mv88e6xxx_detect(chip); 5618fad09c73SVivien Didelot if (err) 5619877b7cb0SAndrew Lunn goto out; 5620fad09c73SVivien Didelot 5621e57e5e77SVivien Didelot mv88e6xxx_phy_init(chip); 5622e57e5e77SVivien Didelot 562300baabe5SAndrew Lunn if (chip->info->ops->get_eeprom) { 562400baabe5SAndrew Lunn if (np) 562500baabe5SAndrew Lunn of_property_read_u32(np, "eeprom-length", 562600baabe5SAndrew Lunn &chip->eeprom_len); 562700baabe5SAndrew Lunn else 562800baabe5SAndrew Lunn chip->eeprom_len = pdata->eeprom_len; 562900baabe5SAndrew Lunn } 5630fad09c73SVivien Didelot 5631c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5632dc30c35bSAndrew Lunn err = mv88e6xxx_switch_reset(chip); 5633c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 5634fad09c73SVivien Didelot if (err) 5635dc30c35bSAndrew Lunn goto out; 5636fad09c73SVivien Didelot 5637a27415deSAndrew Lunn if (np) { 5638dc30c35bSAndrew Lunn chip->irq = of_irq_get(np, 0); 5639dc30c35bSAndrew Lunn if (chip->irq == -EPROBE_DEFER) { 5640dc30c35bSAndrew Lunn err = chip->irq; 5641dc30c35bSAndrew Lunn goto out; 5642fad09c73SVivien Didelot } 5643a27415deSAndrew Lunn } 5644a27415deSAndrew Lunn 5645a27415deSAndrew Lunn if (pdata) 5646a27415deSAndrew Lunn chip->irq = pdata->irq; 5647fad09c73SVivien Didelot 5648294d711eSAndrew Lunn /* Has to be performed before the MDIO bus is created, because 5649a708767eSUwe Kleine-König * the PHYs will link their interrupts to these interrupt 5650294d711eSAndrew Lunn * controllers 5651dc30c35bSAndrew Lunn */ 5652c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5653294d711eSAndrew Lunn if (chip->irq > 0) 5654dc30c35bSAndrew Lunn err = mv88e6xxx_g1_irq_setup(chip); 5655294d711eSAndrew Lunn else 5656294d711eSAndrew Lunn err = mv88e6xxx_irq_poll_setup(chip); 5657c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 5658dc30c35bSAndrew Lunn 5659dc30c35bSAndrew Lunn if (err) 5660dc30c35bSAndrew Lunn goto out; 5661dc30c35bSAndrew Lunn 5662d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) { 5663dc30c35bSAndrew Lunn err = mv88e6xxx_g2_irq_setup(chip); 5664dc30c35bSAndrew Lunn if (err) 5665dc30c35bSAndrew Lunn goto out_g1_irq; 5666dc30c35bSAndrew Lunn } 56670977644cSAndrew Lunn 56680977644cSAndrew Lunn err = mv88e6xxx_g1_atu_prob_irq_setup(chip); 56690977644cSAndrew Lunn if (err) 56700977644cSAndrew Lunn goto out_g2_irq; 567162eb1162SAndrew Lunn 567262eb1162SAndrew Lunn err = mv88e6xxx_g1_vtu_prob_irq_setup(chip); 567362eb1162SAndrew Lunn if (err) 567462eb1162SAndrew Lunn goto out_g1_atu_prob_irq; 5675dc30c35bSAndrew Lunn 5676a3c53be5SAndrew Lunn err = mv88e6xxx_mdios_register(chip, np); 5677dc30c35bSAndrew Lunn if (err) 567862eb1162SAndrew Lunn goto out_g1_vtu_prob_irq; 5679dc30c35bSAndrew Lunn 568055ed0ce0SFlorian Fainelli err = mv88e6xxx_register_switch(chip); 5681dc30c35bSAndrew Lunn if (err) 5682dc30c35bSAndrew Lunn goto out_mdio; 5683dc30c35bSAndrew Lunn 5684fad09c73SVivien Didelot return 0; 5685dc30c35bSAndrew Lunn 5686dc30c35bSAndrew Lunn out_mdio: 5687a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 568862eb1162SAndrew Lunn out_g1_vtu_prob_irq: 568962eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 56900977644cSAndrew Lunn out_g1_atu_prob_irq: 56910977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 5692dc30c35bSAndrew Lunn out_g2_irq: 5693294d711eSAndrew Lunn if (chip->info->g2_irqs > 0) 5694dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 5695dc30c35bSAndrew Lunn out_g1_irq: 5696294d711eSAndrew Lunn if (chip->irq > 0) 5697dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 5698294d711eSAndrew Lunn else 5699294d711eSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 5700dc30c35bSAndrew Lunn out: 5701877b7cb0SAndrew Lunn if (pdata) 5702877b7cb0SAndrew Lunn dev_put(pdata->netdev); 5703877b7cb0SAndrew Lunn 5704dc30c35bSAndrew Lunn return err; 5705fad09c73SVivien Didelot } 5706fad09c73SVivien Didelot 5707fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev) 5708fad09c73SVivien Didelot { 5709fad09c73SVivien Didelot struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 571004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 5711fad09c73SVivien Didelot 5712c6fe0ad2SBrandon Streiff if (chip->info->ptp_support) { 5713c6fe0ad2SBrandon Streiff mv88e6xxx_hwtstamp_free(chip); 57142fa8d3afSBrandon Streiff mv88e6xxx_ptp_free(chip); 5715c6fe0ad2SBrandon Streiff } 57162fa8d3afSBrandon Streiff 5717930188ceSAndrew Lunn mv88e6xxx_phy_destroy(chip); 5718fad09c73SVivien Didelot mv88e6xxx_unregister_switch(chip); 5719a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 5720dc30c35bSAndrew Lunn 572162eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 57220977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 572376f38f1fSAndrew Lunn 5724d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) 5725dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 572676f38f1fSAndrew Lunn 572776f38f1fSAndrew Lunn if (chip->irq > 0) 5728dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 572976f38f1fSAndrew Lunn else 573076f38f1fSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 5731fad09c73SVivien Didelot } 5732fad09c73SVivien Didelot 5733fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = { 5734fad09c73SVivien Didelot { 5735fad09c73SVivien Didelot .compatible = "marvell,mv88e6085", 5736fad09c73SVivien Didelot .data = &mv88e6xxx_table[MV88E6085], 5737fad09c73SVivien Didelot }, 57381a3b39ecSAndrew Lunn { 57391a3b39ecSAndrew Lunn .compatible = "marvell,mv88e6190", 57401a3b39ecSAndrew Lunn .data = &mv88e6xxx_table[MV88E6190], 57411a3b39ecSAndrew Lunn }, 57421f71836fSRasmus Villemoes { 57431f71836fSRasmus Villemoes .compatible = "marvell,mv88e6250", 57441f71836fSRasmus Villemoes .data = &mv88e6xxx_table[MV88E6250], 57451f71836fSRasmus Villemoes }, 5746fad09c73SVivien Didelot { /* sentinel */ }, 5747fad09c73SVivien Didelot }; 5748fad09c73SVivien Didelot 5749fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match); 5750fad09c73SVivien Didelot 5751fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = { 5752fad09c73SVivien Didelot .probe = mv88e6xxx_probe, 5753fad09c73SVivien Didelot .remove = mv88e6xxx_remove, 5754fad09c73SVivien Didelot .mdiodrv.driver = { 5755fad09c73SVivien Didelot .name = "mv88e6085", 5756fad09c73SVivien Didelot .of_match_table = mv88e6xxx_of_match, 5757bcd3d9d9SMiquel Raynal .pm = &mv88e6xxx_pm_ops, 5758fad09c73SVivien Didelot }, 5759fad09c73SVivien Didelot }; 5760fad09c73SVivien Didelot 57617324d50eSAndrew Lunn mdio_module_driver(mv88e6xxx_driver); 5762fad09c73SVivien Didelot 5763fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); 5764fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips"); 5765fad09c73SVivien Didelot MODULE_LICENSE("GPL"); 5766