1fad09c73SVivien Didelot /* 2fad09c73SVivien Didelot * Marvell 88e6xxx Ethernet switch single-chip support 3fad09c73SVivien Didelot * 4fad09c73SVivien Didelot * Copyright (c) 2008 Marvell Semiconductor 5fad09c73SVivien Didelot * 6fad09c73SVivien Didelot * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch> 7fad09c73SVivien Didelot * 84333d619SVivien Didelot * Copyright (c) 2016-2017 Savoir-faire Linux Inc. 94333d619SVivien Didelot * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 104333d619SVivien Didelot * 11fad09c73SVivien Didelot * This program is free software; you can redistribute it and/or modify 12fad09c73SVivien Didelot * it under the terms of the GNU General Public License as published by 13fad09c73SVivien Didelot * the Free Software Foundation; either version 2 of the License, or 14fad09c73SVivien Didelot * (at your option) any later version. 15fad09c73SVivien Didelot */ 16fad09c73SVivien Didelot 17fad09c73SVivien Didelot #include <linux/delay.h> 18fad09c73SVivien Didelot #include <linux/etherdevice.h> 19fad09c73SVivien Didelot #include <linux/ethtool.h> 20fad09c73SVivien Didelot #include <linux/if_bridge.h> 21dc30c35bSAndrew Lunn #include <linux/interrupt.h> 22dc30c35bSAndrew Lunn #include <linux/irq.h> 23dc30c35bSAndrew Lunn #include <linux/irqdomain.h> 24fad09c73SVivien Didelot #include <linux/jiffies.h> 25fad09c73SVivien Didelot #include <linux/list.h> 26fad09c73SVivien Didelot #include <linux/mdio.h> 27fad09c73SVivien Didelot #include <linux/module.h> 28fad09c73SVivien Didelot #include <linux/of_device.h> 29dc30c35bSAndrew Lunn #include <linux/of_irq.h> 30fad09c73SVivien Didelot #include <linux/of_mdio.h> 31fad09c73SVivien Didelot #include <linux/netdevice.h> 32fad09c73SVivien Didelot #include <linux/gpio/consumer.h> 33fad09c73SVivien Didelot #include <linux/phy.h> 34fad09c73SVivien Didelot #include <net/dsa.h> 35ec561276SVivien Didelot 36fad09c73SVivien Didelot #include "mv88e6xxx.h" 37a935c052SVivien Didelot #include "global1.h" 38ec561276SVivien Didelot #include "global2.h" 3910fa5bfcSAndrew Lunn #include "phy.h" 4018abed21SVivien Didelot #include "port.h" 416d91782fSAndrew Lunn #include "serdes.h" 42fad09c73SVivien Didelot 43fad09c73SVivien Didelot static void assert_reg_lock(struct mv88e6xxx_chip *chip) 44fad09c73SVivien Didelot { 45fad09c73SVivien Didelot if (unlikely(!mutex_is_locked(&chip->reg_lock))) { 46fad09c73SVivien Didelot dev_err(chip->dev, "Switch registers lock not held!\n"); 47fad09c73SVivien Didelot dump_stack(); 48fad09c73SVivien Didelot } 49fad09c73SVivien Didelot } 50fad09c73SVivien Didelot 51fad09c73SVivien Didelot /* The switch ADDR[4:1] configuration pins define the chip SMI device address 52fad09c73SVivien Didelot * (ADDR[0] is always zero, thus only even SMI addresses can be strapped). 53fad09c73SVivien Didelot * 54fad09c73SVivien Didelot * When ADDR is all zero, the chip uses Single-chip Addressing Mode, assuming it 55fad09c73SVivien Didelot * is the only device connected to the SMI master. In this mode it responds to 56fad09c73SVivien Didelot * all 32 possible SMI addresses, and thus maps directly the internal devices. 57fad09c73SVivien Didelot * 58fad09c73SVivien Didelot * When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing 59fad09c73SVivien Didelot * multiple devices to share the SMI interface. In this mode it responds to only 60fad09c73SVivien Didelot * 2 registers, used to indirectly access the internal SMI devices. 61fad09c73SVivien Didelot */ 62fad09c73SVivien Didelot 63fad09c73SVivien Didelot static int mv88e6xxx_smi_read(struct mv88e6xxx_chip *chip, 64fad09c73SVivien Didelot int addr, int reg, u16 *val) 65fad09c73SVivien Didelot { 66fad09c73SVivien Didelot if (!chip->smi_ops) 67fad09c73SVivien Didelot return -EOPNOTSUPP; 68fad09c73SVivien Didelot 69fad09c73SVivien Didelot return chip->smi_ops->read(chip, addr, reg, val); 70fad09c73SVivien Didelot } 71fad09c73SVivien Didelot 72fad09c73SVivien Didelot static int mv88e6xxx_smi_write(struct mv88e6xxx_chip *chip, 73fad09c73SVivien Didelot int addr, int reg, u16 val) 74fad09c73SVivien Didelot { 75fad09c73SVivien Didelot if (!chip->smi_ops) 76fad09c73SVivien Didelot return -EOPNOTSUPP; 77fad09c73SVivien Didelot 78fad09c73SVivien Didelot return chip->smi_ops->write(chip, addr, reg, val); 79fad09c73SVivien Didelot } 80fad09c73SVivien Didelot 81fad09c73SVivien Didelot static int mv88e6xxx_smi_single_chip_read(struct mv88e6xxx_chip *chip, 82fad09c73SVivien Didelot int addr, int reg, u16 *val) 83fad09c73SVivien Didelot { 84fad09c73SVivien Didelot int ret; 85fad09c73SVivien Didelot 86fad09c73SVivien Didelot ret = mdiobus_read_nested(chip->bus, addr, reg); 87fad09c73SVivien Didelot if (ret < 0) 88fad09c73SVivien Didelot return ret; 89fad09c73SVivien Didelot 90fad09c73SVivien Didelot *val = ret & 0xffff; 91fad09c73SVivien Didelot 92fad09c73SVivien Didelot return 0; 93fad09c73SVivien Didelot } 94fad09c73SVivien Didelot 95fad09c73SVivien Didelot static int mv88e6xxx_smi_single_chip_write(struct mv88e6xxx_chip *chip, 96fad09c73SVivien Didelot int addr, int reg, u16 val) 97fad09c73SVivien Didelot { 98fad09c73SVivien Didelot int ret; 99fad09c73SVivien Didelot 100fad09c73SVivien Didelot ret = mdiobus_write_nested(chip->bus, addr, reg, val); 101fad09c73SVivien Didelot if (ret < 0) 102fad09c73SVivien Didelot return ret; 103fad09c73SVivien Didelot 104fad09c73SVivien Didelot return 0; 105fad09c73SVivien Didelot } 106fad09c73SVivien Didelot 107c08026abSVivien Didelot static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_single_chip_ops = { 108fad09c73SVivien Didelot .read = mv88e6xxx_smi_single_chip_read, 109fad09c73SVivien Didelot .write = mv88e6xxx_smi_single_chip_write, 110fad09c73SVivien Didelot }; 111fad09c73SVivien Didelot 112fad09c73SVivien Didelot static int mv88e6xxx_smi_multi_chip_wait(struct mv88e6xxx_chip *chip) 113fad09c73SVivien Didelot { 114fad09c73SVivien Didelot int ret; 115fad09c73SVivien Didelot int i; 116fad09c73SVivien Didelot 117fad09c73SVivien Didelot for (i = 0; i < 16; i++) { 118fad09c73SVivien Didelot ret = mdiobus_read_nested(chip->bus, chip->sw_addr, SMI_CMD); 119fad09c73SVivien Didelot if (ret < 0) 120fad09c73SVivien Didelot return ret; 121fad09c73SVivien Didelot 122fad09c73SVivien Didelot if ((ret & SMI_CMD_BUSY) == 0) 123fad09c73SVivien Didelot return 0; 124fad09c73SVivien Didelot } 125fad09c73SVivien Didelot 126fad09c73SVivien Didelot return -ETIMEDOUT; 127fad09c73SVivien Didelot } 128fad09c73SVivien Didelot 129fad09c73SVivien Didelot static int mv88e6xxx_smi_multi_chip_read(struct mv88e6xxx_chip *chip, 130fad09c73SVivien Didelot int addr, int reg, u16 *val) 131fad09c73SVivien Didelot { 132fad09c73SVivien Didelot int ret; 133fad09c73SVivien Didelot 134fad09c73SVivien Didelot /* Wait for the bus to become free. */ 135fad09c73SVivien Didelot ret = mv88e6xxx_smi_multi_chip_wait(chip); 136fad09c73SVivien Didelot if (ret < 0) 137fad09c73SVivien Didelot return ret; 138fad09c73SVivien Didelot 139fad09c73SVivien Didelot /* Transmit the read command. */ 140fad09c73SVivien Didelot ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_CMD, 141fad09c73SVivien Didelot SMI_CMD_OP_22_READ | (addr << 5) | reg); 142fad09c73SVivien Didelot if (ret < 0) 143fad09c73SVivien Didelot return ret; 144fad09c73SVivien Didelot 145fad09c73SVivien Didelot /* Wait for the read command to complete. */ 146fad09c73SVivien Didelot ret = mv88e6xxx_smi_multi_chip_wait(chip); 147fad09c73SVivien Didelot if (ret < 0) 148fad09c73SVivien Didelot return ret; 149fad09c73SVivien Didelot 150fad09c73SVivien Didelot /* Read the data. */ 151fad09c73SVivien Didelot ret = mdiobus_read_nested(chip->bus, chip->sw_addr, SMI_DATA); 152fad09c73SVivien Didelot if (ret < 0) 153fad09c73SVivien Didelot return ret; 154fad09c73SVivien Didelot 155fad09c73SVivien Didelot *val = ret & 0xffff; 156fad09c73SVivien Didelot 157fad09c73SVivien Didelot return 0; 158fad09c73SVivien Didelot } 159fad09c73SVivien Didelot 160fad09c73SVivien Didelot static int mv88e6xxx_smi_multi_chip_write(struct mv88e6xxx_chip *chip, 161fad09c73SVivien Didelot int addr, int reg, u16 val) 162fad09c73SVivien Didelot { 163fad09c73SVivien Didelot int ret; 164fad09c73SVivien Didelot 165fad09c73SVivien Didelot /* Wait for the bus to become free. */ 166fad09c73SVivien Didelot ret = mv88e6xxx_smi_multi_chip_wait(chip); 167fad09c73SVivien Didelot if (ret < 0) 168fad09c73SVivien Didelot return ret; 169fad09c73SVivien Didelot 170fad09c73SVivien Didelot /* Transmit the data to write. */ 171fad09c73SVivien Didelot ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_DATA, val); 172fad09c73SVivien Didelot if (ret < 0) 173fad09c73SVivien Didelot return ret; 174fad09c73SVivien Didelot 175fad09c73SVivien Didelot /* Transmit the write command. */ 176fad09c73SVivien Didelot ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_CMD, 177fad09c73SVivien Didelot SMI_CMD_OP_22_WRITE | (addr << 5) | reg); 178fad09c73SVivien Didelot if (ret < 0) 179fad09c73SVivien Didelot return ret; 180fad09c73SVivien Didelot 181fad09c73SVivien Didelot /* Wait for the write command to complete. */ 182fad09c73SVivien Didelot ret = mv88e6xxx_smi_multi_chip_wait(chip); 183fad09c73SVivien Didelot if (ret < 0) 184fad09c73SVivien Didelot return ret; 185fad09c73SVivien Didelot 186fad09c73SVivien Didelot return 0; 187fad09c73SVivien Didelot } 188fad09c73SVivien Didelot 189c08026abSVivien Didelot static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_multi_chip_ops = { 190fad09c73SVivien Didelot .read = mv88e6xxx_smi_multi_chip_read, 191fad09c73SVivien Didelot .write = mv88e6xxx_smi_multi_chip_write, 192fad09c73SVivien Didelot }; 193fad09c73SVivien Didelot 194ec561276SVivien Didelot int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val) 195fad09c73SVivien Didelot { 196fad09c73SVivien Didelot int err; 197fad09c73SVivien Didelot 198fad09c73SVivien Didelot assert_reg_lock(chip); 199fad09c73SVivien Didelot 200fad09c73SVivien Didelot err = mv88e6xxx_smi_read(chip, addr, reg, val); 201fad09c73SVivien Didelot if (err) 202fad09c73SVivien Didelot return err; 203fad09c73SVivien Didelot 204fad09c73SVivien Didelot dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 205fad09c73SVivien Didelot addr, reg, *val); 206fad09c73SVivien Didelot 207fad09c73SVivien Didelot return 0; 208fad09c73SVivien Didelot } 209fad09c73SVivien Didelot 210ec561276SVivien Didelot int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val) 211fad09c73SVivien Didelot { 212fad09c73SVivien Didelot int err; 213fad09c73SVivien Didelot 214fad09c73SVivien Didelot assert_reg_lock(chip); 215fad09c73SVivien Didelot 216fad09c73SVivien Didelot err = mv88e6xxx_smi_write(chip, addr, reg, val); 217fad09c73SVivien Didelot if (err) 218fad09c73SVivien Didelot return err; 219fad09c73SVivien Didelot 220fad09c73SVivien Didelot dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 221fad09c73SVivien Didelot addr, reg, val); 222fad09c73SVivien Didelot 223fad09c73SVivien Didelot return 0; 224fad09c73SVivien Didelot } 225fad09c73SVivien Didelot 22610fa5bfcSAndrew Lunn struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) 227a3c53be5SAndrew Lunn { 228a3c53be5SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 229a3c53be5SAndrew Lunn 230a3c53be5SAndrew Lunn mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus, 231a3c53be5SAndrew Lunn list); 232a3c53be5SAndrew Lunn if (!mdio_bus) 233a3c53be5SAndrew Lunn return NULL; 234a3c53be5SAndrew Lunn 235a3c53be5SAndrew Lunn return mdio_bus->bus; 236a3c53be5SAndrew Lunn } 237a3c53be5SAndrew Lunn 238dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_mask(struct irq_data *d) 239dc30c35bSAndrew Lunn { 240dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 241dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 242dc30c35bSAndrew Lunn 243dc30c35bSAndrew Lunn chip->g1_irq.masked |= (1 << n); 244dc30c35bSAndrew Lunn } 245dc30c35bSAndrew Lunn 246dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_unmask(struct irq_data *d) 247dc30c35bSAndrew Lunn { 248dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 249dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 250dc30c35bSAndrew Lunn 251dc30c35bSAndrew Lunn chip->g1_irq.masked &= ~(1 << n); 252dc30c35bSAndrew Lunn } 253dc30c35bSAndrew Lunn 254dc30c35bSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id) 255dc30c35bSAndrew Lunn { 256dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = dev_id; 257dc30c35bSAndrew Lunn unsigned int nhandled = 0; 258dc30c35bSAndrew Lunn unsigned int sub_irq; 259dc30c35bSAndrew Lunn unsigned int n; 260dc30c35bSAndrew Lunn u16 reg; 261dc30c35bSAndrew Lunn int err; 262dc30c35bSAndrew Lunn 263dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 264dc30c35bSAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, ®); 265dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 266dc30c35bSAndrew Lunn 267dc30c35bSAndrew Lunn if (err) 268dc30c35bSAndrew Lunn goto out; 269dc30c35bSAndrew Lunn 270dc30c35bSAndrew Lunn for (n = 0; n < chip->g1_irq.nirqs; ++n) { 271dc30c35bSAndrew Lunn if (reg & (1 << n)) { 272dc30c35bSAndrew Lunn sub_irq = irq_find_mapping(chip->g1_irq.domain, n); 273dc30c35bSAndrew Lunn handle_nested_irq(sub_irq); 274dc30c35bSAndrew Lunn ++nhandled; 275dc30c35bSAndrew Lunn } 276dc30c35bSAndrew Lunn } 277dc30c35bSAndrew Lunn out: 278dc30c35bSAndrew Lunn return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); 279dc30c35bSAndrew Lunn } 280dc30c35bSAndrew Lunn 281dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d) 282dc30c35bSAndrew Lunn { 283dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 284dc30c35bSAndrew Lunn 285dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 286dc30c35bSAndrew Lunn } 287dc30c35bSAndrew Lunn 288dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d) 289dc30c35bSAndrew Lunn { 290dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 291dc30c35bSAndrew Lunn u16 mask = GENMASK(chip->g1_irq.nirqs, 0); 292dc30c35bSAndrew Lunn u16 reg; 293dc30c35bSAndrew Lunn int err; 294dc30c35bSAndrew Lunn 295dc30c35bSAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, ®); 296dc30c35bSAndrew Lunn if (err) 297dc30c35bSAndrew Lunn goto out; 298dc30c35bSAndrew Lunn 299dc30c35bSAndrew Lunn reg &= ~mask; 300dc30c35bSAndrew Lunn reg |= (~chip->g1_irq.masked & mask); 301dc30c35bSAndrew Lunn 302dc30c35bSAndrew Lunn err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, reg); 303dc30c35bSAndrew Lunn if (err) 304dc30c35bSAndrew Lunn goto out; 305dc30c35bSAndrew Lunn 306dc30c35bSAndrew Lunn out: 307dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 308dc30c35bSAndrew Lunn } 309dc30c35bSAndrew Lunn 310dc30c35bSAndrew Lunn static struct irq_chip mv88e6xxx_g1_irq_chip = { 311dc30c35bSAndrew Lunn .name = "mv88e6xxx-g1", 312dc30c35bSAndrew Lunn .irq_mask = mv88e6xxx_g1_irq_mask, 313dc30c35bSAndrew Lunn .irq_unmask = mv88e6xxx_g1_irq_unmask, 314dc30c35bSAndrew Lunn .irq_bus_lock = mv88e6xxx_g1_irq_bus_lock, 315dc30c35bSAndrew Lunn .irq_bus_sync_unlock = mv88e6xxx_g1_irq_bus_sync_unlock, 316dc30c35bSAndrew Lunn }; 317dc30c35bSAndrew Lunn 318dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d, 319dc30c35bSAndrew Lunn unsigned int irq, 320dc30c35bSAndrew Lunn irq_hw_number_t hwirq) 321dc30c35bSAndrew Lunn { 322dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = d->host_data; 323dc30c35bSAndrew Lunn 324dc30c35bSAndrew Lunn irq_set_chip_data(irq, d->host_data); 325dc30c35bSAndrew Lunn irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq); 326dc30c35bSAndrew Lunn irq_set_noprobe(irq); 327dc30c35bSAndrew Lunn 328dc30c35bSAndrew Lunn return 0; 329dc30c35bSAndrew Lunn } 330dc30c35bSAndrew Lunn 331dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = { 332dc30c35bSAndrew Lunn .map = mv88e6xxx_g1_irq_domain_map, 333dc30c35bSAndrew Lunn .xlate = irq_domain_xlate_twocell, 334dc30c35bSAndrew Lunn }; 335dc30c35bSAndrew Lunn 336dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) 337dc30c35bSAndrew Lunn { 338dc30c35bSAndrew Lunn int irq, virq; 3393460a577SAndrew Lunn u16 mask; 3403460a577SAndrew Lunn 3413460a577SAndrew Lunn mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &mask); 3423460a577SAndrew Lunn mask |= GENMASK(chip->g1_irq.nirqs, 0); 3433460a577SAndrew Lunn mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask); 3443460a577SAndrew Lunn 3453460a577SAndrew Lunn free_irq(chip->irq, chip); 346dc30c35bSAndrew Lunn 3475edef2f2SAndreas Färber for (irq = 0; irq < chip->g1_irq.nirqs; irq++) { 348a3db3d3aSAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 349dc30c35bSAndrew Lunn irq_dispose_mapping(virq); 350dc30c35bSAndrew Lunn } 351dc30c35bSAndrew Lunn 352a3db3d3aSAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 353dc30c35bSAndrew Lunn } 354dc30c35bSAndrew Lunn 355dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) 356dc30c35bSAndrew Lunn { 3573dd0ef05SAndrew Lunn int err, irq, virq; 3583dd0ef05SAndrew Lunn u16 reg, mask; 359dc30c35bSAndrew Lunn 360dc30c35bSAndrew Lunn chip->g1_irq.nirqs = chip->info->g1_irqs; 361dc30c35bSAndrew Lunn chip->g1_irq.domain = irq_domain_add_simple( 362dc30c35bSAndrew Lunn NULL, chip->g1_irq.nirqs, 0, 363dc30c35bSAndrew Lunn &mv88e6xxx_g1_irq_domain_ops, chip); 364dc30c35bSAndrew Lunn if (!chip->g1_irq.domain) 365dc30c35bSAndrew Lunn return -ENOMEM; 366dc30c35bSAndrew Lunn 367dc30c35bSAndrew Lunn for (irq = 0; irq < chip->g1_irq.nirqs; irq++) 368dc30c35bSAndrew Lunn irq_create_mapping(chip->g1_irq.domain, irq); 369dc30c35bSAndrew Lunn 370dc30c35bSAndrew Lunn chip->g1_irq.chip = mv88e6xxx_g1_irq_chip; 371dc30c35bSAndrew Lunn chip->g1_irq.masked = ~0; 372dc30c35bSAndrew Lunn 3733dd0ef05SAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &mask); 374dc30c35bSAndrew Lunn if (err) 3753dd0ef05SAndrew Lunn goto out_mapping; 376dc30c35bSAndrew Lunn 3773dd0ef05SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 378dc30c35bSAndrew Lunn 3793dd0ef05SAndrew Lunn err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask); 380dc30c35bSAndrew Lunn if (err) 3813dd0ef05SAndrew Lunn goto out_disable; 382dc30c35bSAndrew Lunn 383dc30c35bSAndrew Lunn /* Reading the interrupt status clears (most of) them */ 384dc30c35bSAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, ®); 385dc30c35bSAndrew Lunn if (err) 3863dd0ef05SAndrew Lunn goto out_disable; 387dc30c35bSAndrew Lunn 388dc30c35bSAndrew Lunn err = request_threaded_irq(chip->irq, NULL, 389dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_thread_fn, 390dc30c35bSAndrew Lunn IRQF_ONESHOT | IRQF_TRIGGER_FALLING, 391dc30c35bSAndrew Lunn dev_name(chip->dev), chip); 392dc30c35bSAndrew Lunn if (err) 3933dd0ef05SAndrew Lunn goto out_disable; 394dc30c35bSAndrew Lunn 395dc30c35bSAndrew Lunn return 0; 396dc30c35bSAndrew Lunn 3973dd0ef05SAndrew Lunn out_disable: 3983dd0ef05SAndrew Lunn mask |= GENMASK(chip->g1_irq.nirqs, 0); 3993dd0ef05SAndrew Lunn mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask); 4003dd0ef05SAndrew Lunn 4013dd0ef05SAndrew Lunn out_mapping: 4023dd0ef05SAndrew Lunn for (irq = 0; irq < 16; irq++) { 4033dd0ef05SAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 4043dd0ef05SAndrew Lunn irq_dispose_mapping(virq); 4053dd0ef05SAndrew Lunn } 4063dd0ef05SAndrew Lunn 4073dd0ef05SAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 408dc30c35bSAndrew Lunn 409dc30c35bSAndrew Lunn return err; 410dc30c35bSAndrew Lunn } 411dc30c35bSAndrew Lunn 412ec561276SVivien Didelot int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask) 4132d79af6eSVivien Didelot { 4146441e669SAndrew Lunn int i; 4152d79af6eSVivien Didelot 4166441e669SAndrew Lunn for (i = 0; i < 16; i++) { 4172d79af6eSVivien Didelot u16 val; 4182d79af6eSVivien Didelot int err; 4192d79af6eSVivien Didelot 4202d79af6eSVivien Didelot err = mv88e6xxx_read(chip, addr, reg, &val); 4212d79af6eSVivien Didelot if (err) 4222d79af6eSVivien Didelot return err; 4232d79af6eSVivien Didelot 4242d79af6eSVivien Didelot if (!(val & mask)) 4252d79af6eSVivien Didelot return 0; 4262d79af6eSVivien Didelot 4272d79af6eSVivien Didelot usleep_range(1000, 2000); 4282d79af6eSVivien Didelot } 4292d79af6eSVivien Didelot 43030853553SAndrew Lunn dev_err(chip->dev, "Timeout while waiting for switch\n"); 4312d79af6eSVivien Didelot return -ETIMEDOUT; 4322d79af6eSVivien Didelot } 4332d79af6eSVivien Didelot 434f22ab641SVivien Didelot /* Indirect write to single pointer-data register with an Update bit */ 435ec561276SVivien Didelot int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update) 436f22ab641SVivien Didelot { 437f22ab641SVivien Didelot u16 val; 4380f02b4f7SAndrew Lunn int err; 439f22ab641SVivien Didelot 440f22ab641SVivien Didelot /* Wait until the previous operation is completed */ 4410f02b4f7SAndrew Lunn err = mv88e6xxx_wait(chip, addr, reg, BIT(15)); 442f22ab641SVivien Didelot if (err) 443f22ab641SVivien Didelot return err; 444f22ab641SVivien Didelot 445f22ab641SVivien Didelot /* Set the Update bit to trigger a write operation */ 446f22ab641SVivien Didelot val = BIT(15) | update; 447f22ab641SVivien Didelot 448f22ab641SVivien Didelot return mv88e6xxx_write(chip, addr, reg, val); 449f22ab641SVivien Didelot } 450f22ab641SVivien Didelot 451d78343d2SVivien Didelot static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, 452d78343d2SVivien Didelot int link, int speed, int duplex, 453d78343d2SVivien Didelot phy_interface_t mode) 454d78343d2SVivien Didelot { 455d78343d2SVivien Didelot int err; 456d78343d2SVivien Didelot 457d78343d2SVivien Didelot if (!chip->info->ops->port_set_link) 458d78343d2SVivien Didelot return 0; 459d78343d2SVivien Didelot 460d78343d2SVivien Didelot /* Port's MAC control must not be changed unless the link is down */ 461d78343d2SVivien Didelot err = chip->info->ops->port_set_link(chip, port, 0); 462d78343d2SVivien Didelot if (err) 463d78343d2SVivien Didelot return err; 464d78343d2SVivien Didelot 465d78343d2SVivien Didelot if (chip->info->ops->port_set_speed) { 466d78343d2SVivien Didelot err = chip->info->ops->port_set_speed(chip, port, speed); 467d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 468d78343d2SVivien Didelot goto restore_link; 469d78343d2SVivien Didelot } 470d78343d2SVivien Didelot 471d78343d2SVivien Didelot if (chip->info->ops->port_set_duplex) { 472d78343d2SVivien Didelot err = chip->info->ops->port_set_duplex(chip, port, duplex); 473d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 474d78343d2SVivien Didelot goto restore_link; 475d78343d2SVivien Didelot } 476d78343d2SVivien Didelot 477d78343d2SVivien Didelot if (chip->info->ops->port_set_rgmii_delay) { 478d78343d2SVivien Didelot err = chip->info->ops->port_set_rgmii_delay(chip, port, mode); 479d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 480d78343d2SVivien Didelot goto restore_link; 481d78343d2SVivien Didelot } 482d78343d2SVivien Didelot 483f39908d3SAndrew Lunn if (chip->info->ops->port_set_cmode) { 484f39908d3SAndrew Lunn err = chip->info->ops->port_set_cmode(chip, port, mode); 485f39908d3SAndrew Lunn if (err && err != -EOPNOTSUPP) 486f39908d3SAndrew Lunn goto restore_link; 487f39908d3SAndrew Lunn } 488f39908d3SAndrew Lunn 489d78343d2SVivien Didelot err = 0; 490d78343d2SVivien Didelot restore_link: 491d78343d2SVivien Didelot if (chip->info->ops->port_set_link(chip, port, link)) 492d78343d2SVivien Didelot netdev_err(chip->ds->ports[port].netdev, 493d78343d2SVivien Didelot "failed to restore MAC's link\n"); 494d78343d2SVivien Didelot 495d78343d2SVivien Didelot return err; 496d78343d2SVivien Didelot } 497d78343d2SVivien Didelot 498fad09c73SVivien Didelot /* We expect the switch to perform auto negotiation if there is a real 499fad09c73SVivien Didelot * phy. However, in the case of a fixed link phy, we force the port 500fad09c73SVivien Didelot * settings from the fixed link settings. 501fad09c73SVivien Didelot */ 502fad09c73SVivien Didelot static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, 503fad09c73SVivien Didelot struct phy_device *phydev) 504fad09c73SVivien Didelot { 50504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 5060e7b9925SAndrew Lunn int err; 507fad09c73SVivien Didelot 508fad09c73SVivien Didelot if (!phy_is_pseudo_fixed_link(phydev)) 509fad09c73SVivien Didelot return; 510fad09c73SVivien Didelot 511fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 512d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed, 513d78343d2SVivien Didelot phydev->duplex, phydev->interface); 514fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 515d78343d2SVivien Didelot 516d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 517d78343d2SVivien Didelot netdev_err(ds->ports[port].netdev, "failed to configure MAC\n"); 518fad09c73SVivien Didelot } 519fad09c73SVivien Didelot 520a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 521fad09c73SVivien Didelot { 522a605a0feSAndrew Lunn if (!chip->info->ops->stats_snapshot) 523a605a0feSAndrew Lunn return -EOPNOTSUPP; 524fad09c73SVivien Didelot 525a605a0feSAndrew Lunn return chip->info->ops->stats_snapshot(chip, port); 526fad09c73SVivien Didelot } 527fad09c73SVivien Didelot 528fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = { 529dfafe449SAndrew Lunn { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, }, 530dfafe449SAndrew Lunn { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, }, 531dfafe449SAndrew Lunn { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, }, 532dfafe449SAndrew Lunn { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, }, 533dfafe449SAndrew Lunn { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, }, 534dfafe449SAndrew Lunn { "in_pause", 4, 0x16, STATS_TYPE_BANK0, }, 535dfafe449SAndrew Lunn { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, }, 536dfafe449SAndrew Lunn { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, }, 537dfafe449SAndrew Lunn { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, }, 538dfafe449SAndrew Lunn { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, }, 539dfafe449SAndrew Lunn { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, }, 540dfafe449SAndrew Lunn { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, }, 541dfafe449SAndrew Lunn { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, }, 542dfafe449SAndrew Lunn { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, }, 543dfafe449SAndrew Lunn { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, }, 544dfafe449SAndrew Lunn { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, }, 545dfafe449SAndrew Lunn { "out_pause", 4, 0x15, STATS_TYPE_BANK0, }, 546dfafe449SAndrew Lunn { "excessive", 4, 0x11, STATS_TYPE_BANK0, }, 547dfafe449SAndrew Lunn { "collisions", 4, 0x1e, STATS_TYPE_BANK0, }, 548dfafe449SAndrew Lunn { "deferred", 4, 0x05, STATS_TYPE_BANK0, }, 549dfafe449SAndrew Lunn { "single", 4, 0x14, STATS_TYPE_BANK0, }, 550dfafe449SAndrew Lunn { "multiple", 4, 0x17, STATS_TYPE_BANK0, }, 551dfafe449SAndrew Lunn { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, }, 552dfafe449SAndrew Lunn { "late", 4, 0x1f, STATS_TYPE_BANK0, }, 553dfafe449SAndrew Lunn { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, }, 554dfafe449SAndrew Lunn { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, }, 555dfafe449SAndrew Lunn { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, }, 556dfafe449SAndrew Lunn { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, }, 557dfafe449SAndrew Lunn { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, }, 558dfafe449SAndrew Lunn { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, }, 559dfafe449SAndrew Lunn { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, }, 560dfafe449SAndrew Lunn { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, }, 561dfafe449SAndrew Lunn { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, }, 562dfafe449SAndrew Lunn { "in_discards", 4, 0x00, STATS_TYPE_BANK1, }, 563dfafe449SAndrew Lunn { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, }, 564dfafe449SAndrew Lunn { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, }, 565dfafe449SAndrew Lunn { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, }, 566dfafe449SAndrew Lunn { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, }, 567dfafe449SAndrew Lunn { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, }, 568dfafe449SAndrew Lunn { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, }, 569dfafe449SAndrew Lunn { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, }, 570dfafe449SAndrew Lunn { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, }, 571dfafe449SAndrew Lunn { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, }, 572dfafe449SAndrew Lunn { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, }, 573dfafe449SAndrew Lunn { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, }, 574dfafe449SAndrew Lunn { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, }, 575dfafe449SAndrew Lunn { "in_management", 4, 0x0f, STATS_TYPE_BANK1, }, 576dfafe449SAndrew Lunn { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, }, 577dfafe449SAndrew Lunn { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, }, 578dfafe449SAndrew Lunn { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, }, 579dfafe449SAndrew Lunn { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, }, 580dfafe449SAndrew Lunn { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, }, 581dfafe449SAndrew Lunn { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, }, 582dfafe449SAndrew Lunn { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, }, 583dfafe449SAndrew Lunn { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, }, 584dfafe449SAndrew Lunn { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, }, 585dfafe449SAndrew Lunn { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, }, 586dfafe449SAndrew Lunn { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, }, 587dfafe449SAndrew Lunn { "out_management", 4, 0x1f, STATS_TYPE_BANK1, }, 588fad09c73SVivien Didelot }; 589fad09c73SVivien Didelot 590fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, 591fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *s, 592e0d8b615SAndrew Lunn int port, u16 bank1_select, 593e0d8b615SAndrew Lunn u16 histogram) 594fad09c73SVivien Didelot { 595fad09c73SVivien Didelot u32 low; 596fad09c73SVivien Didelot u32 high = 0; 597dfafe449SAndrew Lunn u16 reg = 0; 5980e7b9925SAndrew Lunn int err; 599fad09c73SVivien Didelot u64 value; 600fad09c73SVivien Didelot 601fad09c73SVivien Didelot switch (s->type) { 602dfafe449SAndrew Lunn case STATS_TYPE_PORT: 6030e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg, ®); 6040e7b9925SAndrew Lunn if (err) 605fad09c73SVivien Didelot return UINT64_MAX; 606fad09c73SVivien Didelot 6070e7b9925SAndrew Lunn low = reg; 608fad09c73SVivien Didelot if (s->sizeof_stat == 4) { 6090e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg + 1, ®); 6100e7b9925SAndrew Lunn if (err) 611fad09c73SVivien Didelot return UINT64_MAX; 6120e7b9925SAndrew Lunn high = reg; 613fad09c73SVivien Didelot } 614fad09c73SVivien Didelot break; 615dfafe449SAndrew Lunn case STATS_TYPE_BANK1: 616e0d8b615SAndrew Lunn reg = bank1_select; 617dfafe449SAndrew Lunn /* fall through */ 618dfafe449SAndrew Lunn case STATS_TYPE_BANK0: 619e0d8b615SAndrew Lunn reg |= s->reg | histogram; 6207f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg, &low); 621fad09c73SVivien Didelot if (s->sizeof_stat == 8) 6227f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg + 1, &high); 6239fc3e4dcSGustavo A. R. Silva break; 6249fc3e4dcSGustavo A. R. Silva default: 6259fc3e4dcSGustavo A. R. Silva return UINT64_MAX; 626fad09c73SVivien Didelot } 627fad09c73SVivien Didelot value = (((u64)high) << 16) | low; 628fad09c73SVivien Didelot return value; 629fad09c73SVivien Didelot } 630fad09c73SVivien Didelot 631dfafe449SAndrew Lunn static void mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, 632dfafe449SAndrew Lunn uint8_t *data, int types) 633fad09c73SVivien Didelot { 634fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 635fad09c73SVivien Didelot int i, j; 636fad09c73SVivien Didelot 637fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 638fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 639dfafe449SAndrew Lunn if (stat->type & types) { 640fad09c73SVivien Didelot memcpy(data + j * ETH_GSTRING_LEN, stat->string, 641fad09c73SVivien Didelot ETH_GSTRING_LEN); 642fad09c73SVivien Didelot j++; 643fad09c73SVivien Didelot } 644fad09c73SVivien Didelot } 645fad09c73SVivien Didelot } 646fad09c73SVivien Didelot 647dfafe449SAndrew Lunn static void mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, 648dfafe449SAndrew Lunn uint8_t *data) 649dfafe449SAndrew Lunn { 650dfafe449SAndrew Lunn mv88e6xxx_stats_get_strings(chip, data, 651dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT); 652dfafe449SAndrew Lunn } 653dfafe449SAndrew Lunn 654dfafe449SAndrew Lunn static void mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, 655dfafe449SAndrew Lunn uint8_t *data) 656dfafe449SAndrew Lunn { 657dfafe449SAndrew Lunn mv88e6xxx_stats_get_strings(chip, data, 658dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1); 659dfafe449SAndrew Lunn } 660dfafe449SAndrew Lunn 661dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, 662dfafe449SAndrew Lunn uint8_t *data) 663fad09c73SVivien Didelot { 66404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 665dfafe449SAndrew Lunn 666dfafe449SAndrew Lunn if (chip->info->ops->stats_get_strings) 667dfafe449SAndrew Lunn chip->info->ops->stats_get_strings(chip, data); 668dfafe449SAndrew Lunn } 669dfafe449SAndrew Lunn 670dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip, 671dfafe449SAndrew Lunn int types) 672dfafe449SAndrew Lunn { 673fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 674fad09c73SVivien Didelot int i, j; 675fad09c73SVivien Didelot 676fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 677fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 678dfafe449SAndrew Lunn if (stat->type & types) 679fad09c73SVivien Didelot j++; 680fad09c73SVivien Didelot } 681fad09c73SVivien Didelot return j; 682fad09c73SVivien Didelot } 683fad09c73SVivien Didelot 684dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip) 685dfafe449SAndrew Lunn { 686dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 687dfafe449SAndrew Lunn STATS_TYPE_PORT); 688dfafe449SAndrew Lunn } 689dfafe449SAndrew Lunn 690dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip) 691dfafe449SAndrew Lunn { 692dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 693dfafe449SAndrew Lunn STATS_TYPE_BANK1); 694dfafe449SAndrew Lunn } 695dfafe449SAndrew Lunn 696dfafe449SAndrew Lunn static int mv88e6xxx_get_sset_count(struct dsa_switch *ds) 697dfafe449SAndrew Lunn { 698dfafe449SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 699dfafe449SAndrew Lunn 700dfafe449SAndrew Lunn if (chip->info->ops->stats_get_sset_count) 701dfafe449SAndrew Lunn return chip->info->ops->stats_get_sset_count(chip); 702dfafe449SAndrew Lunn 703dfafe449SAndrew Lunn return 0; 704dfafe449SAndrew Lunn } 705dfafe449SAndrew Lunn 706052f947fSAndrew Lunn static void mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 707e0d8b615SAndrew Lunn uint64_t *data, int types, 708e0d8b615SAndrew Lunn u16 bank1_select, u16 histogram) 709052f947fSAndrew Lunn { 710052f947fSAndrew Lunn struct mv88e6xxx_hw_stat *stat; 711052f947fSAndrew Lunn int i, j; 712052f947fSAndrew Lunn 713052f947fSAndrew Lunn for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 714052f947fSAndrew Lunn stat = &mv88e6xxx_hw_stats[i]; 715052f947fSAndrew Lunn if (stat->type & types) { 716e0d8b615SAndrew Lunn data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 717e0d8b615SAndrew Lunn bank1_select, 718e0d8b615SAndrew Lunn histogram); 719052f947fSAndrew Lunn j++; 720052f947fSAndrew Lunn } 721052f947fSAndrew Lunn } 722052f947fSAndrew Lunn } 723052f947fSAndrew Lunn 724052f947fSAndrew Lunn static void mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 725052f947fSAndrew Lunn uint64_t *data) 726052f947fSAndrew Lunn { 727052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 728e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT, 729e0d8b615SAndrew Lunn 0, GLOBAL_STATS_OP_HIST_RX_TX); 730052f947fSAndrew Lunn } 731052f947fSAndrew Lunn 732052f947fSAndrew Lunn static void mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 733052f947fSAndrew Lunn uint64_t *data) 734052f947fSAndrew Lunn { 735052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 736e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 737e0d8b615SAndrew Lunn GLOBAL_STATS_OP_BANK_1_BIT_9, 738e0d8b615SAndrew Lunn GLOBAL_STATS_OP_HIST_RX_TX); 739e0d8b615SAndrew Lunn } 740e0d8b615SAndrew Lunn 741e0d8b615SAndrew Lunn static void mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 742e0d8b615SAndrew Lunn uint64_t *data) 743e0d8b615SAndrew Lunn { 744e0d8b615SAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 745e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 746e0d8b615SAndrew Lunn GLOBAL_STATS_OP_BANK_1_BIT_10, 0); 747052f947fSAndrew Lunn } 748052f947fSAndrew Lunn 749052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, 750052f947fSAndrew Lunn uint64_t *data) 751052f947fSAndrew Lunn { 752052f947fSAndrew Lunn if (chip->info->ops->stats_get_stats) 753052f947fSAndrew Lunn chip->info->ops->stats_get_stats(chip, port, data); 754052f947fSAndrew Lunn } 755052f947fSAndrew Lunn 756fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, 757fad09c73SVivien Didelot uint64_t *data) 758fad09c73SVivien Didelot { 75904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 760fad09c73SVivien Didelot int ret; 761fad09c73SVivien Didelot 762fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 763fad09c73SVivien Didelot 764a605a0feSAndrew Lunn ret = mv88e6xxx_stats_snapshot(chip, port); 765fad09c73SVivien Didelot if (ret < 0) { 766fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 767fad09c73SVivien Didelot return; 768fad09c73SVivien Didelot } 769052f947fSAndrew Lunn 770052f947fSAndrew Lunn mv88e6xxx_get_stats(chip, port, data); 771fad09c73SVivien Didelot 772fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 773fad09c73SVivien Didelot } 774fad09c73SVivien Didelot 775de227387SAndrew Lunn static int mv88e6xxx_stats_set_histogram(struct mv88e6xxx_chip *chip) 776de227387SAndrew Lunn { 777de227387SAndrew Lunn if (chip->info->ops->stats_set_histogram) 778de227387SAndrew Lunn return chip->info->ops->stats_set_histogram(chip); 779de227387SAndrew Lunn 780de227387SAndrew Lunn return 0; 781de227387SAndrew Lunn } 782de227387SAndrew Lunn 783fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) 784fad09c73SVivien Didelot { 785fad09c73SVivien Didelot return 32 * sizeof(u16); 786fad09c73SVivien Didelot } 787fad09c73SVivien Didelot 788fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, 789fad09c73SVivien Didelot struct ethtool_regs *regs, void *_p) 790fad09c73SVivien Didelot { 79104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 7920e7b9925SAndrew Lunn int err; 7930e7b9925SAndrew Lunn u16 reg; 794fad09c73SVivien Didelot u16 *p = _p; 795fad09c73SVivien Didelot int i; 796fad09c73SVivien Didelot 797fad09c73SVivien Didelot regs->version = 0; 798fad09c73SVivien Didelot 799fad09c73SVivien Didelot memset(p, 0xff, 32 * sizeof(u16)); 800fad09c73SVivien Didelot 801fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 802fad09c73SVivien Didelot 803fad09c73SVivien Didelot for (i = 0; i < 32; i++) { 804fad09c73SVivien Didelot 8050e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, i, ®); 8060e7b9925SAndrew Lunn if (!err) 8070e7b9925SAndrew Lunn p[i] = reg; 808fad09c73SVivien Didelot } 809fad09c73SVivien Didelot 810fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 811fad09c73SVivien Didelot } 812fad09c73SVivien Didelot 813fad09c73SVivien Didelot static int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, 814fad09c73SVivien Didelot struct ethtool_eee *e) 815fad09c73SVivien Didelot { 81604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 8179c93829cSVivien Didelot u16 reg; 8189c93829cSVivien Didelot int err; 819fad09c73SVivien Didelot 820fad09c73SVivien Didelot if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEE)) 821fad09c73SVivien Didelot return -EOPNOTSUPP; 822fad09c73SVivien Didelot 823fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 824fad09c73SVivien Didelot 8259c93829cSVivien Didelot err = mv88e6xxx_phy_read(chip, port, 16, ®); 8269c93829cSVivien Didelot if (err) 827fad09c73SVivien Didelot goto out; 828fad09c73SVivien Didelot 829fad09c73SVivien Didelot e->eee_enabled = !!(reg & 0x0200); 830fad09c73SVivien Didelot e->tx_lpi_enabled = !!(reg & 0x0100); 831fad09c73SVivien Didelot 8320e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, PORT_STATUS, ®); 8339c93829cSVivien Didelot if (err) 834fad09c73SVivien Didelot goto out; 835fad09c73SVivien Didelot 836fad09c73SVivien Didelot e->eee_active = !!(reg & PORT_STATUS_EEE); 837fad09c73SVivien Didelot out: 838fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 8399c93829cSVivien Didelot 8409c93829cSVivien Didelot return err; 841fad09c73SVivien Didelot } 842fad09c73SVivien Didelot 843fad09c73SVivien Didelot static int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, 844fad09c73SVivien Didelot struct phy_device *phydev, struct ethtool_eee *e) 845fad09c73SVivien Didelot { 84604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 8479c93829cSVivien Didelot u16 reg; 8489c93829cSVivien Didelot int err; 849fad09c73SVivien Didelot 850fad09c73SVivien Didelot if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEE)) 851fad09c73SVivien Didelot return -EOPNOTSUPP; 852fad09c73SVivien Didelot 853fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 854fad09c73SVivien Didelot 8559c93829cSVivien Didelot err = mv88e6xxx_phy_read(chip, port, 16, ®); 8569c93829cSVivien Didelot if (err) 857fad09c73SVivien Didelot goto out; 858fad09c73SVivien Didelot 8599c93829cSVivien Didelot reg &= ~0x0300; 860fad09c73SVivien Didelot if (e->eee_enabled) 861fad09c73SVivien Didelot reg |= 0x0200; 862fad09c73SVivien Didelot if (e->tx_lpi_enabled) 863fad09c73SVivien Didelot reg |= 0x0100; 864fad09c73SVivien Didelot 8659c93829cSVivien Didelot err = mv88e6xxx_phy_write(chip, port, 16, reg); 866fad09c73SVivien Didelot out: 867fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 868fad09c73SVivien Didelot 8699c93829cSVivien Didelot return err; 870fad09c73SVivien Didelot } 871fad09c73SVivien Didelot 872e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port) 873fad09c73SVivien Didelot { 874e5887a2aSVivien Didelot struct dsa_switch *ds = NULL; 875e5887a2aSVivien Didelot struct net_device *br; 876e5887a2aSVivien Didelot u16 pvlan; 877fad09c73SVivien Didelot int i; 878fad09c73SVivien Didelot 879e5887a2aSVivien Didelot if (dev < DSA_MAX_SWITCHES) 880e5887a2aSVivien Didelot ds = chip->ds->dst->ds[dev]; 881fad09c73SVivien Didelot 882e5887a2aSVivien Didelot /* Prevent frames from unknown switch or port */ 883e5887a2aSVivien Didelot if (!ds || port >= ds->num_ports) 884e5887a2aSVivien Didelot return 0; 885e5887a2aSVivien Didelot 886e5887a2aSVivien Didelot /* Frames from DSA links and CPU ports can egress any local port */ 887e5887a2aSVivien Didelot if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) 888e5887a2aSVivien Didelot return mv88e6xxx_port_mask(chip); 889e5887a2aSVivien Didelot 890e5887a2aSVivien Didelot br = ds->ports[port].bridge_dev; 891e5887a2aSVivien Didelot pvlan = 0; 892e5887a2aSVivien Didelot 893e5887a2aSVivien Didelot /* Frames from user ports can egress any local DSA links and CPU ports, 894e5887a2aSVivien Didelot * as well as any local member of their bridge group. 895e5887a2aSVivien Didelot */ 896e5887a2aSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 897e5887a2aSVivien Didelot if (dsa_is_cpu_port(chip->ds, i) || 898e5887a2aSVivien Didelot dsa_is_dsa_port(chip->ds, i) || 899e5887a2aSVivien Didelot (br && chip->ds->ports[i].bridge_dev == br)) 900e5887a2aSVivien Didelot pvlan |= BIT(i); 901e5887a2aSVivien Didelot 902e5887a2aSVivien Didelot return pvlan; 903fad09c73SVivien Didelot } 904e5887a2aSVivien Didelot 905240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port) 906e5887a2aSVivien Didelot { 907e5887a2aSVivien Didelot u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port); 908fad09c73SVivien Didelot 909fad09c73SVivien Didelot /* prevent frames from going back out of the port they came in on */ 910fad09c73SVivien Didelot output_ports &= ~BIT(port); 911fad09c73SVivien Didelot 9125a7921f4SVivien Didelot return mv88e6xxx_port_set_vlan_map(chip, port, output_ports); 913fad09c73SVivien Didelot } 914fad09c73SVivien Didelot 915fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, 916fad09c73SVivien Didelot u8 state) 917fad09c73SVivien Didelot { 91804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 919fad09c73SVivien Didelot int stp_state; 920fad09c73SVivien Didelot int err; 921fad09c73SVivien Didelot 922fad09c73SVivien Didelot switch (state) { 923fad09c73SVivien Didelot case BR_STATE_DISABLED: 924fad09c73SVivien Didelot stp_state = PORT_CONTROL_STATE_DISABLED; 925fad09c73SVivien Didelot break; 926fad09c73SVivien Didelot case BR_STATE_BLOCKING: 927fad09c73SVivien Didelot case BR_STATE_LISTENING: 928fad09c73SVivien Didelot stp_state = PORT_CONTROL_STATE_BLOCKING; 929fad09c73SVivien Didelot break; 930fad09c73SVivien Didelot case BR_STATE_LEARNING: 931fad09c73SVivien Didelot stp_state = PORT_CONTROL_STATE_LEARNING; 932fad09c73SVivien Didelot break; 933fad09c73SVivien Didelot case BR_STATE_FORWARDING: 934fad09c73SVivien Didelot default: 935fad09c73SVivien Didelot stp_state = PORT_CONTROL_STATE_FORWARDING; 936fad09c73SVivien Didelot break; 937fad09c73SVivien Didelot } 938fad09c73SVivien Didelot 939fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 940e28def33SVivien Didelot err = mv88e6xxx_port_set_state(chip, port, stp_state); 941fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 942fad09c73SVivien Didelot 943fad09c73SVivien Didelot if (err) 944e28def33SVivien Didelot netdev_err(ds->ports[port].netdev, "failed to update state\n"); 945fad09c73SVivien Didelot } 946fad09c73SVivien Didelot 947a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) 948a2ac29d2SVivien Didelot { 949c3a7d4adSVivien Didelot int err; 950c3a7d4adSVivien Didelot 951daefc943SVivien Didelot err = mv88e6xxx_g1_atu_flush(chip, 0, true); 952daefc943SVivien Didelot if (err) 953daefc943SVivien Didelot return err; 954daefc943SVivien Didelot 955c3a7d4adSVivien Didelot err = mv88e6xxx_g1_atu_set_learn2all(chip, true); 956c3a7d4adSVivien Didelot if (err) 957c3a7d4adSVivien Didelot return err; 958c3a7d4adSVivien Didelot 959a2ac29d2SVivien Didelot return mv88e6xxx_g1_atu_set_age_time(chip, 300000); 960a2ac29d2SVivien Didelot } 961a2ac29d2SVivien Didelot 96217a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port) 96317a1594eSVivien Didelot { 96417a1594eSVivien Didelot u16 pvlan = 0; 96517a1594eSVivien Didelot 96617a1594eSVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 96717a1594eSVivien Didelot return -EOPNOTSUPP; 96817a1594eSVivien Didelot 96917a1594eSVivien Didelot /* Skip the local source device, which uses in-chip port VLAN */ 97017a1594eSVivien Didelot if (dev != chip->ds->index) 971aec5ac88SVivien Didelot pvlan = mv88e6xxx_port_vlan(chip, dev, port); 97217a1594eSVivien Didelot 97317a1594eSVivien Didelot return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan); 97417a1594eSVivien Didelot } 97517a1594eSVivien Didelot 97681228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip) 97781228996SVivien Didelot { 97817a1594eSVivien Didelot int dev, port; 97917a1594eSVivien Didelot int err; 98017a1594eSVivien Didelot 98181228996SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 98281228996SVivien Didelot return 0; 98381228996SVivien Didelot 98481228996SVivien Didelot /* Clear 5 Bit Port for usage with Marvell Link Street devices: 98581228996SVivien Didelot * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev. 98681228996SVivien Didelot */ 98717a1594eSVivien Didelot err = mv88e6xxx_g2_misc_4_bit_port(chip); 98817a1594eSVivien Didelot if (err) 98917a1594eSVivien Didelot return err; 99017a1594eSVivien Didelot 99117a1594eSVivien Didelot for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) { 99217a1594eSVivien Didelot for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) { 99317a1594eSVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 99417a1594eSVivien Didelot if (err) 99517a1594eSVivien Didelot return err; 99617a1594eSVivien Didelot } 99717a1594eSVivien Didelot } 99817a1594eSVivien Didelot 99917a1594eSVivien Didelot return 0; 100081228996SVivien Didelot } 100181228996SVivien Didelot 1002749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port) 1003749efcb8SVivien Didelot { 1004749efcb8SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1005749efcb8SVivien Didelot int err; 1006749efcb8SVivien Didelot 1007749efcb8SVivien Didelot mutex_lock(&chip->reg_lock); 1008e606ca36SVivien Didelot err = mv88e6xxx_g1_atu_remove(chip, 0, port, false); 1009749efcb8SVivien Didelot mutex_unlock(&chip->reg_lock); 1010749efcb8SVivien Didelot 1011749efcb8SVivien Didelot if (err) 1012749efcb8SVivien Didelot netdev_err(ds->ports[port].netdev, "failed to flush ATU\n"); 1013749efcb8SVivien Didelot } 1014749efcb8SVivien Didelot 1015b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip) 1016b486d7c9SVivien Didelot { 1017b486d7c9SVivien Didelot if (!chip->info->max_vid) 1018b486d7c9SVivien Didelot return 0; 1019b486d7c9SVivien Didelot 1020b486d7c9SVivien Didelot return mv88e6xxx_g1_vtu_flush(chip); 1021b486d7c9SVivien Didelot } 1022b486d7c9SVivien Didelot 1023f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip, 1024f1394b78SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 1025f1394b78SVivien Didelot { 1026f1394b78SVivien Didelot if (!chip->info->ops->vtu_getnext) 1027f1394b78SVivien Didelot return -EOPNOTSUPP; 1028f1394b78SVivien Didelot 1029f1394b78SVivien Didelot return chip->info->ops->vtu_getnext(chip, entry); 1030f1394b78SVivien Didelot } 1031f1394b78SVivien Didelot 10320ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, 10330ad5daf6SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 10340ad5daf6SVivien Didelot { 10350ad5daf6SVivien Didelot if (!chip->info->ops->vtu_loadpurge) 10360ad5daf6SVivien Didelot return -EOPNOTSUPP; 10370ad5daf6SVivien Didelot 10380ad5daf6SVivien Didelot return chip->info->ops->vtu_loadpurge(chip, entry); 10390ad5daf6SVivien Didelot } 10400ad5daf6SVivien Didelot 1041fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, 1042fad09c73SVivien Didelot struct switchdev_obj_port_vlan *vlan, 1043438ff537SVivien Didelot switchdev_obj_dump_cb_t *cb) 1044fad09c73SVivien Didelot { 104504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 10463afb4bdeSVivien Didelot struct mv88e6xxx_vtu_entry next = { 10473afb4bdeSVivien Didelot .vid = chip->info->max_vid, 10483afb4bdeSVivien Didelot }; 1049fad09c73SVivien Didelot u16 pvid; 1050fad09c73SVivien Didelot int err; 1051fad09c73SVivien Didelot 10523cf3c846SVivien Didelot if (!chip->info->max_vid) 1053fad09c73SVivien Didelot return -EOPNOTSUPP; 1054fad09c73SVivien Didelot 1055fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1056fad09c73SVivien Didelot 105777064f37SVivien Didelot err = mv88e6xxx_port_get_pvid(chip, port, &pvid); 1058fad09c73SVivien Didelot if (err) 1059fad09c73SVivien Didelot goto unlock; 1060fad09c73SVivien Didelot 1061fad09c73SVivien Didelot do { 1062f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &next); 1063fad09c73SVivien Didelot if (err) 1064fad09c73SVivien Didelot break; 1065fad09c73SVivien Didelot 1066fad09c73SVivien Didelot if (!next.valid) 1067fad09c73SVivien Didelot break; 1068fad09c73SVivien Didelot 1069bd00e053SVivien Didelot if (next.member[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1070fad09c73SVivien Didelot continue; 1071fad09c73SVivien Didelot 1072fad09c73SVivien Didelot /* reinit and dump this VLAN obj */ 1073fad09c73SVivien Didelot vlan->vid_begin = next.vid; 1074fad09c73SVivien Didelot vlan->vid_end = next.vid; 1075fad09c73SVivien Didelot vlan->flags = 0; 1076fad09c73SVivien Didelot 1077bd00e053SVivien Didelot if (next.member[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED) 1078fad09c73SVivien Didelot vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; 1079fad09c73SVivien Didelot 1080fad09c73SVivien Didelot if (next.vid == pvid) 1081fad09c73SVivien Didelot vlan->flags |= BRIDGE_VLAN_INFO_PVID; 1082fad09c73SVivien Didelot 1083fad09c73SVivien Didelot err = cb(&vlan->obj); 1084fad09c73SVivien Didelot if (err) 1085fad09c73SVivien Didelot break; 10863cf3c846SVivien Didelot } while (next.vid < chip->info->max_vid); 1087fad09c73SVivien Didelot 1088fad09c73SVivien Didelot unlock: 1089fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1090fad09c73SVivien Didelot 1091fad09c73SVivien Didelot return err; 1092fad09c73SVivien Didelot } 1093fad09c73SVivien Didelot 1094d7f435f9SVivien Didelot static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) 1095fad09c73SVivien Didelot { 1096fad09c73SVivien Didelot DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); 10973afb4bdeSVivien Didelot struct mv88e6xxx_vtu_entry vlan = { 10983afb4bdeSVivien Didelot .vid = chip->info->max_vid, 10993afb4bdeSVivien Didelot }; 1100fad09c73SVivien Didelot int i, err; 1101fad09c73SVivien Didelot 1102fad09c73SVivien Didelot bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); 1103fad09c73SVivien Didelot 1104fad09c73SVivien Didelot /* Set every FID bit used by the (un)bridged ports */ 1105370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1106b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, i, fid); 1107fad09c73SVivien Didelot if (err) 1108fad09c73SVivien Didelot return err; 1109fad09c73SVivien Didelot 1110fad09c73SVivien Didelot set_bit(*fid, fid_bitmap); 1111fad09c73SVivien Didelot } 1112fad09c73SVivien Didelot 1113fad09c73SVivien Didelot /* Set every FID bit used by the VLAN entries */ 1114fad09c73SVivien Didelot do { 1115f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1116fad09c73SVivien Didelot if (err) 1117fad09c73SVivien Didelot return err; 1118fad09c73SVivien Didelot 1119fad09c73SVivien Didelot if (!vlan.valid) 1120fad09c73SVivien Didelot break; 1121fad09c73SVivien Didelot 1122fad09c73SVivien Didelot set_bit(vlan.fid, fid_bitmap); 11233cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 1124fad09c73SVivien Didelot 1125fad09c73SVivien Didelot /* The reset value 0x000 is used to indicate that multiple address 1126fad09c73SVivien Didelot * databases are not needed. Return the next positive available. 1127fad09c73SVivien Didelot */ 1128fad09c73SVivien Didelot *fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1); 1129fad09c73SVivien Didelot if (unlikely(*fid >= mv88e6xxx_num_databases(chip))) 1130fad09c73SVivien Didelot return -ENOSPC; 1131fad09c73SVivien Didelot 1132fad09c73SVivien Didelot /* Clear the database */ 1133daefc943SVivien Didelot return mv88e6xxx_g1_atu_flush(chip, *fid, true); 1134fad09c73SVivien Didelot } 1135fad09c73SVivien Didelot 1136567aa59aSVivien Didelot static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid, 1137567aa59aSVivien Didelot struct mv88e6xxx_vtu_entry *entry, bool new) 1138fad09c73SVivien Didelot { 1139fad09c73SVivien Didelot int err; 1140fad09c73SVivien Didelot 1141fad09c73SVivien Didelot if (!vid) 1142fad09c73SVivien Didelot return -EINVAL; 1143fad09c73SVivien Didelot 11443afb4bdeSVivien Didelot entry->vid = vid - 1; 11453afb4bdeSVivien Didelot entry->valid = false; 1146fad09c73SVivien Didelot 1147f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, entry); 1148fad09c73SVivien Didelot if (err) 1149fad09c73SVivien Didelot return err; 1150fad09c73SVivien Didelot 1151567aa59aSVivien Didelot if (entry->vid == vid && entry->valid) 1152567aa59aSVivien Didelot return 0; 1153fad09c73SVivien Didelot 1154567aa59aSVivien Didelot if (new) { 1155567aa59aSVivien Didelot int i; 1156567aa59aSVivien Didelot 1157567aa59aSVivien Didelot /* Initialize a fresh VLAN entry */ 1158567aa59aSVivien Didelot memset(entry, 0, sizeof(*entry)); 1159567aa59aSVivien Didelot entry->valid = true; 1160567aa59aSVivien Didelot entry->vid = vid; 1161567aa59aSVivien Didelot 1162567aa59aSVivien Didelot /* Include only CPU and DSA ports */ 1163567aa59aSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 1164567aa59aSVivien Didelot entry->member[i] = dsa_is_normal_port(chip->ds, i) ? 1165567aa59aSVivien Didelot GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER : 1166567aa59aSVivien Didelot GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED; 1167567aa59aSVivien Didelot 1168567aa59aSVivien Didelot return mv88e6xxx_atu_new(chip, &entry->fid); 1169fad09c73SVivien Didelot } 1170fad09c73SVivien Didelot 1171567aa59aSVivien Didelot /* switchdev expects -EOPNOTSUPP to honor software VLANs */ 1172567aa59aSVivien Didelot return -EOPNOTSUPP; 1173fad09c73SVivien Didelot } 1174fad09c73SVivien Didelot 1175fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, 1176fad09c73SVivien Didelot u16 vid_begin, u16 vid_end) 1177fad09c73SVivien Didelot { 117804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 11793afb4bdeSVivien Didelot struct mv88e6xxx_vtu_entry vlan = { 11803afb4bdeSVivien Didelot .vid = vid_begin - 1, 11813afb4bdeSVivien Didelot }; 1182fad09c73SVivien Didelot int i, err; 1183fad09c73SVivien Didelot 1184fad09c73SVivien Didelot if (!vid_begin) 1185fad09c73SVivien Didelot return -EOPNOTSUPP; 1186fad09c73SVivien Didelot 1187fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1188fad09c73SVivien Didelot 1189fad09c73SVivien Didelot do { 1190f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1191fad09c73SVivien Didelot if (err) 1192fad09c73SVivien Didelot goto unlock; 1193fad09c73SVivien Didelot 1194fad09c73SVivien Didelot if (!vlan.valid) 1195fad09c73SVivien Didelot break; 1196fad09c73SVivien Didelot 1197fad09c73SVivien Didelot if (vlan.vid > vid_end) 1198fad09c73SVivien Didelot break; 1199fad09c73SVivien Didelot 1200370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1201fad09c73SVivien Didelot if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i)) 1202fad09c73SVivien Didelot continue; 1203fad09c73SVivien Didelot 120466e2809dSAndrew Lunn if (!ds->ports[port].netdev) 120566e2809dSAndrew Lunn continue; 120666e2809dSAndrew Lunn 1207bd00e053SVivien Didelot if (vlan.member[i] == 1208fad09c73SVivien Didelot GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1209fad09c73SVivien Didelot continue; 1210fad09c73SVivien Didelot 1211fae8a25eSVivien Didelot if (ds->ports[i].bridge_dev == 1212fae8a25eSVivien Didelot ds->ports[port].bridge_dev) 1213fad09c73SVivien Didelot break; /* same bridge, check next VLAN */ 1214fad09c73SVivien Didelot 1215fae8a25eSVivien Didelot if (!ds->ports[i].bridge_dev) 121666e2809dSAndrew Lunn continue; 121766e2809dSAndrew Lunn 1218fad09c73SVivien Didelot netdev_warn(ds->ports[port].netdev, 1219fad09c73SVivien Didelot "hardware VLAN %d already used by %s\n", 1220fad09c73SVivien Didelot vlan.vid, 1221fae8a25eSVivien Didelot netdev_name(ds->ports[i].bridge_dev)); 1222fad09c73SVivien Didelot err = -EOPNOTSUPP; 1223fad09c73SVivien Didelot goto unlock; 1224fad09c73SVivien Didelot } 1225fad09c73SVivien Didelot } while (vlan.vid < vid_end); 1226fad09c73SVivien Didelot 1227fad09c73SVivien Didelot unlock: 1228fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1229fad09c73SVivien Didelot 1230fad09c73SVivien Didelot return err; 1231fad09c73SVivien Didelot } 1232fad09c73SVivien Didelot 1233fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, 1234fad09c73SVivien Didelot bool vlan_filtering) 1235fad09c73SVivien Didelot { 123604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1237385a0995SVivien Didelot u16 mode = vlan_filtering ? PORT_CONTROL_2_8021Q_SECURE : 1238fad09c73SVivien Didelot PORT_CONTROL_2_8021Q_DISABLED; 12390e7b9925SAndrew Lunn int err; 1240fad09c73SVivien Didelot 12413cf3c846SVivien Didelot if (!chip->info->max_vid) 1242fad09c73SVivien Didelot return -EOPNOTSUPP; 1243fad09c73SVivien Didelot 1244fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1245385a0995SVivien Didelot err = mv88e6xxx_port_set_8021q_mode(chip, port, mode); 1246fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1247fad09c73SVivien Didelot 12480e7b9925SAndrew Lunn return err; 1249fad09c73SVivien Didelot } 1250fad09c73SVivien Didelot 1251fad09c73SVivien Didelot static int 1252fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, 1253fad09c73SVivien Didelot const struct switchdev_obj_port_vlan *vlan, 1254fad09c73SVivien Didelot struct switchdev_trans *trans) 1255fad09c73SVivien Didelot { 125604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1257fad09c73SVivien Didelot int err; 1258fad09c73SVivien Didelot 12593cf3c846SVivien Didelot if (!chip->info->max_vid) 1260fad09c73SVivien Didelot return -EOPNOTSUPP; 1261fad09c73SVivien Didelot 1262fad09c73SVivien Didelot /* If the requested port doesn't belong to the same bridge as the VLAN 1263fad09c73SVivien Didelot * members, do not support it (yet) and fallback to software VLAN. 1264fad09c73SVivien Didelot */ 1265fad09c73SVivien Didelot err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin, 1266fad09c73SVivien Didelot vlan->vid_end); 1267fad09c73SVivien Didelot if (err) 1268fad09c73SVivien Didelot return err; 1269fad09c73SVivien Didelot 1270fad09c73SVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 1271fad09c73SVivien Didelot * so skip the prepare phase. 1272fad09c73SVivien Didelot */ 1273fad09c73SVivien Didelot return 0; 1274fad09c73SVivien Didelot } 1275fad09c73SVivien Didelot 1276fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port, 1277fad09c73SVivien Didelot u16 vid, bool untagged) 1278fad09c73SVivien Didelot { 1279b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1280fad09c73SVivien Didelot int err; 1281fad09c73SVivien Didelot 1282567aa59aSVivien Didelot err = mv88e6xxx_vtu_get(chip, vid, &vlan, true); 1283fad09c73SVivien Didelot if (err) 1284fad09c73SVivien Didelot return err; 1285fad09c73SVivien Didelot 1286bd00e053SVivien Didelot vlan.member[port] = untagged ? 1287fad09c73SVivien Didelot GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED : 1288fad09c73SVivien Didelot GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED; 1289fad09c73SVivien Didelot 12900ad5daf6SVivien Didelot return mv88e6xxx_vtu_loadpurge(chip, &vlan); 1291fad09c73SVivien Didelot } 1292fad09c73SVivien Didelot 1293fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, 1294fad09c73SVivien Didelot const struct switchdev_obj_port_vlan *vlan, 1295fad09c73SVivien Didelot struct switchdev_trans *trans) 1296fad09c73SVivien Didelot { 129704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1298fad09c73SVivien Didelot bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; 1299fad09c73SVivien Didelot bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 1300fad09c73SVivien Didelot u16 vid; 1301fad09c73SVivien Didelot 13023cf3c846SVivien Didelot if (!chip->info->max_vid) 1303fad09c73SVivien Didelot return; 1304fad09c73SVivien Didelot 1305fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1306fad09c73SVivien Didelot 1307fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) 1308fad09c73SVivien Didelot if (_mv88e6xxx_port_vlan_add(chip, port, vid, untagged)) 1309fad09c73SVivien Didelot netdev_err(ds->ports[port].netdev, 1310fad09c73SVivien Didelot "failed to add VLAN %d%c\n", 1311fad09c73SVivien Didelot vid, untagged ? 'u' : 't'); 1312fad09c73SVivien Didelot 131377064f37SVivien Didelot if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end)) 1314fad09c73SVivien Didelot netdev_err(ds->ports[port].netdev, "failed to set PVID %d\n", 1315fad09c73SVivien Didelot vlan->vid_end); 1316fad09c73SVivien Didelot 1317fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1318fad09c73SVivien Didelot } 1319fad09c73SVivien Didelot 1320fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip, 1321fad09c73SVivien Didelot int port, u16 vid) 1322fad09c73SVivien Didelot { 1323fad09c73SVivien Didelot struct dsa_switch *ds = chip->ds; 1324b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1325fad09c73SVivien Didelot int i, err; 1326fad09c73SVivien Didelot 1327567aa59aSVivien Didelot err = mv88e6xxx_vtu_get(chip, vid, &vlan, false); 1328fad09c73SVivien Didelot if (err) 1329fad09c73SVivien Didelot return err; 1330fad09c73SVivien Didelot 1331fad09c73SVivien Didelot /* Tell switchdev if this VLAN is handled in software */ 1332bd00e053SVivien Didelot if (vlan.member[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1333fad09c73SVivien Didelot return -EOPNOTSUPP; 1334fad09c73SVivien Didelot 1335bd00e053SVivien Didelot vlan.member[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER; 1336fad09c73SVivien Didelot 1337fad09c73SVivien Didelot /* keep the VLAN unless all ports are excluded */ 1338fad09c73SVivien Didelot vlan.valid = false; 1339370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1340fad09c73SVivien Didelot if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i)) 1341fad09c73SVivien Didelot continue; 1342fad09c73SVivien Didelot 1343bd00e053SVivien Didelot if (vlan.member[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) { 1344fad09c73SVivien Didelot vlan.valid = true; 1345fad09c73SVivien Didelot break; 1346fad09c73SVivien Didelot } 1347fad09c73SVivien Didelot } 1348fad09c73SVivien Didelot 13490ad5daf6SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 1350fad09c73SVivien Didelot if (err) 1351fad09c73SVivien Didelot return err; 1352fad09c73SVivien Didelot 1353e606ca36SVivien Didelot return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); 1354fad09c73SVivien Didelot } 1355fad09c73SVivien Didelot 1356fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, 1357fad09c73SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1358fad09c73SVivien Didelot { 135904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1360fad09c73SVivien Didelot u16 pvid, vid; 1361fad09c73SVivien Didelot int err = 0; 1362fad09c73SVivien Didelot 13633cf3c846SVivien Didelot if (!chip->info->max_vid) 1364fad09c73SVivien Didelot return -EOPNOTSUPP; 1365fad09c73SVivien Didelot 1366fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1367fad09c73SVivien Didelot 136877064f37SVivien Didelot err = mv88e6xxx_port_get_pvid(chip, port, &pvid); 1369fad09c73SVivien Didelot if (err) 1370fad09c73SVivien Didelot goto unlock; 1371fad09c73SVivien Didelot 1372fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { 1373fad09c73SVivien Didelot err = _mv88e6xxx_port_vlan_del(chip, port, vid); 1374fad09c73SVivien Didelot if (err) 1375fad09c73SVivien Didelot goto unlock; 1376fad09c73SVivien Didelot 1377fad09c73SVivien Didelot if (vid == pvid) { 137877064f37SVivien Didelot err = mv88e6xxx_port_set_pvid(chip, port, 0); 1379fad09c73SVivien Didelot if (err) 1380fad09c73SVivien Didelot goto unlock; 1381fad09c73SVivien Didelot } 1382fad09c73SVivien Didelot } 1383fad09c73SVivien Didelot 1384fad09c73SVivien Didelot unlock: 1385fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1386fad09c73SVivien Didelot 1387fad09c73SVivien Didelot return err; 1388fad09c73SVivien Didelot } 1389fad09c73SVivien Didelot 139083dabd1fSVivien Didelot static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, 1391fad09c73SVivien Didelot const unsigned char *addr, u16 vid, 1392fad09c73SVivien Didelot u8 state) 1393fad09c73SVivien Didelot { 1394b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 139588472939SVivien Didelot struct mv88e6xxx_atu_entry entry; 1396fad09c73SVivien Didelot int err; 1397fad09c73SVivien Didelot 1398fad09c73SVivien Didelot /* Null VLAN ID corresponds to the port private database */ 1399fad09c73SVivien Didelot if (vid == 0) 1400b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid); 1401fad09c73SVivien Didelot else 1402567aa59aSVivien Didelot err = mv88e6xxx_vtu_get(chip, vid, &vlan, false); 1403fad09c73SVivien Didelot if (err) 1404fad09c73SVivien Didelot return err; 1405fad09c73SVivien Didelot 1406dabc1a96SVivien Didelot entry.state = GLOBAL_ATU_DATA_STATE_UNUSED; 1407dabc1a96SVivien Didelot ether_addr_copy(entry.mac, addr); 1408dabc1a96SVivien Didelot eth_addr_dec(entry.mac); 1409dabc1a96SVivien Didelot 1410dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry); 141188472939SVivien Didelot if (err) 141288472939SVivien Didelot return err; 141388472939SVivien Didelot 1414dabc1a96SVivien Didelot /* Initialize a fresh ATU entry if it isn't found */ 1415dabc1a96SVivien Didelot if (entry.state == GLOBAL_ATU_DATA_STATE_UNUSED || 1416dabc1a96SVivien Didelot !ether_addr_equal(entry.mac, addr)) { 1417dabc1a96SVivien Didelot memset(&entry, 0, sizeof(entry)); 1418dabc1a96SVivien Didelot ether_addr_copy(entry.mac, addr); 1419dabc1a96SVivien Didelot } 1420dabc1a96SVivien Didelot 142188472939SVivien Didelot /* Purge the ATU entry only if no port is using it anymore */ 142288472939SVivien Didelot if (state == GLOBAL_ATU_DATA_STATE_UNUSED) { 142301bd96c8SVivien Didelot entry.portvec &= ~BIT(port); 142401bd96c8SVivien Didelot if (!entry.portvec) 142588472939SVivien Didelot entry.state = GLOBAL_ATU_DATA_STATE_UNUSED; 142688472939SVivien Didelot } else { 142701bd96c8SVivien Didelot entry.portvec |= BIT(port); 1428fad09c73SVivien Didelot entry.state = state; 1429fad09c73SVivien Didelot } 1430fad09c73SVivien Didelot 14319c13c026SVivien Didelot return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry); 1432fad09c73SVivien Didelot } 1433fad09c73SVivien Didelot 1434fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port, 1435fad09c73SVivien Didelot const struct switchdev_obj_port_fdb *fdb, 1436fad09c73SVivien Didelot struct switchdev_trans *trans) 1437fad09c73SVivien Didelot { 1438fad09c73SVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 1439fad09c73SVivien Didelot * so skip the prepare phase. 1440fad09c73SVivien Didelot */ 1441fad09c73SVivien Didelot return 0; 1442fad09c73SVivien Didelot } 1443fad09c73SVivien Didelot 1444fad09c73SVivien Didelot static void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, 1445fad09c73SVivien Didelot const struct switchdev_obj_port_fdb *fdb, 1446fad09c73SVivien Didelot struct switchdev_trans *trans) 1447fad09c73SVivien Didelot { 144804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1449fad09c73SVivien Didelot 1450fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 145183dabd1fSVivien Didelot if (mv88e6xxx_port_db_load_purge(chip, port, fdb->addr, fdb->vid, 145283dabd1fSVivien Didelot GLOBAL_ATU_DATA_STATE_UC_STATIC)) 145383dabd1fSVivien Didelot netdev_err(ds->ports[port].netdev, "failed to load unicast MAC address\n"); 1454fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1455fad09c73SVivien Didelot } 1456fad09c73SVivien Didelot 1457fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, 1458fad09c73SVivien Didelot const struct switchdev_obj_port_fdb *fdb) 1459fad09c73SVivien Didelot { 146004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 146183dabd1fSVivien Didelot int err; 1462fad09c73SVivien Didelot 1463fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 146483dabd1fSVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, fdb->addr, fdb->vid, 1465fad09c73SVivien Didelot GLOBAL_ATU_DATA_STATE_UNUSED); 1466fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1467fad09c73SVivien Didelot 146883dabd1fSVivien Didelot return err; 1469fad09c73SVivien Didelot } 1470fad09c73SVivien Didelot 147183dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, 1472fad09c73SVivien Didelot u16 fid, u16 vid, int port, 147383dabd1fSVivien Didelot struct switchdev_obj *obj, 1474438ff537SVivien Didelot switchdev_obj_dump_cb_t *cb) 1475fad09c73SVivien Didelot { 1476dabc1a96SVivien Didelot struct mv88e6xxx_atu_entry addr; 1477fad09c73SVivien Didelot int err; 1478fad09c73SVivien Didelot 1479dabc1a96SVivien Didelot addr.state = GLOBAL_ATU_DATA_STATE_UNUSED; 1480dabc1a96SVivien Didelot eth_broadcast_addr(addr.mac); 1481fad09c73SVivien Didelot 1482fad09c73SVivien Didelot do { 1483dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); 1484fad09c73SVivien Didelot if (err) 148583dabd1fSVivien Didelot return err; 1486fad09c73SVivien Didelot 1487fad09c73SVivien Didelot if (addr.state == GLOBAL_ATU_DATA_STATE_UNUSED) 1488fad09c73SVivien Didelot break; 1489fad09c73SVivien Didelot 149001bd96c8SVivien Didelot if (addr.trunk || (addr.portvec & BIT(port)) == 0) 149183dabd1fSVivien Didelot continue; 1492fad09c73SVivien Didelot 149383dabd1fSVivien Didelot if (obj->id == SWITCHDEV_OBJ_ID_PORT_FDB) { 149483dabd1fSVivien Didelot struct switchdev_obj_port_fdb *fdb; 149583dabd1fSVivien Didelot 149683dabd1fSVivien Didelot if (!is_unicast_ether_addr(addr.mac)) 149783dabd1fSVivien Didelot continue; 149883dabd1fSVivien Didelot 149983dabd1fSVivien Didelot fdb = SWITCHDEV_OBJ_PORT_FDB(obj); 1500fad09c73SVivien Didelot fdb->vid = vid; 1501fad09c73SVivien Didelot ether_addr_copy(fdb->addr, addr.mac); 150283dabd1fSVivien Didelot if (addr.state == GLOBAL_ATU_DATA_STATE_UC_STATIC) 150383dabd1fSVivien Didelot fdb->ndm_state = NUD_NOARP; 150483dabd1fSVivien Didelot else 150583dabd1fSVivien Didelot fdb->ndm_state = NUD_REACHABLE; 15067df8fbddSVivien Didelot } else if (obj->id == SWITCHDEV_OBJ_ID_PORT_MDB) { 15077df8fbddSVivien Didelot struct switchdev_obj_port_mdb *mdb; 15087df8fbddSVivien Didelot 15097df8fbddSVivien Didelot if (!is_multicast_ether_addr(addr.mac)) 15107df8fbddSVivien Didelot continue; 15117df8fbddSVivien Didelot 15127df8fbddSVivien Didelot mdb = SWITCHDEV_OBJ_PORT_MDB(obj); 15137df8fbddSVivien Didelot mdb->vid = vid; 15147df8fbddSVivien Didelot ether_addr_copy(mdb->addr, addr.mac); 151583dabd1fSVivien Didelot } else { 151683dabd1fSVivien Didelot return -EOPNOTSUPP; 1517fad09c73SVivien Didelot } 151883dabd1fSVivien Didelot 151983dabd1fSVivien Didelot err = cb(obj); 152083dabd1fSVivien Didelot if (err) 152183dabd1fSVivien Didelot return err; 1522fad09c73SVivien Didelot } while (!is_broadcast_ether_addr(addr.mac)); 1523fad09c73SVivien Didelot 1524fad09c73SVivien Didelot return err; 1525fad09c73SVivien Didelot } 1526fad09c73SVivien Didelot 152783dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, 152883dabd1fSVivien Didelot struct switchdev_obj *obj, 1529438ff537SVivien Didelot switchdev_obj_dump_cb_t *cb) 153083dabd1fSVivien Didelot { 1531b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan = { 15323cf3c846SVivien Didelot .vid = chip->info->max_vid, 153383dabd1fSVivien Didelot }; 153483dabd1fSVivien Didelot u16 fid; 153583dabd1fSVivien Didelot int err; 153683dabd1fSVivien Didelot 153783dabd1fSVivien Didelot /* Dump port's default Filtering Information Database (VLAN ID 0) */ 1538b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &fid); 153983dabd1fSVivien Didelot if (err) 154083dabd1fSVivien Didelot return err; 154183dabd1fSVivien Didelot 154283dabd1fSVivien Didelot err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, obj, cb); 154383dabd1fSVivien Didelot if (err) 154483dabd1fSVivien Didelot return err; 154583dabd1fSVivien Didelot 154683dabd1fSVivien Didelot /* Dump VLANs' Filtering Information Databases */ 154783dabd1fSVivien Didelot do { 1548f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 154983dabd1fSVivien Didelot if (err) 155083dabd1fSVivien Didelot return err; 155183dabd1fSVivien Didelot 155283dabd1fSVivien Didelot if (!vlan.valid) 155383dabd1fSVivien Didelot break; 155483dabd1fSVivien Didelot 155583dabd1fSVivien Didelot err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port, 155683dabd1fSVivien Didelot obj, cb); 155783dabd1fSVivien Didelot if (err) 155883dabd1fSVivien Didelot return err; 15593cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 156083dabd1fSVivien Didelot 156183dabd1fSVivien Didelot return err; 156283dabd1fSVivien Didelot } 156383dabd1fSVivien Didelot 1564fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, 1565fad09c73SVivien Didelot struct switchdev_obj_port_fdb *fdb, 1566438ff537SVivien Didelot switchdev_obj_dump_cb_t *cb) 1567fad09c73SVivien Didelot { 156804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1569fad09c73SVivien Didelot int err; 1570fad09c73SVivien Didelot 1571fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 157283dabd1fSVivien Didelot err = mv88e6xxx_port_db_dump(chip, port, &fdb->obj, cb); 1573fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1574fad09c73SVivien Didelot 1575fad09c73SVivien Didelot return err; 1576fad09c73SVivien Didelot } 1577fad09c73SVivien Didelot 1578240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, 1579240ea3efSVivien Didelot struct net_device *br) 1580240ea3efSVivien Didelot { 1581e96a6e02SVivien Didelot struct dsa_switch *ds; 1582240ea3efSVivien Didelot int port; 1583e96a6e02SVivien Didelot int dev; 1584240ea3efSVivien Didelot int err; 1585240ea3efSVivien Didelot 1586240ea3efSVivien Didelot /* Remap the Port VLAN of each local bridge group member */ 1587240ea3efSVivien Didelot for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) { 1588240ea3efSVivien Didelot if (chip->ds->ports[port].bridge_dev == br) { 1589240ea3efSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, port); 1590240ea3efSVivien Didelot if (err) 1591240ea3efSVivien Didelot return err; 1592240ea3efSVivien Didelot } 1593240ea3efSVivien Didelot } 1594240ea3efSVivien Didelot 1595e96a6e02SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1596e96a6e02SVivien Didelot return 0; 1597e96a6e02SVivien Didelot 1598e96a6e02SVivien Didelot /* Remap the Port VLAN of each cross-chip bridge group member */ 1599e96a6e02SVivien Didelot for (dev = 0; dev < DSA_MAX_SWITCHES; ++dev) { 1600e96a6e02SVivien Didelot ds = chip->ds->dst->ds[dev]; 1601e96a6e02SVivien Didelot if (!ds) 1602e96a6e02SVivien Didelot break; 1603e96a6e02SVivien Didelot 1604e96a6e02SVivien Didelot for (port = 0; port < ds->num_ports; ++port) { 1605e96a6e02SVivien Didelot if (ds->ports[port].bridge_dev == br) { 1606e96a6e02SVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 1607e96a6e02SVivien Didelot if (err) 1608e96a6e02SVivien Didelot return err; 1609e96a6e02SVivien Didelot } 1610e96a6e02SVivien Didelot } 1611e96a6e02SVivien Didelot } 1612e96a6e02SVivien Didelot 1613240ea3efSVivien Didelot return 0; 1614240ea3efSVivien Didelot } 1615240ea3efSVivien Didelot 1616fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, 1617fae8a25eSVivien Didelot struct net_device *br) 1618fad09c73SVivien Didelot { 161904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1620240ea3efSVivien Didelot int err; 1621fad09c73SVivien Didelot 1622fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1623240ea3efSVivien Didelot err = mv88e6xxx_bridge_map(chip, br); 1624fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1625fad09c73SVivien Didelot 1626fad09c73SVivien Didelot return err; 1627fad09c73SVivien Didelot } 1628fad09c73SVivien Didelot 1629f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, 1630f123f2fbSVivien Didelot struct net_device *br) 1631fad09c73SVivien Didelot { 163204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1633fad09c73SVivien Didelot 1634fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1635240ea3efSVivien Didelot if (mv88e6xxx_bridge_map(chip, br) || 1636240ea3efSVivien Didelot mv88e6xxx_port_vlan_map(chip, port)) 1637240ea3efSVivien Didelot dev_err(ds->dev, "failed to remap in-chip Port VLAN\n"); 1638fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1639fad09c73SVivien Didelot } 1640fad09c73SVivien Didelot 1641aec5ac88SVivien Didelot static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev, 1642aec5ac88SVivien Didelot int port, struct net_device *br) 1643aec5ac88SVivien Didelot { 1644aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1645aec5ac88SVivien Didelot int err; 1646aec5ac88SVivien Didelot 1647aec5ac88SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1648aec5ac88SVivien Didelot return 0; 1649aec5ac88SVivien Didelot 1650aec5ac88SVivien Didelot mutex_lock(&chip->reg_lock); 1651aec5ac88SVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 1652aec5ac88SVivien Didelot mutex_unlock(&chip->reg_lock); 1653aec5ac88SVivien Didelot 1654aec5ac88SVivien Didelot return err; 1655aec5ac88SVivien Didelot } 1656aec5ac88SVivien Didelot 1657aec5ac88SVivien Didelot static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev, 1658aec5ac88SVivien Didelot int port, struct net_device *br) 1659aec5ac88SVivien Didelot { 1660aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1661aec5ac88SVivien Didelot 1662aec5ac88SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1663aec5ac88SVivien Didelot return; 1664aec5ac88SVivien Didelot 1665aec5ac88SVivien Didelot mutex_lock(&chip->reg_lock); 1666aec5ac88SVivien Didelot if (mv88e6xxx_pvt_map(chip, dev, port)) 1667aec5ac88SVivien Didelot dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); 1668aec5ac88SVivien Didelot mutex_unlock(&chip->reg_lock); 1669aec5ac88SVivien Didelot } 1670aec5ac88SVivien Didelot 167117e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip) 167217e708baSVivien Didelot { 167317e708baSVivien Didelot if (chip->info->ops->reset) 167417e708baSVivien Didelot return chip->info->ops->reset(chip); 167517e708baSVivien Didelot 167617e708baSVivien Didelot return 0; 167717e708baSVivien Didelot } 167817e708baSVivien Didelot 1679309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) 1680309eca6dSVivien Didelot { 1681309eca6dSVivien Didelot struct gpio_desc *gpiod = chip->reset; 1682309eca6dSVivien Didelot 1683309eca6dSVivien Didelot /* If there is a GPIO connected to the reset pin, toggle it */ 1684309eca6dSVivien Didelot if (gpiod) { 1685309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 1); 1686309eca6dSVivien Didelot usleep_range(10000, 20000); 1687309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 0); 1688309eca6dSVivien Didelot usleep_range(10000, 20000); 1689309eca6dSVivien Didelot } 1690309eca6dSVivien Didelot } 1691309eca6dSVivien Didelot 16924ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip) 16934ac4b5a6SVivien Didelot { 16944ac4b5a6SVivien Didelot int i, err; 16954ac4b5a6SVivien Didelot 16964ac4b5a6SVivien Didelot /* Set all ports to the Disabled state */ 16974ac4b5a6SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 16984ac4b5a6SVivien Didelot err = mv88e6xxx_port_set_state(chip, i, 16994ac4b5a6SVivien Didelot PORT_CONTROL_STATE_DISABLED); 17004ac4b5a6SVivien Didelot if (err) 17014ac4b5a6SVivien Didelot return err; 17024ac4b5a6SVivien Didelot } 17034ac4b5a6SVivien Didelot 17044ac4b5a6SVivien Didelot /* Wait for transmit queues to drain, 17054ac4b5a6SVivien Didelot * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps. 17064ac4b5a6SVivien Didelot */ 17074ac4b5a6SVivien Didelot usleep_range(2000, 4000); 17084ac4b5a6SVivien Didelot 17094ac4b5a6SVivien Didelot return 0; 17104ac4b5a6SVivien Didelot } 17114ac4b5a6SVivien Didelot 1712fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip) 1713fad09c73SVivien Didelot { 1714a935c052SVivien Didelot int err; 1715fad09c73SVivien Didelot 17164ac4b5a6SVivien Didelot err = mv88e6xxx_disable_ports(chip); 17170e7b9925SAndrew Lunn if (err) 17180e7b9925SAndrew Lunn return err; 1719fad09c73SVivien Didelot 1720309eca6dSVivien Didelot mv88e6xxx_hardware_reset(chip); 1721fad09c73SVivien Didelot 172217e708baSVivien Didelot return mv88e6xxx_software_reset(chip); 1723fad09c73SVivien Didelot } 1724fad09c73SVivien Didelot 17254314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, 17264314557cSVivien Didelot enum mv88e6xxx_frame_mode frame, u16 egress, 17274314557cSVivien Didelot u16 etype) 172856995cbcSAndrew Lunn { 172956995cbcSAndrew Lunn int err; 173056995cbcSAndrew Lunn 17314314557cSVivien Didelot if (!chip->info->ops->port_set_frame_mode) 17324314557cSVivien Didelot return -EOPNOTSUPP; 17334314557cSVivien Didelot 17344314557cSVivien Didelot err = mv88e6xxx_port_set_egress_mode(chip, port, egress); 173556995cbcSAndrew Lunn if (err) 173656995cbcSAndrew Lunn return err; 173756995cbcSAndrew Lunn 17384314557cSVivien Didelot err = chip->info->ops->port_set_frame_mode(chip, port, frame); 17394314557cSVivien Didelot if (err) 17404314557cSVivien Didelot return err; 17414314557cSVivien Didelot 17424314557cSVivien Didelot if (chip->info->ops->port_set_ether_type) 17434314557cSVivien Didelot return chip->info->ops->port_set_ether_type(chip, port, etype); 17444314557cSVivien Didelot 17454314557cSVivien Didelot return 0; 17464314557cSVivien Didelot } 17474314557cSVivien Didelot 17484314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port) 17494314557cSVivien Didelot { 17504314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL, 17514314557cSVivien Didelot PORT_CONTROL_EGRESS_UNMODIFIED, 17524314557cSVivien Didelot PORT_ETH_TYPE_DEFAULT); 17534314557cSVivien Didelot } 17544314557cSVivien Didelot 17554314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port) 17564314557cSVivien Didelot { 17574314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA, 17584314557cSVivien Didelot PORT_CONTROL_EGRESS_UNMODIFIED, 17594314557cSVivien Didelot PORT_ETH_TYPE_DEFAULT); 17604314557cSVivien Didelot } 17614314557cSVivien Didelot 17624314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port) 17634314557cSVivien Didelot { 17644314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, 17654314557cSVivien Didelot MV88E6XXX_FRAME_MODE_ETHERTYPE, 17664314557cSVivien Didelot PORT_CONTROL_EGRESS_ADD_TAG, ETH_P_EDSA); 17674314557cSVivien Didelot } 17684314557cSVivien Didelot 17694314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port) 17704314557cSVivien Didelot { 17714314557cSVivien Didelot if (dsa_is_dsa_port(chip->ds, port)) 17724314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 17734314557cSVivien Didelot 17744314557cSVivien Didelot if (dsa_is_normal_port(chip->ds, port)) 17754314557cSVivien Didelot return mv88e6xxx_set_port_mode_normal(chip, port); 17764314557cSVivien Didelot 17774314557cSVivien Didelot /* Setup CPU port mode depending on its supported tag format */ 17784314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA) 17794314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 17804314557cSVivien Didelot 17814314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA) 17824314557cSVivien Didelot return mv88e6xxx_set_port_mode_edsa(chip, port); 17834314557cSVivien Didelot 17844314557cSVivien Didelot return -EINVAL; 17854314557cSVivien Didelot } 17864314557cSVivien Didelot 1787ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port) 1788ea698f4fSVivien Didelot { 1789ea698f4fSVivien Didelot bool message = dsa_is_dsa_port(chip->ds, port); 1790ea698f4fSVivien Didelot 1791ea698f4fSVivien Didelot return mv88e6xxx_port_set_message_port(chip, port, message); 1792ea698f4fSVivien Didelot } 1793ea698f4fSVivien Didelot 1794601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) 1795601aeed3SVivien Didelot { 1796601aeed3SVivien Didelot bool flood = port == dsa_upstream_port(chip->ds); 1797601aeed3SVivien Didelot 1798601aeed3SVivien Didelot /* Upstream ports flood frames with unknown unicast or multicast DA */ 1799601aeed3SVivien Didelot if (chip->info->ops->port_set_egress_floods) 1800601aeed3SVivien Didelot return chip->info->ops->port_set_egress_floods(chip, port, 1801601aeed3SVivien Didelot flood, flood); 1802601aeed3SVivien Didelot 1803601aeed3SVivien Didelot return 0; 1804601aeed3SVivien Didelot } 1805601aeed3SVivien Didelot 18066d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, 18076d91782fSAndrew Lunn bool on) 18086d91782fSAndrew Lunn { 1809523a8904SVivien Didelot if (chip->info->ops->serdes_power) 1810523a8904SVivien Didelot return chip->info->ops->serdes_power(chip, port, on); 18116d91782fSAndrew Lunn 1812523a8904SVivien Didelot return 0; 18136d91782fSAndrew Lunn } 18146d91782fSAndrew Lunn 1815fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) 1816fad09c73SVivien Didelot { 1817fad09c73SVivien Didelot struct dsa_switch *ds = chip->ds; 18180e7b9925SAndrew Lunn int err; 1819fad09c73SVivien Didelot u16 reg; 1820fad09c73SVivien Didelot 1821d78343d2SVivien Didelot /* MAC Forcing register: don't force link, speed, duplex or flow control 1822d78343d2SVivien Didelot * state to any particular values on physical ports, but force the CPU 1823d78343d2SVivien Didelot * port and all DSA ports to their maximum bandwidth and full duplex. 1824fad09c73SVivien Didelot */ 1825d78343d2SVivien Didelot if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) 1826d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP, 1827d78343d2SVivien Didelot SPEED_MAX, DUPLEX_FULL, 1828d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 1829fad09c73SVivien Didelot else 1830d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, 1831d78343d2SVivien Didelot SPEED_UNFORCED, DUPLEX_UNFORCED, 1832d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 18330e7b9925SAndrew Lunn if (err) 18340e7b9925SAndrew Lunn return err; 1835fad09c73SVivien Didelot 1836fad09c73SVivien Didelot /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, 1837fad09c73SVivien Didelot * disable Header mode, enable IGMP/MLD snooping, disable VLAN 1838fad09c73SVivien Didelot * tunneling, determine priority by looking at 802.1p and IP 1839fad09c73SVivien Didelot * priority fields (IP prio has precedence), and set STP state 1840fad09c73SVivien Didelot * to Forwarding. 1841fad09c73SVivien Didelot * 1842fad09c73SVivien Didelot * If this is the CPU link, use DSA or EDSA tagging depending 1843fad09c73SVivien Didelot * on which tagging mode was configured. 1844fad09c73SVivien Didelot * 1845fad09c73SVivien Didelot * If this is a link to another switch, use DSA tagging mode. 1846fad09c73SVivien Didelot * 1847fad09c73SVivien Didelot * If this is the upstream port for this switch, enable 1848fad09c73SVivien Didelot * forwarding of unknown unicasts and multicasts. 1849fad09c73SVivien Didelot */ 1850fad09c73SVivien Didelot reg = PORT_CONTROL_IGMP_MLD_SNOOP | 1851fad09c73SVivien Didelot PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP | 1852fad09c73SVivien Didelot PORT_CONTROL_STATE_FORWARDING; 18530e7b9925SAndrew Lunn err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); 18540e7b9925SAndrew Lunn if (err) 18550e7b9925SAndrew Lunn return err; 185656995cbcSAndrew Lunn 1857601aeed3SVivien Didelot err = mv88e6xxx_setup_port_mode(chip, port); 185856995cbcSAndrew Lunn if (err) 185956995cbcSAndrew Lunn return err; 1860fad09c73SVivien Didelot 1861601aeed3SVivien Didelot err = mv88e6xxx_setup_egress_floods(chip, port); 18624314557cSVivien Didelot if (err) 18634314557cSVivien Didelot return err; 18644314557cSVivien Didelot 186504aca993SAndrew Lunn /* Enable the SERDES interface for DSA and CPU ports. Normal 186604aca993SAndrew Lunn * ports SERDES are enabled when the port is enabled, thus 186704aca993SAndrew Lunn * saving a bit of power. 1868fad09c73SVivien Didelot */ 186904aca993SAndrew Lunn if ((dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) { 18706d91782fSAndrew Lunn err = mv88e6xxx_serdes_power(chip, port, true); 18710e7b9925SAndrew Lunn if (err) 18720e7b9925SAndrew Lunn return err; 187304aca993SAndrew Lunn } 1874fad09c73SVivien Didelot 1875fad09c73SVivien Didelot /* Port Control 2: don't force a good FCS, set the maximum frame size to 1876fad09c73SVivien Didelot * 10240 bytes, disable 802.1q tags checking, don't discard tagged or 1877fad09c73SVivien Didelot * untagged frames on this port, do a destination address lookup on all 1878fad09c73SVivien Didelot * received packets as usual, disable ARP mirroring and don't send a 1879fad09c73SVivien Didelot * copy of all transmitted/received frames on this port to the CPU. 1880fad09c73SVivien Didelot */ 1881a23b2961SAndrew Lunn err = mv88e6xxx_port_set_map_da(chip, port); 1882a23b2961SAndrew Lunn if (err) 1883a23b2961SAndrew Lunn return err; 1884a23b2961SAndrew Lunn 1885fad09c73SVivien Didelot reg = 0; 1886a23b2961SAndrew Lunn if (chip->info->ops->port_set_upstream_port) { 1887a23b2961SAndrew Lunn err = chip->info->ops->port_set_upstream_port( 1888a23b2961SAndrew Lunn chip, port, dsa_upstream_port(ds)); 18890e7b9925SAndrew Lunn if (err) 18900e7b9925SAndrew Lunn return err; 1891fad09c73SVivien Didelot } 1892fad09c73SVivien Didelot 1893a23b2961SAndrew Lunn err = mv88e6xxx_port_set_8021q_mode(chip, port, 1894a23b2961SAndrew Lunn PORT_CONTROL_2_8021Q_DISABLED); 1895a23b2961SAndrew Lunn if (err) 1896a23b2961SAndrew Lunn return err; 1897a23b2961SAndrew Lunn 18985f436666SAndrew Lunn if (chip->info->ops->port_jumbo_config) { 18995f436666SAndrew Lunn err = chip->info->ops->port_jumbo_config(chip, port); 19005f436666SAndrew Lunn if (err) 19015f436666SAndrew Lunn return err; 19025f436666SAndrew Lunn } 19035f436666SAndrew Lunn 1904fad09c73SVivien Didelot /* Port Association Vector: when learning source addresses 1905fad09c73SVivien Didelot * of packets, add the address to the address database using 1906fad09c73SVivien Didelot * a port bitmap that has only the bit for this port set and 1907fad09c73SVivien Didelot * the other bits clear. 1908fad09c73SVivien Didelot */ 1909fad09c73SVivien Didelot reg = 1 << port; 1910fad09c73SVivien Didelot /* Disable learning for CPU port */ 1911fad09c73SVivien Didelot if (dsa_is_cpu_port(ds, port)) 1912fad09c73SVivien Didelot reg = 0; 1913fad09c73SVivien Didelot 19140e7b9925SAndrew Lunn err = mv88e6xxx_port_write(chip, port, PORT_ASSOC_VECTOR, reg); 19150e7b9925SAndrew Lunn if (err) 19160e7b9925SAndrew Lunn return err; 1917fad09c73SVivien Didelot 1918fad09c73SVivien Didelot /* Egress rate control 2: disable egress rate control. */ 19190e7b9925SAndrew Lunn err = mv88e6xxx_port_write(chip, port, PORT_RATE_CONTROL_2, 0x0000); 19200e7b9925SAndrew Lunn if (err) 19210e7b9925SAndrew Lunn return err; 1922fad09c73SVivien Didelot 1923b35d322aSAndrew Lunn if (chip->info->ops->port_pause_config) { 1924b35d322aSAndrew Lunn err = chip->info->ops->port_pause_config(chip, port); 1925b35d322aSAndrew Lunn if (err) 1926b35d322aSAndrew Lunn return err; 1927b35d322aSAndrew Lunn } 1928b35d322aSAndrew Lunn 1929c8c94891SVivien Didelot if (chip->info->ops->port_disable_learn_limit) { 1930c8c94891SVivien Didelot err = chip->info->ops->port_disable_learn_limit(chip, port); 1931c8c94891SVivien Didelot if (err) 1932c8c94891SVivien Didelot return err; 1933c8c94891SVivien Didelot } 1934c8c94891SVivien Didelot 19359dbfb4e1SVivien Didelot if (chip->info->ops->port_disable_pri_override) { 19369dbfb4e1SVivien Didelot err = chip->info->ops->port_disable_pri_override(chip, port); 19370e7b9925SAndrew Lunn if (err) 19380e7b9925SAndrew Lunn return err; 1939ef0a7318SAndrew Lunn } 19402bbb33beSAndrew Lunn 1941ef0a7318SAndrew Lunn if (chip->info->ops->port_tag_remap) { 1942ef0a7318SAndrew Lunn err = chip->info->ops->port_tag_remap(chip, port); 19430e7b9925SAndrew Lunn if (err) 19440e7b9925SAndrew Lunn return err; 1945fad09c73SVivien Didelot } 1946fad09c73SVivien Didelot 1947ef70b111SAndrew Lunn if (chip->info->ops->port_egress_rate_limiting) { 1948ef70b111SAndrew Lunn err = chip->info->ops->port_egress_rate_limiting(chip, port); 19490e7b9925SAndrew Lunn if (err) 19500e7b9925SAndrew Lunn return err; 1951fad09c73SVivien Didelot } 1952fad09c73SVivien Didelot 1953ea698f4fSVivien Didelot err = mv88e6xxx_setup_message_port(chip, port); 19540e7b9925SAndrew Lunn if (err) 19550e7b9925SAndrew Lunn return err; 1956fad09c73SVivien Didelot 1957fad09c73SVivien Didelot /* Port based VLAN map: give each port the same default address 1958fad09c73SVivien Didelot * database, and allow bidirectional communication between the 1959fad09c73SVivien Didelot * CPU and DSA port(s), and the other ports. 1960fad09c73SVivien Didelot */ 1961b4e48c50SVivien Didelot err = mv88e6xxx_port_set_fid(chip, port, 0); 19620e7b9925SAndrew Lunn if (err) 19630e7b9925SAndrew Lunn return err; 1964fad09c73SVivien Didelot 1965240ea3efSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, port); 19660e7b9925SAndrew Lunn if (err) 19670e7b9925SAndrew Lunn return err; 1968fad09c73SVivien Didelot 1969fad09c73SVivien Didelot /* Default VLAN ID and priority: don't set a default VLAN 1970fad09c73SVivien Didelot * ID, and set the default packet priority to zero. 1971fad09c73SVivien Didelot */ 19720e7b9925SAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_DEFAULT_VLAN, 0x0000); 1973fad09c73SVivien Didelot } 1974fad09c73SVivien Didelot 197504aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port, 197604aca993SAndrew Lunn struct phy_device *phydev) 197704aca993SAndrew Lunn { 197804aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 1979523a8904SVivien Didelot int err; 198004aca993SAndrew Lunn 198104aca993SAndrew Lunn mutex_lock(&chip->reg_lock); 1982523a8904SVivien Didelot err = mv88e6xxx_serdes_power(chip, port, true); 198304aca993SAndrew Lunn mutex_unlock(&chip->reg_lock); 198404aca993SAndrew Lunn 198504aca993SAndrew Lunn return err; 198604aca993SAndrew Lunn } 198704aca993SAndrew Lunn 198804aca993SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port, 198904aca993SAndrew Lunn struct phy_device *phydev) 199004aca993SAndrew Lunn { 199104aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 199204aca993SAndrew Lunn 199304aca993SAndrew Lunn mutex_lock(&chip->reg_lock); 1994523a8904SVivien Didelot if (mv88e6xxx_serdes_power(chip, port, false)) 1995523a8904SVivien Didelot dev_err(chip->dev, "failed to power off SERDES\n"); 199604aca993SAndrew Lunn mutex_unlock(&chip->reg_lock); 199704aca993SAndrew Lunn } 199804aca993SAndrew Lunn 1999aa0938c6SWei Yongjun static int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) 20003b4caa1bSVivien Didelot { 20013b4caa1bSVivien Didelot int err; 20023b4caa1bSVivien Didelot 2003a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]); 20043b4caa1bSVivien Didelot if (err) 20053b4caa1bSVivien Didelot return err; 20063b4caa1bSVivien Didelot 2007a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]); 20083b4caa1bSVivien Didelot if (err) 20093b4caa1bSVivien Didelot return err; 20103b4caa1bSVivien Didelot 2011a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]); 2012a935c052SVivien Didelot if (err) 2013a935c052SVivien Didelot return err; 2014a935c052SVivien Didelot 2015a935c052SVivien Didelot return 0; 20163b4caa1bSVivien Didelot } 20173b4caa1bSVivien Didelot 20182cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, 20192cfcd964SVivien Didelot unsigned int ageing_time) 20202cfcd964SVivien Didelot { 202104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 20222cfcd964SVivien Didelot int err; 20232cfcd964SVivien Didelot 20242cfcd964SVivien Didelot mutex_lock(&chip->reg_lock); 2025720c6343SVivien Didelot err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time); 20262cfcd964SVivien Didelot mutex_unlock(&chip->reg_lock); 20272cfcd964SVivien Didelot 20282cfcd964SVivien Didelot return err; 20292cfcd964SVivien Didelot } 20302cfcd964SVivien Didelot 20319729934cSVivien Didelot static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) 2032fad09c73SVivien Didelot { 2033fad09c73SVivien Didelot struct dsa_switch *ds = chip->ds; 2034fad09c73SVivien Didelot u32 upstream_port = dsa_upstream_port(ds); 2035fad09c73SVivien Didelot int err; 2036fad09c73SVivien Didelot 203733641994SAndrew Lunn if (chip->info->ops->g1_set_cpu_port) { 203833641994SAndrew Lunn err = chip->info->ops->g1_set_cpu_port(chip, upstream_port); 2039fad09c73SVivien Didelot if (err) 2040fad09c73SVivien Didelot return err; 204133641994SAndrew Lunn } 204233641994SAndrew Lunn 204333641994SAndrew Lunn if (chip->info->ops->g1_set_egress_port) { 204433641994SAndrew Lunn err = chip->info->ops->g1_set_egress_port(chip, upstream_port); 204533641994SAndrew Lunn if (err) 204633641994SAndrew Lunn return err; 204733641994SAndrew Lunn } 2048fad09c73SVivien Didelot 2049fad09c73SVivien Didelot /* Disable remote management, and set the switch's DSA device number. */ 2050a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, 2051fad09c73SVivien Didelot GLOBAL_CONTROL_2_MULTIPLE_CASCADE | 2052fad09c73SVivien Didelot (ds->index & 0x1f)); 2053fad09c73SVivien Didelot if (err) 2054fad09c73SVivien Didelot return err; 2055fad09c73SVivien Didelot 2056fad09c73SVivien Didelot /* Configure the IP ToS mapping registers. */ 2057a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_0, 0x0000); 2058fad09c73SVivien Didelot if (err) 2059fad09c73SVivien Didelot return err; 2060a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_1, 0x0000); 2061fad09c73SVivien Didelot if (err) 2062fad09c73SVivien Didelot return err; 2063a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_2, 0x5555); 2064fad09c73SVivien Didelot if (err) 2065fad09c73SVivien Didelot return err; 2066a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_3, 0x5555); 2067fad09c73SVivien Didelot if (err) 2068fad09c73SVivien Didelot return err; 2069a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_4, 0xaaaa); 2070fad09c73SVivien Didelot if (err) 2071fad09c73SVivien Didelot return err; 2072a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_5, 0xaaaa); 2073fad09c73SVivien Didelot if (err) 2074fad09c73SVivien Didelot return err; 2075a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_6, 0xffff); 2076fad09c73SVivien Didelot if (err) 2077fad09c73SVivien Didelot return err; 2078a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_7, 0xffff); 2079fad09c73SVivien Didelot if (err) 2080fad09c73SVivien Didelot return err; 2081fad09c73SVivien Didelot 2082fad09c73SVivien Didelot /* Configure the IEEE 802.1p priority mapping register. */ 2083a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IEEE_PRI, 0xfa41); 2084fad09c73SVivien Didelot if (err) 2085fad09c73SVivien Didelot return err; 2086fad09c73SVivien Didelot 2087de227387SAndrew Lunn /* Initialize the statistics unit */ 2088de227387SAndrew Lunn err = mv88e6xxx_stats_set_histogram(chip); 2089de227387SAndrew Lunn if (err) 2090de227387SAndrew Lunn return err; 2091de227387SAndrew Lunn 20929729934cSVivien Didelot /* Clear the statistics counters for all ports */ 2093a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP, 20949729934cSVivien Didelot GLOBAL_STATS_OP_FLUSH_ALL); 20959729934cSVivien Didelot if (err) 20969729934cSVivien Didelot return err; 20979729934cSVivien Didelot 20989729934cSVivien Didelot /* Wait for the flush to complete. */ 20997f9ef3afSAndrew Lunn err = mv88e6xxx_g1_stats_wait(chip); 21009729934cSVivien Didelot if (err) 21019729934cSVivien Didelot return err; 21029729934cSVivien Didelot 21039729934cSVivien Didelot return 0; 21049729934cSVivien Didelot } 21059729934cSVivien Didelot 2106fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds) 2107fad09c73SVivien Didelot { 210804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2109fad09c73SVivien Didelot int err; 2110fad09c73SVivien Didelot int i; 2111fad09c73SVivien Didelot 2112fad09c73SVivien Didelot chip->ds = ds; 2113a3c53be5SAndrew Lunn ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); 2114fad09c73SVivien Didelot 2115fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 2116fad09c73SVivien Didelot 21179729934cSVivien Didelot /* Setup Switch Port Registers */ 2118370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 21199729934cSVivien Didelot err = mv88e6xxx_setup_port(chip, i); 21209729934cSVivien Didelot if (err) 21219729934cSVivien Didelot goto unlock; 21229729934cSVivien Didelot } 21239729934cSVivien Didelot 21249729934cSVivien Didelot /* Setup Switch Global 1 Registers */ 21259729934cSVivien Didelot err = mv88e6xxx_g1_setup(chip); 2126fad09c73SVivien Didelot if (err) 2127fad09c73SVivien Didelot goto unlock; 2128fad09c73SVivien Didelot 21299729934cSVivien Didelot /* Setup Switch Global 2 Registers */ 21309729934cSVivien Didelot if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_GLOBAL2)) { 21319729934cSVivien Didelot err = mv88e6xxx_g2_setup(chip); 2132fad09c73SVivien Didelot if (err) 2133fad09c73SVivien Didelot goto unlock; 2134fad09c73SVivien Didelot } 2135fad09c73SVivien Didelot 21361b17aedfSVivien Didelot err = mv88e6xxx_phy_setup(chip); 21371b17aedfSVivien Didelot if (err) 21381b17aedfSVivien Didelot goto unlock; 21391b17aedfSVivien Didelot 2140b486d7c9SVivien Didelot err = mv88e6xxx_vtu_setup(chip); 2141b486d7c9SVivien Didelot if (err) 2142b486d7c9SVivien Didelot goto unlock; 2143b486d7c9SVivien Didelot 214481228996SVivien Didelot err = mv88e6xxx_pvt_setup(chip); 214581228996SVivien Didelot if (err) 214681228996SVivien Didelot goto unlock; 214781228996SVivien Didelot 2148a2ac29d2SVivien Didelot err = mv88e6xxx_atu_setup(chip); 2149a2ac29d2SVivien Didelot if (err) 2150a2ac29d2SVivien Didelot goto unlock; 2151a2ac29d2SVivien Didelot 21526e55f698SAndrew Lunn /* Some generations have the configuration of sending reserved 21536e55f698SAndrew Lunn * management frames to the CPU in global2, others in 21546e55f698SAndrew Lunn * global1. Hence it does not fit the two setup functions 21556e55f698SAndrew Lunn * above. 21566e55f698SAndrew Lunn */ 21576e55f698SAndrew Lunn if (chip->info->ops->mgmt_rsvd2cpu) { 21586e55f698SAndrew Lunn err = chip->info->ops->mgmt_rsvd2cpu(chip); 21596e55f698SAndrew Lunn if (err) 21606e55f698SAndrew Lunn goto unlock; 21616e55f698SAndrew Lunn } 21626e55f698SAndrew Lunn 2163fad09c73SVivien Didelot unlock: 2164fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 2165fad09c73SVivien Didelot 2166fad09c73SVivien Didelot return err; 2167fad09c73SVivien Didelot } 2168fad09c73SVivien Didelot 21693b4caa1bSVivien Didelot static int mv88e6xxx_set_addr(struct dsa_switch *ds, u8 *addr) 21703b4caa1bSVivien Didelot { 217104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 21723b4caa1bSVivien Didelot int err; 21733b4caa1bSVivien Didelot 2174b073d4e2SVivien Didelot if (!chip->info->ops->set_switch_mac) 2175b073d4e2SVivien Didelot return -EOPNOTSUPP; 2176b073d4e2SVivien Didelot 21773b4caa1bSVivien Didelot mutex_lock(&chip->reg_lock); 2178b073d4e2SVivien Didelot err = chip->info->ops->set_switch_mac(chip, addr); 21793b4caa1bSVivien Didelot mutex_unlock(&chip->reg_lock); 21803b4caa1bSVivien Didelot 21813b4caa1bSVivien Didelot return err; 21823b4caa1bSVivien Didelot } 21833b4caa1bSVivien Didelot 2184e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) 2185fad09c73SVivien Didelot { 21860dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 21870dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 2188e57e5e77SVivien Didelot u16 val; 2189e57e5e77SVivien Didelot int err; 2190fad09c73SVivien Didelot 2191ee26a228SAndrew Lunn if (!chip->info->ops->phy_read) 2192ee26a228SAndrew Lunn return -EOPNOTSUPP; 2193ee26a228SAndrew Lunn 2194fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 2195ee26a228SAndrew Lunn err = chip->info->ops->phy_read(chip, bus, phy, reg, &val); 2196fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 2197e57e5e77SVivien Didelot 2198da9f3301SAndrew Lunn if (reg == MII_PHYSID2) { 2199da9f3301SAndrew Lunn /* Some internal PHYS don't have a model number. Use 2200da9f3301SAndrew Lunn * the mv88e6390 family model number instead. 2201da9f3301SAndrew Lunn */ 2202da9f3301SAndrew Lunn if (!(val & 0x3f0)) 2203da9f3301SAndrew Lunn val |= PORT_SWITCH_ID_PROD_NUM_6390; 2204da9f3301SAndrew Lunn } 2205da9f3301SAndrew Lunn 2206e57e5e77SVivien Didelot return err ? err : val; 2207fad09c73SVivien Didelot } 2208fad09c73SVivien Didelot 2209e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 2210fad09c73SVivien Didelot { 22110dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 22120dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 2213e57e5e77SVivien Didelot int err; 2214fad09c73SVivien Didelot 2215ee26a228SAndrew Lunn if (!chip->info->ops->phy_write) 2216ee26a228SAndrew Lunn return -EOPNOTSUPP; 2217ee26a228SAndrew Lunn 2218fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 2219ee26a228SAndrew Lunn err = chip->info->ops->phy_write(chip, bus, phy, reg, val); 2220fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 2221e57e5e77SVivien Didelot 2222e57e5e77SVivien Didelot return err; 2223fad09c73SVivien Didelot } 2224fad09c73SVivien Didelot 2225fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, 2226a3c53be5SAndrew Lunn struct device_node *np, 2227a3c53be5SAndrew Lunn bool external) 2228fad09c73SVivien Didelot { 2229fad09c73SVivien Didelot static int index; 22300dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 2231fad09c73SVivien Didelot struct mii_bus *bus; 2232fad09c73SVivien Didelot int err; 2233fad09c73SVivien Didelot 22340dd12d54SAndrew Lunn bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus)); 2235fad09c73SVivien Didelot if (!bus) 2236fad09c73SVivien Didelot return -ENOMEM; 2237fad09c73SVivien Didelot 22380dd12d54SAndrew Lunn mdio_bus = bus->priv; 2239a3c53be5SAndrew Lunn mdio_bus->bus = bus; 22400dd12d54SAndrew Lunn mdio_bus->chip = chip; 2241a3c53be5SAndrew Lunn INIT_LIST_HEAD(&mdio_bus->list); 2242a3c53be5SAndrew Lunn mdio_bus->external = external; 22430dd12d54SAndrew Lunn 2244fad09c73SVivien Didelot if (np) { 2245fad09c73SVivien Didelot bus->name = np->full_name; 2246fad09c73SVivien Didelot snprintf(bus->id, MII_BUS_ID_SIZE, "%s", np->full_name); 2247fad09c73SVivien Didelot } else { 2248fad09c73SVivien Didelot bus->name = "mv88e6xxx SMI"; 2249fad09c73SVivien Didelot snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++); 2250fad09c73SVivien Didelot } 2251fad09c73SVivien Didelot 2252fad09c73SVivien Didelot bus->read = mv88e6xxx_mdio_read; 2253fad09c73SVivien Didelot bus->write = mv88e6xxx_mdio_write; 2254fad09c73SVivien Didelot bus->parent = chip->dev; 2255fad09c73SVivien Didelot 2256a3c53be5SAndrew Lunn if (np) 2257a3c53be5SAndrew Lunn err = of_mdiobus_register(bus, np); 2258fad09c73SVivien Didelot else 2259fad09c73SVivien Didelot err = mdiobus_register(bus); 2260fad09c73SVivien Didelot if (err) { 2261fad09c73SVivien Didelot dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err); 2262fad09c73SVivien Didelot return err; 2263fad09c73SVivien Didelot } 2264fad09c73SVivien Didelot 2265a3c53be5SAndrew Lunn if (external) 2266a3c53be5SAndrew Lunn list_add_tail(&mdio_bus->list, &chip->mdios); 2267a3c53be5SAndrew Lunn else 2268a3c53be5SAndrew Lunn list_add(&mdio_bus->list, &chip->mdios); 2269a3c53be5SAndrew Lunn 2270a3c53be5SAndrew Lunn return 0; 2271a3c53be5SAndrew Lunn } 2272a3c53be5SAndrew Lunn 2273a3c53be5SAndrew Lunn static const struct of_device_id mv88e6xxx_mdio_external_match[] = { 2274a3c53be5SAndrew Lunn { .compatible = "marvell,mv88e6xxx-mdio-external", 2275a3c53be5SAndrew Lunn .data = (void *)true }, 2276a3c53be5SAndrew Lunn { }, 2277a3c53be5SAndrew Lunn }; 2278a3c53be5SAndrew Lunn 2279a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, 2280a3c53be5SAndrew Lunn struct device_node *np) 2281a3c53be5SAndrew Lunn { 2282a3c53be5SAndrew Lunn const struct of_device_id *match; 2283a3c53be5SAndrew Lunn struct device_node *child; 2284a3c53be5SAndrew Lunn int err; 2285a3c53be5SAndrew Lunn 2286a3c53be5SAndrew Lunn /* Always register one mdio bus for the internal/default mdio 2287a3c53be5SAndrew Lunn * bus. This maybe represented in the device tree, but is 2288a3c53be5SAndrew Lunn * optional. 2289a3c53be5SAndrew Lunn */ 2290a3c53be5SAndrew Lunn child = of_get_child_by_name(np, "mdio"); 2291a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, false); 2292a3c53be5SAndrew Lunn if (err) 2293a3c53be5SAndrew Lunn return err; 2294a3c53be5SAndrew Lunn 2295a3c53be5SAndrew Lunn /* Walk the device tree, and see if there are any other nodes 2296a3c53be5SAndrew Lunn * which say they are compatible with the external mdio 2297a3c53be5SAndrew Lunn * bus. 2298a3c53be5SAndrew Lunn */ 2299a3c53be5SAndrew Lunn for_each_available_child_of_node(np, child) { 2300a3c53be5SAndrew Lunn match = of_match_node(mv88e6xxx_mdio_external_match, child); 2301a3c53be5SAndrew Lunn if (match) { 2302a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, true); 2303a3c53be5SAndrew Lunn if (err) 2304a3c53be5SAndrew Lunn return err; 2305a3c53be5SAndrew Lunn } 2306a3c53be5SAndrew Lunn } 2307a3c53be5SAndrew Lunn 2308a3c53be5SAndrew Lunn return 0; 2309a3c53be5SAndrew Lunn } 2310a3c53be5SAndrew Lunn 2311a3c53be5SAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) 2312fad09c73SVivien Didelot 2313fad09c73SVivien Didelot { 2314a3c53be5SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 2315a3c53be5SAndrew Lunn struct mii_bus *bus; 2316a3c53be5SAndrew Lunn 2317a3c53be5SAndrew Lunn list_for_each_entry(mdio_bus, &chip->mdios, list) { 2318a3c53be5SAndrew Lunn bus = mdio_bus->bus; 2319fad09c73SVivien Didelot 2320fad09c73SVivien Didelot mdiobus_unregister(bus); 2321a3c53be5SAndrew Lunn } 2322fad09c73SVivien Didelot } 2323fad09c73SVivien Didelot 2324855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) 2325855b1932SVivien Didelot { 232604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2327855b1932SVivien Didelot 2328855b1932SVivien Didelot return chip->eeprom_len; 2329855b1932SVivien Didelot } 2330855b1932SVivien Didelot 2331855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds, 2332855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 2333855b1932SVivien Didelot { 233404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2335855b1932SVivien Didelot int err; 2336855b1932SVivien Didelot 2337ee4dc2e7SVivien Didelot if (!chip->info->ops->get_eeprom) 2338ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 2339ee4dc2e7SVivien Didelot 2340855b1932SVivien Didelot mutex_lock(&chip->reg_lock); 2341ee4dc2e7SVivien Didelot err = chip->info->ops->get_eeprom(chip, eeprom, data); 2342855b1932SVivien Didelot mutex_unlock(&chip->reg_lock); 2343855b1932SVivien Didelot 2344855b1932SVivien Didelot if (err) 2345855b1932SVivien Didelot return err; 2346855b1932SVivien Didelot 2347855b1932SVivien Didelot eeprom->magic = 0xc3ec4951; 2348855b1932SVivien Didelot 2349855b1932SVivien Didelot return 0; 2350855b1932SVivien Didelot } 2351855b1932SVivien Didelot 2352855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, 2353855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 2354855b1932SVivien Didelot { 235504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2356855b1932SVivien Didelot int err; 2357855b1932SVivien Didelot 2358ee4dc2e7SVivien Didelot if (!chip->info->ops->set_eeprom) 2359ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 2360ee4dc2e7SVivien Didelot 2361855b1932SVivien Didelot if (eeprom->magic != 0xc3ec4951) 2362855b1932SVivien Didelot return -EINVAL; 2363855b1932SVivien Didelot 2364855b1932SVivien Didelot mutex_lock(&chip->reg_lock); 2365ee4dc2e7SVivien Didelot err = chip->info->ops->set_eeprom(chip, eeprom, data); 2366855b1932SVivien Didelot mutex_unlock(&chip->reg_lock); 2367855b1932SVivien Didelot 2368855b1932SVivien Didelot return err; 2369855b1932SVivien Didelot } 2370855b1932SVivien Didelot 2371b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = { 23724b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6097 */ 2373b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 2374b3469dd8SVivien Didelot .phy_read = mv88e6xxx_phy_ppu_read, 2375b3469dd8SVivien Didelot .phy_write = mv88e6xxx_phy_ppu_write, 237608ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 23777f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 237896a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2379ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 238056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2381601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 238256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2383ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 2384b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 2385c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 23869dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2387a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 2388dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2389dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2390052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 239133641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 239233641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 2393fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 23946e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 2395a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 2396a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 239717e708baSVivien Didelot .reset = mv88e6185_g1_reset, 2398f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 23990ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2400b3469dd8SVivien Didelot }; 2401b3469dd8SVivien Didelot 2402b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = { 24034b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6095 */ 2404b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 2405b3469dd8SVivien Didelot .phy_read = mv88e6xxx_phy_ppu_read, 2406b3469dd8SVivien Didelot .phy_write = mv88e6xxx_phy_ppu_write, 240708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 24087f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 240996a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 241056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 2411601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 2412a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 2413a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 2414dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2415dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2416052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 24176e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 2418a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 2419a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 242017e708baSVivien Didelot .reset = mv88e6185_g1_reset, 2421f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 24220ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 2423b3469dd8SVivien Didelot }; 2424b3469dd8SVivien Didelot 24257d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = { 242615da3cc8SStefan Eichenberger /* MV88E6XXX_FAMILY_6097 */ 24277d381a02SStefan Eichenberger .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 24287d381a02SStefan Eichenberger .phy_read = mv88e6xxx_g2_smi_phy_read, 24297d381a02SStefan Eichenberger .phy_write = mv88e6xxx_g2_smi_phy_write, 24307d381a02SStefan Eichenberger .port_set_link = mv88e6xxx_port_set_link, 24317d381a02SStefan Eichenberger .port_set_duplex = mv88e6xxx_port_set_duplex, 24327d381a02SStefan Eichenberger .port_set_speed = mv88e6185_port_set_speed, 2433ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 243456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2435601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 243656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 24375f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 2438ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 2439b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 2440c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 24419dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 24427d381a02SStefan Eichenberger .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 24437d381a02SStefan Eichenberger .stats_get_sset_count = mv88e6095_stats_get_sset_count, 24447d381a02SStefan Eichenberger .stats_get_strings = mv88e6095_stats_get_strings, 24457d381a02SStefan Eichenberger .stats_get_stats = mv88e6095_stats_get_stats, 244633641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 244733641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 244891eaa475SVolodymyr Bendiuga .watchdog_ops = &mv88e6097_watchdog_ops, 24496e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 245017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2451f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 24520ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 24537d381a02SStefan Eichenberger }; 24547d381a02SStefan Eichenberger 2455b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = { 24564b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 2457b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2458efb3e74dSAndrew Lunn .phy_read = mv88e6165_phy_read, 2459efb3e74dSAndrew Lunn .phy_write = mv88e6165_phy_write, 246008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 24617f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 246296a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 246356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 2464601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 2465c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 24669dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2467a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 2468dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2469dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2470052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 247133641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 247233641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 2473fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 24746e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 247517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2476f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 24770ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2478b3469dd8SVivien Didelot }; 2479b3469dd8SVivien Didelot 2480b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = { 24814b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 2482b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 2483b3469dd8SVivien Didelot .phy_read = mv88e6xxx_phy_ppu_read, 2484b3469dd8SVivien Didelot .phy_write = mv88e6xxx_phy_ppu_write, 248508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 24867f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 248796a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2488ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 248956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2490601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 249156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2492a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 24935f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 2494ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 2495b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 2496a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 2497dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2498dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2499052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 250033641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 250133641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 2502fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 25036e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 2504a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 2505a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 250617e708baSVivien Didelot .reset = mv88e6185_g1_reset, 2507f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 25080ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 2509b3469dd8SVivien Didelot }; 2510b3469dd8SVivien Didelot 2511990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = { 2512990e27b0SVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 2513990e27b0SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 2514990e27b0SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 2515990e27b0SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2516990e27b0SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2517990e27b0SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 2518990e27b0SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 2519990e27b0SVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 2520990e27b0SVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 2521990e27b0SVivien Didelot .port_set_speed = mv88e6390_port_set_speed, 2522990e27b0SVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 2523990e27b0SVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2524990e27b0SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 2525990e27b0SVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 2526990e27b0SVivien Didelot .port_jumbo_config = mv88e6165_port_jumbo_config, 2527990e27b0SVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 2528990e27b0SVivien Didelot .port_pause_config = mv88e6097_port_pause_config, 2529990e27b0SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 2530990e27b0SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2531990e27b0SVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 2532990e27b0SVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2533990e27b0SVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 2534990e27b0SVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 2535990e27b0SVivien Didelot .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, 2536990e27b0SVivien Didelot .g1_set_egress_port = mv88e6390_g1_set_egress_port, 2537990e27b0SVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 2538990e27b0SVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 2539990e27b0SVivien Didelot .reset = mv88e6352_g1_reset, 2540f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 25410ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2542990e27b0SVivien Didelot }; 2543990e27b0SVivien Didelot 2544b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = { 25454b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 2546b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2547efb3e74dSAndrew Lunn .phy_read = mv88e6165_phy_read, 2548efb3e74dSAndrew Lunn .phy_write = mv88e6165_phy_write, 254908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 25507f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 255196a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2552ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 255356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2554601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 255556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 25565f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 2557ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 2558b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 2559c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 25609dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2561a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 2562dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2563dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2564052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 256533641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 256633641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 2567fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 25686e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 256917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2570f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 25710ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2572b3469dd8SVivien Didelot }; 2573b3469dd8SVivien Didelot 2574b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = { 25754b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 2576b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2577efb3e74dSAndrew Lunn .phy_read = mv88e6165_phy_read, 2578efb3e74dSAndrew Lunn .phy_write = mv88e6165_phy_write, 257908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 25807f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 258196a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2582c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 25839dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2584a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 2585dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2586dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2587052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 258833641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 258933641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 2590fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 25916e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 259217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2593f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 25940ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2595b3469dd8SVivien Didelot }; 2596b3469dd8SVivien Didelot 2597b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = { 25984b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 2599b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2600b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2601b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 260208ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 26037f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 260494d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 260596a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2606ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 260756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2608601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 260956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 26105f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 2611ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 2612b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 2613c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 26149dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2615a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2616dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2617dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2618052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 261933641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 262033641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 2621fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 26226e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 262317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2624f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 26250ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2626b3469dd8SVivien Didelot }; 2627b3469dd8SVivien Didelot 2628b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = { 26294b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 2630ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 2631ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 2632b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2633b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2634b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 263508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 26367f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 2637a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 263896a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 2639ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 264056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2641601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 264256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 26435f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 2644ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 2645b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 2646c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 26479dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2648a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2649dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2650dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2651052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 265233641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 265333641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 2654fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 26556e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 265617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2657f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 26580ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 26596d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 2660b3469dd8SVivien Didelot }; 2661b3469dd8SVivien Didelot 2662b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = { 26634b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 2664b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2665b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2666b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 266708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 26687f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 266994d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 267096a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2671ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 267256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2673601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 267456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 26755f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 2676ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 2677b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 2678c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 26799dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2680a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2681dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2682dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2683052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 268433641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 268533641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 2686fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 26876e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 268817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2689f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 26900ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2691b3469dd8SVivien Didelot }; 2692b3469dd8SVivien Didelot 2693b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = { 26944b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 2695ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 2696ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 2697b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2698b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2699b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 270008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 27017f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 2702a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 270396a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 2704ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 270556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2706601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 270756995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 27085f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 2709ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 2710b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 2711c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 27129dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2713a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2714dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2715dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2716052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 271733641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 271833641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 2719fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 27206e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 272117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2722f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 27230ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 27246d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 2725b3469dd8SVivien Didelot }; 2726b3469dd8SVivien Didelot 2727b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = { 27284b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 2729b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 2730b3469dd8SVivien Didelot .phy_read = mv88e6xxx_phy_ppu_read, 2731b3469dd8SVivien Didelot .phy_write = mv88e6xxx_phy_ppu_write, 273208ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 27337f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 273496a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 273556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 2736601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 2737ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 2738a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 2739a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 2740dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2741dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2742052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 274333641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 274433641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 2745fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 27466e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 2747a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 2748a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 274917e708baSVivien Didelot .reset = mv88e6185_g1_reset, 2750f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 27510ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 2752b3469dd8SVivien Didelot }; 2753b3469dd8SVivien Didelot 27541a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = { 27554b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 275698fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 275798fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 27581a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 27591a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 27601a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 27611a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 27621a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 27631a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 27641a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 2765ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 276656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2767601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 276856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 27693ce0e65eSAndrew Lunn .port_pause_config = mv88e6390_port_pause_config, 2770c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 27719dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 277279523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 2773de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 2774dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2775dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 2776e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 277733641994SAndrew Lunn .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, 277833641994SAndrew Lunn .g1_set_egress_port = mv88e6390_g1_set_egress_port, 277961303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 27806e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 278117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2782931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 2783931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 27846335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 27851a3b39ecSAndrew Lunn }; 27861a3b39ecSAndrew Lunn 27871a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = { 27884b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 278998fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 279098fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 27911a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 27921a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 27931a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 27941a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 27951a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 27961a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 27971a3b39ecSAndrew Lunn .port_set_speed = mv88e6390x_port_set_speed, 2798ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 279956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2800601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 280156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 28023ce0e65eSAndrew Lunn .port_pause_config = mv88e6390_port_pause_config, 2803c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 28049dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 280579523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 2806de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 2807dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2808dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 2809e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 281033641994SAndrew Lunn .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, 281133641994SAndrew Lunn .g1_set_egress_port = mv88e6390_g1_set_egress_port, 281261303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 28136e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 281417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2815931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 2816931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 28176335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 28181a3b39ecSAndrew Lunn }; 28191a3b39ecSAndrew Lunn 28201a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = { 28214b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 282298fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 282398fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 28241a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 28251a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 28261a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 28271a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 28281a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 28291a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 28301a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 2831ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 283256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2833601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 283456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 28353ce0e65eSAndrew Lunn .port_pause_config = mv88e6390_port_pause_config, 2836c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 28379dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 283879523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 2839de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 2840dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2841dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 2842e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 284333641994SAndrew Lunn .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, 284433641994SAndrew Lunn .g1_set_egress_port = mv88e6390_g1_set_egress_port, 284561303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 28466e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 284717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2848931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 2849931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 28506335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 28511a3b39ecSAndrew Lunn }; 28521a3b39ecSAndrew Lunn 2853b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = { 28544b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 2855ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 2856ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 2857b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2858b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2859b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 286008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 28617f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 2862a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 286396a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 2864ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 286556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2866601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 286756995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 28685f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 2869ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 2870b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 2871c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 28729dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2873a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2874dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2875dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2876052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 287733641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 287833641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 2879fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 28806e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 288117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2882f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 28830ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 28846d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 2885b3469dd8SVivien Didelot }; 2886b3469dd8SVivien Didelot 28871a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = { 28884b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 288998fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 289098fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 28911a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 28921a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 28931a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 28941a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 28951a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 28961a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 28971a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 2898ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 289956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2900601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 290156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 29023ce0e65eSAndrew Lunn .port_pause_config = mv88e6390_port_pause_config, 2903f39908d3SAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 2904c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 29059dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 290679523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 2907de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 2908dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2909dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 2910e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 291133641994SAndrew Lunn .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, 291233641994SAndrew Lunn .g1_set_egress_port = mv88e6390_g1_set_egress_port, 291361303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 29146e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 291517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2916931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 2917931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 29186335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 29191a3b39ecSAndrew Lunn }; 29201a3b39ecSAndrew Lunn 2921b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = { 29224b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6320 */ 2923ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 2924ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 2925b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2926b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2927b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 292808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 29297f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 293096a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2931ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 293256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2933601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 293456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 29355f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 2936ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 2937b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 2938c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 29399dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2940a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2941dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2942dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 2943052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 294433641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 294533641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 29466e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 294717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2948f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 29490ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 2950b3469dd8SVivien Didelot }; 2951b3469dd8SVivien Didelot 2952b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = { 29534b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6321 */ 2954ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 2955ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 2956b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2957b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2958b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 295908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 29607f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 296196a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2962ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 296356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2964601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 296556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 29665f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 2967ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 2968b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 2969c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 29709dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2971a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2972dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2973dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 2974052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 297533641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 297633641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 297717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2978f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 29790ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 2980b3469dd8SVivien Didelot }; 2981b3469dd8SVivien Didelot 298216e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = { 298316e329aeSVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 298416e329aeSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 298516e329aeSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 298616e329aeSVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 298716e329aeSVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 298816e329aeSVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 298916e329aeSVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 299016e329aeSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 299116e329aeSVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 299216e329aeSVivien Didelot .port_set_speed = mv88e6390_port_set_speed, 299316e329aeSVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 299416e329aeSVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 299516e329aeSVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 299616e329aeSVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 299716e329aeSVivien Didelot .port_jumbo_config = mv88e6165_port_jumbo_config, 299816e329aeSVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 299916e329aeSVivien Didelot .port_pause_config = mv88e6097_port_pause_config, 300016e329aeSVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 300116e329aeSVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 300216e329aeSVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 300316e329aeSVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 300416e329aeSVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 300516e329aeSVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 300616e329aeSVivien Didelot .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, 300716e329aeSVivien Didelot .g1_set_egress_port = mv88e6390_g1_set_egress_port, 300816e329aeSVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 300916e329aeSVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 301016e329aeSVivien Didelot .reset = mv88e6352_g1_reset, 3011f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 30120ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 301316e329aeSVivien Didelot }; 301416e329aeSVivien Didelot 3015b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = { 30164b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 3017b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3018b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3019b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 302008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 30217f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 302294d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 302396a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3024ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 302556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3026601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 302756995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 30285f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 3029ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 3030b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 3031c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 30329dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 3033a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 3034dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3035dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3036052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 303733641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 303833641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 3039fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 30406e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 304117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3042f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 30430ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3044b3469dd8SVivien Didelot }; 3045b3469dd8SVivien Didelot 3046b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = { 30474b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 3048b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3049b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3050b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 305108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 30527f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 305394d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 305496a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3055ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 305656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3057601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 305856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 30595f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 3060ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 3061b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 3062c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 30639dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 3064a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 3065dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3066dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3067052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 306833641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 306933641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 3070fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 30716e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 307217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3073f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 30740ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3075b3469dd8SVivien Didelot }; 3076b3469dd8SVivien Didelot 3077b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = { 30784b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 3079ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3080ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3081b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3082b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3083b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 308408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 30857f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3086a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 308796a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 3088ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 308956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3090601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 309156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 30925f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 3093ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 3094b35d322aSAndrew Lunn .port_pause_config = mv88e6097_port_pause_config, 3095c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 30969dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 3097a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 3098dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3099dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3100052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 310133641994SAndrew Lunn .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, 310233641994SAndrew Lunn .g1_set_egress_port = mv88e6095_g1_set_egress_port, 3103fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 31046e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 310517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3106f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 31070ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 31086d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 3109b3469dd8SVivien Didelot }; 3110b3469dd8SVivien Didelot 31111a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = { 31124b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 311398fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 311498fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 31151a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 31161a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 31171a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 31181a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 31191a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 31201a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 31211a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 3122ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 312356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3124601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 312556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 31265f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 3127ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 31283ce0e65eSAndrew Lunn .port_pause_config = mv88e6390_port_pause_config, 3129f39908d3SAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 3130c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 31319dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 313279523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3133de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3134dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3135dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3136e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 313733641994SAndrew Lunn .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, 313833641994SAndrew Lunn .g1_set_egress_port = mv88e6390_g1_set_egress_port, 313961303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 31406e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 314117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3142931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3143931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 31446335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 31451a3b39ecSAndrew Lunn }; 31461a3b39ecSAndrew Lunn 31471a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = { 31484b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 314998fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 315098fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 31511a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 31521a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 31531a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 31541a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 31551a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 31561a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 31571a3b39ecSAndrew Lunn .port_set_speed = mv88e6390x_port_set_speed, 3158ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 315956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3160601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 316156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 31625f436666SAndrew Lunn .port_jumbo_config = mv88e6165_port_jumbo_config, 3163ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 31643ce0e65eSAndrew Lunn .port_pause_config = mv88e6390_port_pause_config, 3165c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 31669dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 316779523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3168de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3169dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3170dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3171e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 317233641994SAndrew Lunn .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, 317333641994SAndrew Lunn .g1_set_egress_port = mv88e6390_g1_set_egress_port, 317461303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 31756e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 317617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3177931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3178931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 31796335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 31801a3b39ecSAndrew Lunn }; 31811a3b39ecSAndrew Lunn 3182fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = { 3183fad09c73SVivien Didelot [MV88E6085] = { 3184fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6085, 3185fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6097, 3186fad09c73SVivien Didelot .name = "Marvell 88E6085", 3187fad09c73SVivien Didelot .num_databases = 4096, 3188fad09c73SVivien Didelot .num_ports = 10, 31893cf3c846SVivien Didelot .max_vid = 4095, 3190fad09c73SVivien Didelot .port_base_addr = 0x10, 3191a935c052SVivien Didelot .global1_addr = 0x1b, 3192acddbd21SVivien Didelot .age_time_coeff = 15000, 3193dc30c35bSAndrew Lunn .g1_irqs = 8, 3194e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3195f3645652SVivien Didelot .pvt = true, 3196443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3197fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6097, 3198b3469dd8SVivien Didelot .ops = &mv88e6085_ops, 3199fad09c73SVivien Didelot }, 3200fad09c73SVivien Didelot 3201fad09c73SVivien Didelot [MV88E6095] = { 3202fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6095, 3203fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6095, 3204fad09c73SVivien Didelot .name = "Marvell 88E6095/88E6095F", 3205fad09c73SVivien Didelot .num_databases = 256, 3206fad09c73SVivien Didelot .num_ports = 11, 32073cf3c846SVivien Didelot .max_vid = 4095, 3208fad09c73SVivien Didelot .port_base_addr = 0x10, 3209a935c052SVivien Didelot .global1_addr = 0x1b, 3210acddbd21SVivien Didelot .age_time_coeff = 15000, 3211dc30c35bSAndrew Lunn .g1_irqs = 8, 3212e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3213443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3214fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6095, 3215b3469dd8SVivien Didelot .ops = &mv88e6095_ops, 3216fad09c73SVivien Didelot }, 3217fad09c73SVivien Didelot 32187d381a02SStefan Eichenberger [MV88E6097] = { 32197d381a02SStefan Eichenberger .prod_num = PORT_SWITCH_ID_PROD_NUM_6097, 32207d381a02SStefan Eichenberger .family = MV88E6XXX_FAMILY_6097, 32217d381a02SStefan Eichenberger .name = "Marvell 88E6097/88E6097F", 32227d381a02SStefan Eichenberger .num_databases = 4096, 32237d381a02SStefan Eichenberger .num_ports = 11, 32243cf3c846SVivien Didelot .max_vid = 4095, 32257d381a02SStefan Eichenberger .port_base_addr = 0x10, 32267d381a02SStefan Eichenberger .global1_addr = 0x1b, 32277d381a02SStefan Eichenberger .age_time_coeff = 15000, 3228c534178bSStefan Eichenberger .g1_irqs = 8, 3229e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3230f3645652SVivien Didelot .pvt = true, 32312bfcfcd3SStefan Eichenberger .tag_protocol = DSA_TAG_PROTO_EDSA, 32327d381a02SStefan Eichenberger .flags = MV88E6XXX_FLAGS_FAMILY_6097, 32337d381a02SStefan Eichenberger .ops = &mv88e6097_ops, 32347d381a02SStefan Eichenberger }, 32357d381a02SStefan Eichenberger 3236fad09c73SVivien Didelot [MV88E6123] = { 3237fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6123, 3238fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 3239fad09c73SVivien Didelot .name = "Marvell 88E6123", 3240fad09c73SVivien Didelot .num_databases = 4096, 3241fad09c73SVivien Didelot .num_ports = 3, 32423cf3c846SVivien Didelot .max_vid = 4095, 3243fad09c73SVivien Didelot .port_base_addr = 0x10, 3244a935c052SVivien Didelot .global1_addr = 0x1b, 3245acddbd21SVivien Didelot .age_time_coeff = 15000, 3246dc30c35bSAndrew Lunn .g1_irqs = 9, 3247e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3248f3645652SVivien Didelot .pvt = true, 3249443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3250fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6165, 3251b3469dd8SVivien Didelot .ops = &mv88e6123_ops, 3252fad09c73SVivien Didelot }, 3253fad09c73SVivien Didelot 3254fad09c73SVivien Didelot [MV88E6131] = { 3255fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6131, 3256fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 3257fad09c73SVivien Didelot .name = "Marvell 88E6131", 3258fad09c73SVivien Didelot .num_databases = 256, 3259fad09c73SVivien Didelot .num_ports = 8, 32603cf3c846SVivien Didelot .max_vid = 4095, 3261fad09c73SVivien Didelot .port_base_addr = 0x10, 3262a935c052SVivien Didelot .global1_addr = 0x1b, 3263acddbd21SVivien Didelot .age_time_coeff = 15000, 3264dc30c35bSAndrew Lunn .g1_irqs = 9, 3265e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3266443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3267fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6185, 3268b3469dd8SVivien Didelot .ops = &mv88e6131_ops, 3269fad09c73SVivien Didelot }, 3270fad09c73SVivien Didelot 3271990e27b0SVivien Didelot [MV88E6141] = { 3272990e27b0SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6141, 3273990e27b0SVivien Didelot .family = MV88E6XXX_FAMILY_6341, 3274990e27b0SVivien Didelot .name = "Marvell 88E6341", 3275990e27b0SVivien Didelot .num_databases = 4096, 3276990e27b0SVivien Didelot .num_ports = 6, 32773cf3c846SVivien Didelot .max_vid = 4095, 3278990e27b0SVivien Didelot .port_base_addr = 0x10, 3279990e27b0SVivien Didelot .global1_addr = 0x1b, 3280990e27b0SVivien Didelot .age_time_coeff = 3750, 3281990e27b0SVivien Didelot .atu_move_port_mask = 0x1f, 3282f3645652SVivien Didelot .pvt = true, 3283990e27b0SVivien Didelot .tag_protocol = DSA_TAG_PROTO_EDSA, 3284990e27b0SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6341, 3285990e27b0SVivien Didelot .ops = &mv88e6141_ops, 3286990e27b0SVivien Didelot }, 3287990e27b0SVivien Didelot 3288fad09c73SVivien Didelot [MV88E6161] = { 3289fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6161, 3290fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 3291fad09c73SVivien Didelot .name = "Marvell 88E6161", 3292fad09c73SVivien Didelot .num_databases = 4096, 3293fad09c73SVivien Didelot .num_ports = 6, 32943cf3c846SVivien Didelot .max_vid = 4095, 3295fad09c73SVivien Didelot .port_base_addr = 0x10, 3296a935c052SVivien Didelot .global1_addr = 0x1b, 3297acddbd21SVivien Didelot .age_time_coeff = 15000, 3298dc30c35bSAndrew Lunn .g1_irqs = 9, 3299e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3300f3645652SVivien Didelot .pvt = true, 3301443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3302fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6165, 3303b3469dd8SVivien Didelot .ops = &mv88e6161_ops, 3304fad09c73SVivien Didelot }, 3305fad09c73SVivien Didelot 3306fad09c73SVivien Didelot [MV88E6165] = { 3307fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6165, 3308fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 3309fad09c73SVivien Didelot .name = "Marvell 88E6165", 3310fad09c73SVivien Didelot .num_databases = 4096, 3311fad09c73SVivien Didelot .num_ports = 6, 33123cf3c846SVivien Didelot .max_vid = 4095, 3313fad09c73SVivien Didelot .port_base_addr = 0x10, 3314a935c052SVivien Didelot .global1_addr = 0x1b, 3315acddbd21SVivien Didelot .age_time_coeff = 15000, 3316dc30c35bSAndrew Lunn .g1_irqs = 9, 3317e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3318f3645652SVivien Didelot .pvt = true, 3319443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3320fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6165, 3321b3469dd8SVivien Didelot .ops = &mv88e6165_ops, 3322fad09c73SVivien Didelot }, 3323fad09c73SVivien Didelot 3324fad09c73SVivien Didelot [MV88E6171] = { 3325fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6171, 3326fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 3327fad09c73SVivien Didelot .name = "Marvell 88E6171", 3328fad09c73SVivien Didelot .num_databases = 4096, 3329fad09c73SVivien Didelot .num_ports = 7, 33303cf3c846SVivien Didelot .max_vid = 4095, 3331fad09c73SVivien Didelot .port_base_addr = 0x10, 3332a935c052SVivien Didelot .global1_addr = 0x1b, 3333acddbd21SVivien Didelot .age_time_coeff = 15000, 3334dc30c35bSAndrew Lunn .g1_irqs = 9, 3335e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3336f3645652SVivien Didelot .pvt = true, 3337443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3338fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6351, 3339b3469dd8SVivien Didelot .ops = &mv88e6171_ops, 3340fad09c73SVivien Didelot }, 3341fad09c73SVivien Didelot 3342fad09c73SVivien Didelot [MV88E6172] = { 3343fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6172, 3344fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 3345fad09c73SVivien Didelot .name = "Marvell 88E6172", 3346fad09c73SVivien Didelot .num_databases = 4096, 3347fad09c73SVivien Didelot .num_ports = 7, 33483cf3c846SVivien Didelot .max_vid = 4095, 3349fad09c73SVivien Didelot .port_base_addr = 0x10, 3350a935c052SVivien Didelot .global1_addr = 0x1b, 3351acddbd21SVivien Didelot .age_time_coeff = 15000, 3352dc30c35bSAndrew Lunn .g1_irqs = 9, 3353e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3354f3645652SVivien Didelot .pvt = true, 3355443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3356fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6352, 3357b3469dd8SVivien Didelot .ops = &mv88e6172_ops, 3358fad09c73SVivien Didelot }, 3359fad09c73SVivien Didelot 3360fad09c73SVivien Didelot [MV88E6175] = { 3361fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6175, 3362fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 3363fad09c73SVivien Didelot .name = "Marvell 88E6175", 3364fad09c73SVivien Didelot .num_databases = 4096, 3365fad09c73SVivien Didelot .num_ports = 7, 33663cf3c846SVivien Didelot .max_vid = 4095, 3367fad09c73SVivien Didelot .port_base_addr = 0x10, 3368a935c052SVivien Didelot .global1_addr = 0x1b, 3369acddbd21SVivien Didelot .age_time_coeff = 15000, 3370dc30c35bSAndrew Lunn .g1_irqs = 9, 3371e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3372f3645652SVivien Didelot .pvt = true, 3373443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3374fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6351, 3375b3469dd8SVivien Didelot .ops = &mv88e6175_ops, 3376fad09c73SVivien Didelot }, 3377fad09c73SVivien Didelot 3378fad09c73SVivien Didelot [MV88E6176] = { 3379fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6176, 3380fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 3381fad09c73SVivien Didelot .name = "Marvell 88E6176", 3382fad09c73SVivien Didelot .num_databases = 4096, 3383fad09c73SVivien Didelot .num_ports = 7, 33843cf3c846SVivien Didelot .max_vid = 4095, 3385fad09c73SVivien Didelot .port_base_addr = 0x10, 3386a935c052SVivien Didelot .global1_addr = 0x1b, 3387acddbd21SVivien Didelot .age_time_coeff = 15000, 3388dc30c35bSAndrew Lunn .g1_irqs = 9, 3389e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3390f3645652SVivien Didelot .pvt = true, 3391443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3392fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6352, 3393b3469dd8SVivien Didelot .ops = &mv88e6176_ops, 3394fad09c73SVivien Didelot }, 3395fad09c73SVivien Didelot 3396fad09c73SVivien Didelot [MV88E6185] = { 3397fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6185, 3398fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 3399fad09c73SVivien Didelot .name = "Marvell 88E6185", 3400fad09c73SVivien Didelot .num_databases = 256, 3401fad09c73SVivien Didelot .num_ports = 10, 34023cf3c846SVivien Didelot .max_vid = 4095, 3403fad09c73SVivien Didelot .port_base_addr = 0x10, 3404a935c052SVivien Didelot .global1_addr = 0x1b, 3405acddbd21SVivien Didelot .age_time_coeff = 15000, 3406dc30c35bSAndrew Lunn .g1_irqs = 8, 3407e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3408443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3409fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6185, 3410b3469dd8SVivien Didelot .ops = &mv88e6185_ops, 3411fad09c73SVivien Didelot }, 3412fad09c73SVivien Didelot 34131a3b39ecSAndrew Lunn [MV88E6190] = { 34141a3b39ecSAndrew Lunn .prod_num = PORT_SWITCH_ID_PROD_NUM_6190, 34151a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 34161a3b39ecSAndrew Lunn .name = "Marvell 88E6190", 34171a3b39ecSAndrew Lunn .num_databases = 4096, 34181a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 3419931d1822SVivien Didelot .max_vid = 8191, 34201a3b39ecSAndrew Lunn .port_base_addr = 0x0, 34211a3b39ecSAndrew Lunn .global1_addr = 0x1b, 3422443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3423b91e055cSAndrew Lunn .age_time_coeff = 3750, 34241a3b39ecSAndrew Lunn .g1_irqs = 9, 3425f3645652SVivien Didelot .pvt = true, 3426e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 34271a3b39ecSAndrew Lunn .flags = MV88E6XXX_FLAGS_FAMILY_6390, 34281a3b39ecSAndrew Lunn .ops = &mv88e6190_ops, 34291a3b39ecSAndrew Lunn }, 34301a3b39ecSAndrew Lunn 34311a3b39ecSAndrew Lunn [MV88E6190X] = { 34321a3b39ecSAndrew Lunn .prod_num = PORT_SWITCH_ID_PROD_NUM_6190X, 34331a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 34341a3b39ecSAndrew Lunn .name = "Marvell 88E6190X", 34351a3b39ecSAndrew Lunn .num_databases = 4096, 34361a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 3437931d1822SVivien Didelot .max_vid = 8191, 34381a3b39ecSAndrew Lunn .port_base_addr = 0x0, 34391a3b39ecSAndrew Lunn .global1_addr = 0x1b, 3440b91e055cSAndrew Lunn .age_time_coeff = 3750, 34411a3b39ecSAndrew Lunn .g1_irqs = 9, 3442e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 3443f3645652SVivien Didelot .pvt = true, 3444443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 34451a3b39ecSAndrew Lunn .flags = MV88E6XXX_FLAGS_FAMILY_6390, 34461a3b39ecSAndrew Lunn .ops = &mv88e6190x_ops, 34471a3b39ecSAndrew Lunn }, 34481a3b39ecSAndrew Lunn 34491a3b39ecSAndrew Lunn [MV88E6191] = { 34501a3b39ecSAndrew Lunn .prod_num = PORT_SWITCH_ID_PROD_NUM_6191, 34511a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 34521a3b39ecSAndrew Lunn .name = "Marvell 88E6191", 34531a3b39ecSAndrew Lunn .num_databases = 4096, 34541a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 3455931d1822SVivien Didelot .max_vid = 8191, 34561a3b39ecSAndrew Lunn .port_base_addr = 0x0, 34571a3b39ecSAndrew Lunn .global1_addr = 0x1b, 3458b91e055cSAndrew Lunn .age_time_coeff = 3750, 3459443d5a1bSAndrew Lunn .g1_irqs = 9, 3460e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 3461f3645652SVivien Didelot .pvt = true, 3462443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 34631a3b39ecSAndrew Lunn .flags = MV88E6XXX_FLAGS_FAMILY_6390, 34642cf4cefbSVivien Didelot .ops = &mv88e6191_ops, 34651a3b39ecSAndrew Lunn }, 34661a3b39ecSAndrew Lunn 3467fad09c73SVivien Didelot [MV88E6240] = { 3468fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6240, 3469fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 3470fad09c73SVivien Didelot .name = "Marvell 88E6240", 3471fad09c73SVivien Didelot .num_databases = 4096, 3472fad09c73SVivien Didelot .num_ports = 7, 34733cf3c846SVivien Didelot .max_vid = 4095, 3474fad09c73SVivien Didelot .port_base_addr = 0x10, 3475a935c052SVivien Didelot .global1_addr = 0x1b, 3476acddbd21SVivien Didelot .age_time_coeff = 15000, 3477dc30c35bSAndrew Lunn .g1_irqs = 9, 3478e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3479f3645652SVivien Didelot .pvt = true, 3480443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3481fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6352, 3482b3469dd8SVivien Didelot .ops = &mv88e6240_ops, 3483fad09c73SVivien Didelot }, 3484fad09c73SVivien Didelot 34851a3b39ecSAndrew Lunn [MV88E6290] = { 34861a3b39ecSAndrew Lunn .prod_num = PORT_SWITCH_ID_PROD_NUM_6290, 34871a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 34881a3b39ecSAndrew Lunn .name = "Marvell 88E6290", 34891a3b39ecSAndrew Lunn .num_databases = 4096, 34901a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 3491931d1822SVivien Didelot .max_vid = 8191, 34921a3b39ecSAndrew Lunn .port_base_addr = 0x0, 34931a3b39ecSAndrew Lunn .global1_addr = 0x1b, 3494b91e055cSAndrew Lunn .age_time_coeff = 3750, 34951a3b39ecSAndrew Lunn .g1_irqs = 9, 3496e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 3497f3645652SVivien Didelot .pvt = true, 3498443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 34991a3b39ecSAndrew Lunn .flags = MV88E6XXX_FLAGS_FAMILY_6390, 35001a3b39ecSAndrew Lunn .ops = &mv88e6290_ops, 35011a3b39ecSAndrew Lunn }, 35021a3b39ecSAndrew Lunn 3503fad09c73SVivien Didelot [MV88E6320] = { 3504fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6320, 3505fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 3506fad09c73SVivien Didelot .name = "Marvell 88E6320", 3507fad09c73SVivien Didelot .num_databases = 4096, 3508fad09c73SVivien Didelot .num_ports = 7, 35093cf3c846SVivien Didelot .max_vid = 4095, 3510fad09c73SVivien Didelot .port_base_addr = 0x10, 3511a935c052SVivien Didelot .global1_addr = 0x1b, 3512acddbd21SVivien Didelot .age_time_coeff = 15000, 3513dc30c35bSAndrew Lunn .g1_irqs = 8, 3514e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3515f3645652SVivien Didelot .pvt = true, 3516443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3517fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6320, 3518b3469dd8SVivien Didelot .ops = &mv88e6320_ops, 3519fad09c73SVivien Didelot }, 3520fad09c73SVivien Didelot 3521fad09c73SVivien Didelot [MV88E6321] = { 3522fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6321, 3523fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 3524fad09c73SVivien Didelot .name = "Marvell 88E6321", 3525fad09c73SVivien Didelot .num_databases = 4096, 3526fad09c73SVivien Didelot .num_ports = 7, 35273cf3c846SVivien Didelot .max_vid = 4095, 3528fad09c73SVivien Didelot .port_base_addr = 0x10, 3529a935c052SVivien Didelot .global1_addr = 0x1b, 3530acddbd21SVivien Didelot .age_time_coeff = 15000, 3531dc30c35bSAndrew Lunn .g1_irqs = 8, 3532e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3533443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3534fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6320, 3535b3469dd8SVivien Didelot .ops = &mv88e6321_ops, 3536fad09c73SVivien Didelot }, 3537fad09c73SVivien Didelot 3538a75961d0SGregory CLEMENT [MV88E6341] = { 3539a75961d0SGregory CLEMENT .prod_num = PORT_SWITCH_ID_PROD_NUM_6341, 3540a75961d0SGregory CLEMENT .family = MV88E6XXX_FAMILY_6341, 3541a75961d0SGregory CLEMENT .name = "Marvell 88E6341", 3542a75961d0SGregory CLEMENT .num_databases = 4096, 3543a75961d0SGregory CLEMENT .num_ports = 6, 35443cf3c846SVivien Didelot .max_vid = 4095, 3545a75961d0SGregory CLEMENT .port_base_addr = 0x10, 3546a75961d0SGregory CLEMENT .global1_addr = 0x1b, 3547a75961d0SGregory CLEMENT .age_time_coeff = 3750, 3548e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 3549f3645652SVivien Didelot .pvt = true, 3550a75961d0SGregory CLEMENT .tag_protocol = DSA_TAG_PROTO_EDSA, 3551a75961d0SGregory CLEMENT .flags = MV88E6XXX_FLAGS_FAMILY_6341, 3552a75961d0SGregory CLEMENT .ops = &mv88e6341_ops, 3553a75961d0SGregory CLEMENT }, 3554a75961d0SGregory CLEMENT 3555fad09c73SVivien Didelot [MV88E6350] = { 3556fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6350, 3557fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 3558fad09c73SVivien Didelot .name = "Marvell 88E6350", 3559fad09c73SVivien Didelot .num_databases = 4096, 3560fad09c73SVivien Didelot .num_ports = 7, 35613cf3c846SVivien Didelot .max_vid = 4095, 3562fad09c73SVivien Didelot .port_base_addr = 0x10, 3563a935c052SVivien Didelot .global1_addr = 0x1b, 3564acddbd21SVivien Didelot .age_time_coeff = 15000, 3565dc30c35bSAndrew Lunn .g1_irqs = 9, 3566e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3567f3645652SVivien Didelot .pvt = true, 3568443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3569fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6351, 3570b3469dd8SVivien Didelot .ops = &mv88e6350_ops, 3571fad09c73SVivien Didelot }, 3572fad09c73SVivien Didelot 3573fad09c73SVivien Didelot [MV88E6351] = { 3574fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6351, 3575fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 3576fad09c73SVivien Didelot .name = "Marvell 88E6351", 3577fad09c73SVivien Didelot .num_databases = 4096, 3578fad09c73SVivien Didelot .num_ports = 7, 35793cf3c846SVivien Didelot .max_vid = 4095, 3580fad09c73SVivien Didelot .port_base_addr = 0x10, 3581a935c052SVivien Didelot .global1_addr = 0x1b, 3582acddbd21SVivien Didelot .age_time_coeff = 15000, 3583dc30c35bSAndrew Lunn .g1_irqs = 9, 3584e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3585f3645652SVivien Didelot .pvt = true, 3586443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3587fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6351, 3588b3469dd8SVivien Didelot .ops = &mv88e6351_ops, 3589fad09c73SVivien Didelot }, 3590fad09c73SVivien Didelot 3591fad09c73SVivien Didelot [MV88E6352] = { 3592fad09c73SVivien Didelot .prod_num = PORT_SWITCH_ID_PROD_NUM_6352, 3593fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 3594fad09c73SVivien Didelot .name = "Marvell 88E6352", 3595fad09c73SVivien Didelot .num_databases = 4096, 3596fad09c73SVivien Didelot .num_ports = 7, 35973cf3c846SVivien Didelot .max_vid = 4095, 3598fad09c73SVivien Didelot .port_base_addr = 0x10, 3599a935c052SVivien Didelot .global1_addr = 0x1b, 3600acddbd21SVivien Didelot .age_time_coeff = 15000, 3601dc30c35bSAndrew Lunn .g1_irqs = 9, 3602e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3603f3645652SVivien Didelot .pvt = true, 3604443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3605fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6352, 3606b3469dd8SVivien Didelot .ops = &mv88e6352_ops, 3607fad09c73SVivien Didelot }, 36081a3b39ecSAndrew Lunn [MV88E6390] = { 36091a3b39ecSAndrew Lunn .prod_num = PORT_SWITCH_ID_PROD_NUM_6390, 36101a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 36111a3b39ecSAndrew Lunn .name = "Marvell 88E6390", 36121a3b39ecSAndrew Lunn .num_databases = 4096, 36131a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 3614931d1822SVivien Didelot .max_vid = 8191, 36151a3b39ecSAndrew Lunn .port_base_addr = 0x0, 36161a3b39ecSAndrew Lunn .global1_addr = 0x1b, 3617b91e055cSAndrew Lunn .age_time_coeff = 3750, 36181a3b39ecSAndrew Lunn .g1_irqs = 9, 3619e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 3620f3645652SVivien Didelot .pvt = true, 3621443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 36221a3b39ecSAndrew Lunn .flags = MV88E6XXX_FLAGS_FAMILY_6390, 36231a3b39ecSAndrew Lunn .ops = &mv88e6390_ops, 36241a3b39ecSAndrew Lunn }, 36251a3b39ecSAndrew Lunn [MV88E6390X] = { 36261a3b39ecSAndrew Lunn .prod_num = PORT_SWITCH_ID_PROD_NUM_6390X, 36271a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 36281a3b39ecSAndrew Lunn .name = "Marvell 88E6390X", 36291a3b39ecSAndrew Lunn .num_databases = 4096, 36301a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 3631931d1822SVivien Didelot .max_vid = 8191, 36321a3b39ecSAndrew Lunn .port_base_addr = 0x0, 36331a3b39ecSAndrew Lunn .global1_addr = 0x1b, 3634b91e055cSAndrew Lunn .age_time_coeff = 3750, 36351a3b39ecSAndrew Lunn .g1_irqs = 9, 3636e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 3637f3645652SVivien Didelot .pvt = true, 3638443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 36391a3b39ecSAndrew Lunn .flags = MV88E6XXX_FLAGS_FAMILY_6390, 36401a3b39ecSAndrew Lunn .ops = &mv88e6390x_ops, 36411a3b39ecSAndrew Lunn }, 3642fad09c73SVivien Didelot }; 3643fad09c73SVivien Didelot 3644fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) 3645fad09c73SVivien Didelot { 3646fad09c73SVivien Didelot int i; 3647fad09c73SVivien Didelot 3648fad09c73SVivien Didelot for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i) 3649fad09c73SVivien Didelot if (mv88e6xxx_table[i].prod_num == prod_num) 3650fad09c73SVivien Didelot return &mv88e6xxx_table[i]; 3651fad09c73SVivien Didelot 3652fad09c73SVivien Didelot return NULL; 3653fad09c73SVivien Didelot } 3654fad09c73SVivien Didelot 3655fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip) 3656fad09c73SVivien Didelot { 3657fad09c73SVivien Didelot const struct mv88e6xxx_info *info; 36588f6345b2SVivien Didelot unsigned int prod_num, rev; 36598f6345b2SVivien Didelot u16 id; 36608f6345b2SVivien Didelot int err; 3661fad09c73SVivien Didelot 36628f6345b2SVivien Didelot mutex_lock(&chip->reg_lock); 36638f6345b2SVivien Didelot err = mv88e6xxx_port_read(chip, 0, PORT_SWITCH_ID, &id); 36648f6345b2SVivien Didelot mutex_unlock(&chip->reg_lock); 36658f6345b2SVivien Didelot if (err) 36668f6345b2SVivien Didelot return err; 3667fad09c73SVivien Didelot 3668fad09c73SVivien Didelot prod_num = (id & 0xfff0) >> 4; 3669fad09c73SVivien Didelot rev = id & 0x000f; 3670fad09c73SVivien Didelot 3671fad09c73SVivien Didelot info = mv88e6xxx_lookup_info(prod_num); 3672fad09c73SVivien Didelot if (!info) 3673fad09c73SVivien Didelot return -ENODEV; 3674fad09c73SVivien Didelot 3675fad09c73SVivien Didelot /* Update the compatible info with the probed one */ 3676fad09c73SVivien Didelot chip->info = info; 3677fad09c73SVivien Didelot 3678ca070c10SVivien Didelot err = mv88e6xxx_g2_require(chip); 3679ca070c10SVivien Didelot if (err) 3680ca070c10SVivien Didelot return err; 3681ca070c10SVivien Didelot 3682fad09c73SVivien Didelot dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n", 3683fad09c73SVivien Didelot chip->info->prod_num, chip->info->name, rev); 3684fad09c73SVivien Didelot 3685fad09c73SVivien Didelot return 0; 3686fad09c73SVivien Didelot } 3687fad09c73SVivien Didelot 3688fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) 3689fad09c73SVivien Didelot { 3690fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 3691fad09c73SVivien Didelot 3692fad09c73SVivien Didelot chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 3693fad09c73SVivien Didelot if (!chip) 3694fad09c73SVivien Didelot return NULL; 3695fad09c73SVivien Didelot 3696fad09c73SVivien Didelot chip->dev = dev; 3697fad09c73SVivien Didelot 3698fad09c73SVivien Didelot mutex_init(&chip->reg_lock); 3699a3c53be5SAndrew Lunn INIT_LIST_HEAD(&chip->mdios); 3700fad09c73SVivien Didelot 3701fad09c73SVivien Didelot return chip; 3702fad09c73SVivien Didelot } 3703fad09c73SVivien Didelot 3704fad09c73SVivien Didelot static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip, 3705fad09c73SVivien Didelot struct mii_bus *bus, int sw_addr) 3706fad09c73SVivien Didelot { 3707fad09c73SVivien Didelot if (sw_addr == 0) 3708fad09c73SVivien Didelot chip->smi_ops = &mv88e6xxx_smi_single_chip_ops; 3709a0ffff24SVivien Didelot else if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_MULTI_CHIP)) 3710fad09c73SVivien Didelot chip->smi_ops = &mv88e6xxx_smi_multi_chip_ops; 3711fad09c73SVivien Didelot else 3712fad09c73SVivien Didelot return -EINVAL; 3713fad09c73SVivien Didelot 3714fad09c73SVivien Didelot chip->bus = bus; 3715fad09c73SVivien Didelot chip->sw_addr = sw_addr; 3716fad09c73SVivien Didelot 3717fad09c73SVivien Didelot return 0; 3718fad09c73SVivien Didelot } 3719fad09c73SVivien Didelot 37207b314362SAndrew Lunn static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds) 37217b314362SAndrew Lunn { 372204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 37232bbb33beSAndrew Lunn 3724443d5a1bSAndrew Lunn return chip->info->tag_protocol; 37257b314362SAndrew Lunn } 37267b314362SAndrew Lunn 3727fad09c73SVivien Didelot static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, 3728fad09c73SVivien Didelot struct device *host_dev, int sw_addr, 3729fad09c73SVivien Didelot void **priv) 3730fad09c73SVivien Didelot { 3731fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 3732fad09c73SVivien Didelot struct mii_bus *bus; 3733fad09c73SVivien Didelot int err; 3734fad09c73SVivien Didelot 3735fad09c73SVivien Didelot bus = dsa_host_dev_to_mii_bus(host_dev); 3736fad09c73SVivien Didelot if (!bus) 3737fad09c73SVivien Didelot return NULL; 3738fad09c73SVivien Didelot 3739fad09c73SVivien Didelot chip = mv88e6xxx_alloc_chip(dsa_dev); 3740fad09c73SVivien Didelot if (!chip) 3741fad09c73SVivien Didelot return NULL; 3742fad09c73SVivien Didelot 3743fad09c73SVivien Didelot /* Legacy SMI probing will only support chips similar to 88E6085 */ 3744fad09c73SVivien Didelot chip->info = &mv88e6xxx_table[MV88E6085]; 3745fad09c73SVivien Didelot 3746fad09c73SVivien Didelot err = mv88e6xxx_smi_init(chip, bus, sw_addr); 3747fad09c73SVivien Didelot if (err) 3748fad09c73SVivien Didelot goto free; 3749fad09c73SVivien Didelot 3750fad09c73SVivien Didelot err = mv88e6xxx_detect(chip); 3751fad09c73SVivien Didelot if (err) 3752fad09c73SVivien Didelot goto free; 3753fad09c73SVivien Didelot 3754dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 3755dc30c35bSAndrew Lunn err = mv88e6xxx_switch_reset(chip); 3756dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 3757dc30c35bSAndrew Lunn if (err) 3758dc30c35bSAndrew Lunn goto free; 3759dc30c35bSAndrew Lunn 3760e57e5e77SVivien Didelot mv88e6xxx_phy_init(chip); 3761e57e5e77SVivien Didelot 3762a3c53be5SAndrew Lunn err = mv88e6xxx_mdios_register(chip, NULL); 3763fad09c73SVivien Didelot if (err) 3764fad09c73SVivien Didelot goto free; 3765fad09c73SVivien Didelot 3766fad09c73SVivien Didelot *priv = chip; 3767fad09c73SVivien Didelot 3768fad09c73SVivien Didelot return chip->info->name; 3769fad09c73SVivien Didelot free: 3770fad09c73SVivien Didelot devm_kfree(dsa_dev, chip); 3771fad09c73SVivien Didelot 3772fad09c73SVivien Didelot return NULL; 3773fad09c73SVivien Didelot } 3774fad09c73SVivien Didelot 37757df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port, 37767df8fbddSVivien Didelot const struct switchdev_obj_port_mdb *mdb, 37777df8fbddSVivien Didelot struct switchdev_trans *trans) 37787df8fbddSVivien Didelot { 37797df8fbddSVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 37807df8fbddSVivien Didelot * so skip the prepare phase. 37817df8fbddSVivien Didelot */ 37827df8fbddSVivien Didelot 37837df8fbddSVivien Didelot return 0; 37847df8fbddSVivien Didelot } 37857df8fbddSVivien Didelot 37867df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port, 37877df8fbddSVivien Didelot const struct switchdev_obj_port_mdb *mdb, 37887df8fbddSVivien Didelot struct switchdev_trans *trans) 37897df8fbddSVivien Didelot { 379004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 37917df8fbddSVivien Didelot 37927df8fbddSVivien Didelot mutex_lock(&chip->reg_lock); 37937df8fbddSVivien Didelot if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 37947df8fbddSVivien Didelot GLOBAL_ATU_DATA_STATE_MC_STATIC)) 37957df8fbddSVivien Didelot netdev_err(ds->ports[port].netdev, "failed to load multicast MAC address\n"); 37967df8fbddSVivien Didelot mutex_unlock(&chip->reg_lock); 37977df8fbddSVivien Didelot } 37987df8fbddSVivien Didelot 37997df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, 38007df8fbddSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 38017df8fbddSVivien Didelot { 380204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 38037df8fbddSVivien Didelot int err; 38047df8fbddSVivien Didelot 38057df8fbddSVivien Didelot mutex_lock(&chip->reg_lock); 38067df8fbddSVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 38077df8fbddSVivien Didelot GLOBAL_ATU_DATA_STATE_UNUSED); 38087df8fbddSVivien Didelot mutex_unlock(&chip->reg_lock); 38097df8fbddSVivien Didelot 38107df8fbddSVivien Didelot return err; 38117df8fbddSVivien Didelot } 38127df8fbddSVivien Didelot 38137df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_dump(struct dsa_switch *ds, int port, 38147df8fbddSVivien Didelot struct switchdev_obj_port_mdb *mdb, 3815438ff537SVivien Didelot switchdev_obj_dump_cb_t *cb) 38167df8fbddSVivien Didelot { 381704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 38187df8fbddSVivien Didelot int err; 38197df8fbddSVivien Didelot 38207df8fbddSVivien Didelot mutex_lock(&chip->reg_lock); 38217df8fbddSVivien Didelot err = mv88e6xxx_port_db_dump(chip, port, &mdb->obj, cb); 38227df8fbddSVivien Didelot mutex_unlock(&chip->reg_lock); 38237df8fbddSVivien Didelot 38247df8fbddSVivien Didelot return err; 38257df8fbddSVivien Didelot } 38267df8fbddSVivien Didelot 3827a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = { 3828fad09c73SVivien Didelot .probe = mv88e6xxx_drv_probe, 38297b314362SAndrew Lunn .get_tag_protocol = mv88e6xxx_get_tag_protocol, 3830fad09c73SVivien Didelot .setup = mv88e6xxx_setup, 3831fad09c73SVivien Didelot .set_addr = mv88e6xxx_set_addr, 3832fad09c73SVivien Didelot .adjust_link = mv88e6xxx_adjust_link, 3833fad09c73SVivien Didelot .get_strings = mv88e6xxx_get_strings, 3834fad09c73SVivien Didelot .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, 3835fad09c73SVivien Didelot .get_sset_count = mv88e6xxx_get_sset_count, 383604aca993SAndrew Lunn .port_enable = mv88e6xxx_port_enable, 383704aca993SAndrew Lunn .port_disable = mv88e6xxx_port_disable, 3838fad09c73SVivien Didelot .set_eee = mv88e6xxx_set_eee, 3839fad09c73SVivien Didelot .get_eee = mv88e6xxx_get_eee, 3840fad09c73SVivien Didelot .get_eeprom_len = mv88e6xxx_get_eeprom_len, 3841fad09c73SVivien Didelot .get_eeprom = mv88e6xxx_get_eeprom, 3842fad09c73SVivien Didelot .set_eeprom = mv88e6xxx_set_eeprom, 3843fad09c73SVivien Didelot .get_regs_len = mv88e6xxx_get_regs_len, 3844fad09c73SVivien Didelot .get_regs = mv88e6xxx_get_regs, 38452cfcd964SVivien Didelot .set_ageing_time = mv88e6xxx_set_ageing_time, 3846fad09c73SVivien Didelot .port_bridge_join = mv88e6xxx_port_bridge_join, 3847fad09c73SVivien Didelot .port_bridge_leave = mv88e6xxx_port_bridge_leave, 3848fad09c73SVivien Didelot .port_stp_state_set = mv88e6xxx_port_stp_state_set, 3849749efcb8SVivien Didelot .port_fast_age = mv88e6xxx_port_fast_age, 3850fad09c73SVivien Didelot .port_vlan_filtering = mv88e6xxx_port_vlan_filtering, 3851fad09c73SVivien Didelot .port_vlan_prepare = mv88e6xxx_port_vlan_prepare, 3852fad09c73SVivien Didelot .port_vlan_add = mv88e6xxx_port_vlan_add, 3853fad09c73SVivien Didelot .port_vlan_del = mv88e6xxx_port_vlan_del, 3854fad09c73SVivien Didelot .port_vlan_dump = mv88e6xxx_port_vlan_dump, 3855fad09c73SVivien Didelot .port_fdb_prepare = mv88e6xxx_port_fdb_prepare, 3856fad09c73SVivien Didelot .port_fdb_add = mv88e6xxx_port_fdb_add, 3857fad09c73SVivien Didelot .port_fdb_del = mv88e6xxx_port_fdb_del, 3858fad09c73SVivien Didelot .port_fdb_dump = mv88e6xxx_port_fdb_dump, 38597df8fbddSVivien Didelot .port_mdb_prepare = mv88e6xxx_port_mdb_prepare, 38607df8fbddSVivien Didelot .port_mdb_add = mv88e6xxx_port_mdb_add, 38617df8fbddSVivien Didelot .port_mdb_del = mv88e6xxx_port_mdb_del, 38627df8fbddSVivien Didelot .port_mdb_dump = mv88e6xxx_port_mdb_dump, 3863aec5ac88SVivien Didelot .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join, 3864aec5ac88SVivien Didelot .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave, 3865fad09c73SVivien Didelot }; 3866fad09c73SVivien Didelot 3867ab3d408dSFlorian Fainelli static struct dsa_switch_driver mv88e6xxx_switch_drv = { 3868ab3d408dSFlorian Fainelli .ops = &mv88e6xxx_switch_ops, 3869ab3d408dSFlorian Fainelli }; 3870ab3d408dSFlorian Fainelli 387155ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) 3872fad09c73SVivien Didelot { 3873fad09c73SVivien Didelot struct device *dev = chip->dev; 3874fad09c73SVivien Didelot struct dsa_switch *ds; 3875fad09c73SVivien Didelot 387673b1204dSVivien Didelot ds = dsa_switch_alloc(dev, mv88e6xxx_num_ports(chip)); 3877fad09c73SVivien Didelot if (!ds) 3878fad09c73SVivien Didelot return -ENOMEM; 3879fad09c73SVivien Didelot 3880fad09c73SVivien Didelot ds->priv = chip; 38819d490b4eSVivien Didelot ds->ops = &mv88e6xxx_switch_ops; 38829ff74f24SVivien Didelot ds->ageing_time_min = chip->info->age_time_coeff; 38839ff74f24SVivien Didelot ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; 3884fad09c73SVivien Didelot 3885fad09c73SVivien Didelot dev_set_drvdata(dev, ds); 3886fad09c73SVivien Didelot 388755ed0ce0SFlorian Fainelli return dsa_register_switch(ds, dev); 3888fad09c73SVivien Didelot } 3889fad09c73SVivien Didelot 3890fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip) 3891fad09c73SVivien Didelot { 3892fad09c73SVivien Didelot dsa_unregister_switch(chip->ds); 3893fad09c73SVivien Didelot } 3894fad09c73SVivien Didelot 3895fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev) 3896fad09c73SVivien Didelot { 3897fad09c73SVivien Didelot struct device *dev = &mdiodev->dev; 3898fad09c73SVivien Didelot struct device_node *np = dev->of_node; 3899fad09c73SVivien Didelot const struct mv88e6xxx_info *compat_info; 3900fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 3901fad09c73SVivien Didelot u32 eeprom_len; 3902fad09c73SVivien Didelot int err; 3903fad09c73SVivien Didelot 3904fad09c73SVivien Didelot compat_info = of_device_get_match_data(dev); 3905fad09c73SVivien Didelot if (!compat_info) 3906fad09c73SVivien Didelot return -EINVAL; 3907fad09c73SVivien Didelot 3908fad09c73SVivien Didelot chip = mv88e6xxx_alloc_chip(dev); 3909fad09c73SVivien Didelot if (!chip) 3910fad09c73SVivien Didelot return -ENOMEM; 3911fad09c73SVivien Didelot 3912fad09c73SVivien Didelot chip->info = compat_info; 3913fad09c73SVivien Didelot 3914fad09c73SVivien Didelot err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr); 3915fad09c73SVivien Didelot if (err) 3916fad09c73SVivien Didelot return err; 3917fad09c73SVivien Didelot 3918b4308f04SAndrew Lunn chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 3919b4308f04SAndrew Lunn if (IS_ERR(chip->reset)) 3920b4308f04SAndrew Lunn return PTR_ERR(chip->reset); 3921b4308f04SAndrew Lunn 3922fad09c73SVivien Didelot err = mv88e6xxx_detect(chip); 3923fad09c73SVivien Didelot if (err) 3924fad09c73SVivien Didelot return err; 3925fad09c73SVivien Didelot 3926e57e5e77SVivien Didelot mv88e6xxx_phy_init(chip); 3927e57e5e77SVivien Didelot 3928ee4dc2e7SVivien Didelot if (chip->info->ops->get_eeprom && 3929fad09c73SVivien Didelot !of_property_read_u32(np, "eeprom-length", &eeprom_len)) 3930fad09c73SVivien Didelot chip->eeprom_len = eeprom_len; 3931fad09c73SVivien Didelot 3932dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 3933dc30c35bSAndrew Lunn err = mv88e6xxx_switch_reset(chip); 3934dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 3935fad09c73SVivien Didelot if (err) 3936dc30c35bSAndrew Lunn goto out; 3937fad09c73SVivien Didelot 3938dc30c35bSAndrew Lunn chip->irq = of_irq_get(np, 0); 3939dc30c35bSAndrew Lunn if (chip->irq == -EPROBE_DEFER) { 3940dc30c35bSAndrew Lunn err = chip->irq; 3941dc30c35bSAndrew Lunn goto out; 3942fad09c73SVivien Didelot } 3943fad09c73SVivien Didelot 3944dc30c35bSAndrew Lunn if (chip->irq > 0) { 3945dc30c35bSAndrew Lunn /* Has to be performed before the MDIO bus is created, 3946dc30c35bSAndrew Lunn * because the PHYs will link there interrupts to these 3947dc30c35bSAndrew Lunn * interrupt controllers 3948dc30c35bSAndrew Lunn */ 3949dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 3950dc30c35bSAndrew Lunn err = mv88e6xxx_g1_irq_setup(chip); 3951dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 3952dc30c35bSAndrew Lunn 3953dc30c35bSAndrew Lunn if (err) 3954dc30c35bSAndrew Lunn goto out; 3955dc30c35bSAndrew Lunn 3956dc30c35bSAndrew Lunn if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT)) { 3957dc30c35bSAndrew Lunn err = mv88e6xxx_g2_irq_setup(chip); 3958dc30c35bSAndrew Lunn if (err) 3959dc30c35bSAndrew Lunn goto out_g1_irq; 3960dc30c35bSAndrew Lunn } 3961dc30c35bSAndrew Lunn } 3962dc30c35bSAndrew Lunn 3963a3c53be5SAndrew Lunn err = mv88e6xxx_mdios_register(chip, np); 3964dc30c35bSAndrew Lunn if (err) 3965dc30c35bSAndrew Lunn goto out_g2_irq; 3966dc30c35bSAndrew Lunn 396755ed0ce0SFlorian Fainelli err = mv88e6xxx_register_switch(chip); 3968dc30c35bSAndrew Lunn if (err) 3969dc30c35bSAndrew Lunn goto out_mdio; 3970dc30c35bSAndrew Lunn 3971fad09c73SVivien Didelot return 0; 3972dc30c35bSAndrew Lunn 3973dc30c35bSAndrew Lunn out_mdio: 3974a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 3975dc30c35bSAndrew Lunn out_g2_irq: 397646712644SAndrew Lunn if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT) && chip->irq > 0) 3977dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 3978dc30c35bSAndrew Lunn out_g1_irq: 397961f7c3f8SAndrew Lunn if (chip->irq > 0) { 398061f7c3f8SAndrew Lunn mutex_lock(&chip->reg_lock); 3981dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 398261f7c3f8SAndrew Lunn mutex_unlock(&chip->reg_lock); 398361f7c3f8SAndrew Lunn } 3984dc30c35bSAndrew Lunn out: 3985dc30c35bSAndrew Lunn return err; 3986fad09c73SVivien Didelot } 3987fad09c73SVivien Didelot 3988fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev) 3989fad09c73SVivien Didelot { 3990fad09c73SVivien Didelot struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 399104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3992fad09c73SVivien Didelot 3993930188ceSAndrew Lunn mv88e6xxx_phy_destroy(chip); 3994fad09c73SVivien Didelot mv88e6xxx_unregister_switch(chip); 3995a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 3996dc30c35bSAndrew Lunn 399746712644SAndrew Lunn if (chip->irq > 0) { 3998dc30c35bSAndrew Lunn if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT)) 3999dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 4000dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 4001fad09c73SVivien Didelot } 400246712644SAndrew Lunn } 4003fad09c73SVivien Didelot 4004fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = { 4005fad09c73SVivien Didelot { 4006fad09c73SVivien Didelot .compatible = "marvell,mv88e6085", 4007fad09c73SVivien Didelot .data = &mv88e6xxx_table[MV88E6085], 4008fad09c73SVivien Didelot }, 40091a3b39ecSAndrew Lunn { 40101a3b39ecSAndrew Lunn .compatible = "marvell,mv88e6190", 40111a3b39ecSAndrew Lunn .data = &mv88e6xxx_table[MV88E6190], 40121a3b39ecSAndrew Lunn }, 4013fad09c73SVivien Didelot { /* sentinel */ }, 4014fad09c73SVivien Didelot }; 4015fad09c73SVivien Didelot 4016fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match); 4017fad09c73SVivien Didelot 4018fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = { 4019fad09c73SVivien Didelot .probe = mv88e6xxx_probe, 4020fad09c73SVivien Didelot .remove = mv88e6xxx_remove, 4021fad09c73SVivien Didelot .mdiodrv.driver = { 4022fad09c73SVivien Didelot .name = "mv88e6085", 4023fad09c73SVivien Didelot .of_match_table = mv88e6xxx_of_match, 4024fad09c73SVivien Didelot }, 4025fad09c73SVivien Didelot }; 4026fad09c73SVivien Didelot 4027fad09c73SVivien Didelot static int __init mv88e6xxx_init(void) 4028fad09c73SVivien Didelot { 4029ab3d408dSFlorian Fainelli register_switch_driver(&mv88e6xxx_switch_drv); 4030fad09c73SVivien Didelot return mdio_driver_register(&mv88e6xxx_driver); 4031fad09c73SVivien Didelot } 4032fad09c73SVivien Didelot module_init(mv88e6xxx_init); 4033fad09c73SVivien Didelot 4034fad09c73SVivien Didelot static void __exit mv88e6xxx_cleanup(void) 4035fad09c73SVivien Didelot { 4036fad09c73SVivien Didelot mdio_driver_unregister(&mv88e6xxx_driver); 4037ab3d408dSFlorian Fainelli unregister_switch_driver(&mv88e6xxx_switch_drv); 4038fad09c73SVivien Didelot } 4039fad09c73SVivien Didelot module_exit(mv88e6xxx_cleanup); 4040fad09c73SVivien Didelot 4041fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); 4042fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips"); 4043fad09c73SVivien Didelot MODULE_LICENSE("GPL"); 4044