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 364d5f2ba7SVivien Didelot #include "chip.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)) 492774439e5SVivien Didelot dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port); 493d78343d2SVivien Didelot 494d78343d2SVivien Didelot return err; 495d78343d2SVivien Didelot } 496d78343d2SVivien Didelot 497fad09c73SVivien Didelot /* We expect the switch to perform auto negotiation if there is a real 498fad09c73SVivien Didelot * phy. However, in the case of a fixed link phy, we force the port 499fad09c73SVivien Didelot * settings from the fixed link settings. 500fad09c73SVivien Didelot */ 501fad09c73SVivien Didelot static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, 502fad09c73SVivien Didelot struct phy_device *phydev) 503fad09c73SVivien Didelot { 50404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 5050e7b9925SAndrew Lunn int err; 506fad09c73SVivien Didelot 507fad09c73SVivien Didelot if (!phy_is_pseudo_fixed_link(phydev)) 508fad09c73SVivien Didelot return; 509fad09c73SVivien Didelot 510fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 511d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed, 512d78343d2SVivien Didelot phydev->duplex, phydev->interface); 513fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 514d78343d2SVivien Didelot 515d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 516774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to configure MAC\n", port); 517fad09c73SVivien Didelot } 518fad09c73SVivien Didelot 519a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 520fad09c73SVivien Didelot { 521a605a0feSAndrew Lunn if (!chip->info->ops->stats_snapshot) 522a605a0feSAndrew Lunn return -EOPNOTSUPP; 523fad09c73SVivien Didelot 524a605a0feSAndrew Lunn return chip->info->ops->stats_snapshot(chip, port); 525fad09c73SVivien Didelot } 526fad09c73SVivien Didelot 527fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = { 528dfafe449SAndrew Lunn { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, }, 529dfafe449SAndrew Lunn { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, }, 530dfafe449SAndrew Lunn { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, }, 531dfafe449SAndrew Lunn { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, }, 532dfafe449SAndrew Lunn { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, }, 533dfafe449SAndrew Lunn { "in_pause", 4, 0x16, STATS_TYPE_BANK0, }, 534dfafe449SAndrew Lunn { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, }, 535dfafe449SAndrew Lunn { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, }, 536dfafe449SAndrew Lunn { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, }, 537dfafe449SAndrew Lunn { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, }, 538dfafe449SAndrew Lunn { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, }, 539dfafe449SAndrew Lunn { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, }, 540dfafe449SAndrew Lunn { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, }, 541dfafe449SAndrew Lunn { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, }, 542dfafe449SAndrew Lunn { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, }, 543dfafe449SAndrew Lunn { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, }, 544dfafe449SAndrew Lunn { "out_pause", 4, 0x15, STATS_TYPE_BANK0, }, 545dfafe449SAndrew Lunn { "excessive", 4, 0x11, STATS_TYPE_BANK0, }, 546dfafe449SAndrew Lunn { "collisions", 4, 0x1e, STATS_TYPE_BANK0, }, 547dfafe449SAndrew Lunn { "deferred", 4, 0x05, STATS_TYPE_BANK0, }, 548dfafe449SAndrew Lunn { "single", 4, 0x14, STATS_TYPE_BANK0, }, 549dfafe449SAndrew Lunn { "multiple", 4, 0x17, STATS_TYPE_BANK0, }, 550dfafe449SAndrew Lunn { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, }, 551dfafe449SAndrew Lunn { "late", 4, 0x1f, STATS_TYPE_BANK0, }, 552dfafe449SAndrew Lunn { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, }, 553dfafe449SAndrew Lunn { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, }, 554dfafe449SAndrew Lunn { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, }, 555dfafe449SAndrew Lunn { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, }, 556dfafe449SAndrew Lunn { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, }, 557dfafe449SAndrew Lunn { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, }, 558dfafe449SAndrew Lunn { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, }, 559dfafe449SAndrew Lunn { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, }, 560dfafe449SAndrew Lunn { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, }, 561dfafe449SAndrew Lunn { "in_discards", 4, 0x00, STATS_TYPE_BANK1, }, 562dfafe449SAndrew Lunn { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, }, 563dfafe449SAndrew Lunn { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, }, 564dfafe449SAndrew Lunn { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, }, 565dfafe449SAndrew Lunn { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, }, 566dfafe449SAndrew Lunn { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, }, 567dfafe449SAndrew Lunn { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, }, 568dfafe449SAndrew Lunn { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, }, 569dfafe449SAndrew Lunn { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, }, 570dfafe449SAndrew Lunn { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, }, 571dfafe449SAndrew Lunn { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, }, 572dfafe449SAndrew Lunn { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, }, 573dfafe449SAndrew Lunn { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, }, 574dfafe449SAndrew Lunn { "in_management", 4, 0x0f, STATS_TYPE_BANK1, }, 575dfafe449SAndrew Lunn { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, }, 576dfafe449SAndrew Lunn { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, }, 577dfafe449SAndrew Lunn { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, }, 578dfafe449SAndrew Lunn { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, }, 579dfafe449SAndrew Lunn { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, }, 580dfafe449SAndrew Lunn { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, }, 581dfafe449SAndrew Lunn { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, }, 582dfafe449SAndrew Lunn { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, }, 583dfafe449SAndrew Lunn { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, }, 584dfafe449SAndrew Lunn { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, }, 585dfafe449SAndrew Lunn { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, }, 586dfafe449SAndrew Lunn { "out_management", 4, 0x1f, STATS_TYPE_BANK1, }, 587fad09c73SVivien Didelot }; 588fad09c73SVivien Didelot 589fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, 590fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *s, 591e0d8b615SAndrew Lunn int port, u16 bank1_select, 592e0d8b615SAndrew Lunn u16 histogram) 593fad09c73SVivien Didelot { 594fad09c73SVivien Didelot u32 low; 595fad09c73SVivien Didelot u32 high = 0; 596dfafe449SAndrew Lunn u16 reg = 0; 5970e7b9925SAndrew Lunn int err; 598fad09c73SVivien Didelot u64 value; 599fad09c73SVivien Didelot 600fad09c73SVivien Didelot switch (s->type) { 601dfafe449SAndrew Lunn case STATS_TYPE_PORT: 6020e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg, ®); 6030e7b9925SAndrew Lunn if (err) 604fad09c73SVivien Didelot return UINT64_MAX; 605fad09c73SVivien Didelot 6060e7b9925SAndrew Lunn low = reg; 607fad09c73SVivien Didelot if (s->sizeof_stat == 4) { 6080e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg + 1, ®); 6090e7b9925SAndrew Lunn if (err) 610fad09c73SVivien Didelot return UINT64_MAX; 6110e7b9925SAndrew Lunn high = reg; 612fad09c73SVivien Didelot } 613fad09c73SVivien Didelot break; 614dfafe449SAndrew Lunn case STATS_TYPE_BANK1: 615e0d8b615SAndrew Lunn reg = bank1_select; 616dfafe449SAndrew Lunn /* fall through */ 617dfafe449SAndrew Lunn case STATS_TYPE_BANK0: 618e0d8b615SAndrew Lunn reg |= s->reg | histogram; 6197f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg, &low); 620fad09c73SVivien Didelot if (s->sizeof_stat == 8) 6217f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg + 1, &high); 6229fc3e4dcSGustavo A. R. Silva break; 6239fc3e4dcSGustavo A. R. Silva default: 6249fc3e4dcSGustavo A. R. Silva return UINT64_MAX; 625fad09c73SVivien Didelot } 626fad09c73SVivien Didelot value = (((u64)high) << 16) | low; 627fad09c73SVivien Didelot return value; 628fad09c73SVivien Didelot } 629fad09c73SVivien Didelot 630dfafe449SAndrew Lunn static void mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, 631dfafe449SAndrew Lunn uint8_t *data, int types) 632fad09c73SVivien Didelot { 633fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 634fad09c73SVivien Didelot int i, j; 635fad09c73SVivien Didelot 636fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 637fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 638dfafe449SAndrew Lunn if (stat->type & types) { 639fad09c73SVivien Didelot memcpy(data + j * ETH_GSTRING_LEN, stat->string, 640fad09c73SVivien Didelot ETH_GSTRING_LEN); 641fad09c73SVivien Didelot j++; 642fad09c73SVivien Didelot } 643fad09c73SVivien Didelot } 644fad09c73SVivien Didelot } 645fad09c73SVivien Didelot 646dfafe449SAndrew Lunn static void mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, 647dfafe449SAndrew Lunn uint8_t *data) 648dfafe449SAndrew Lunn { 649dfafe449SAndrew Lunn mv88e6xxx_stats_get_strings(chip, data, 650dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT); 651dfafe449SAndrew Lunn } 652dfafe449SAndrew Lunn 653dfafe449SAndrew Lunn static void mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, 654dfafe449SAndrew Lunn uint8_t *data) 655dfafe449SAndrew Lunn { 656dfafe449SAndrew Lunn mv88e6xxx_stats_get_strings(chip, data, 657dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1); 658dfafe449SAndrew Lunn } 659dfafe449SAndrew Lunn 660dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, 661dfafe449SAndrew Lunn uint8_t *data) 662fad09c73SVivien Didelot { 66304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 664dfafe449SAndrew Lunn 665dfafe449SAndrew Lunn if (chip->info->ops->stats_get_strings) 666dfafe449SAndrew Lunn chip->info->ops->stats_get_strings(chip, data); 667dfafe449SAndrew Lunn } 668dfafe449SAndrew Lunn 669dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip, 670dfafe449SAndrew Lunn int types) 671dfafe449SAndrew Lunn { 672fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 673fad09c73SVivien Didelot int i, j; 674fad09c73SVivien Didelot 675fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 676fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 677dfafe449SAndrew Lunn if (stat->type & types) 678fad09c73SVivien Didelot j++; 679fad09c73SVivien Didelot } 680fad09c73SVivien Didelot return j; 681fad09c73SVivien Didelot } 682fad09c73SVivien Didelot 683dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip) 684dfafe449SAndrew Lunn { 685dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 686dfafe449SAndrew Lunn STATS_TYPE_PORT); 687dfafe449SAndrew Lunn } 688dfafe449SAndrew Lunn 689dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip) 690dfafe449SAndrew Lunn { 691dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 692dfafe449SAndrew Lunn STATS_TYPE_BANK1); 693dfafe449SAndrew Lunn } 694dfafe449SAndrew Lunn 695dfafe449SAndrew Lunn static int mv88e6xxx_get_sset_count(struct dsa_switch *ds) 696dfafe449SAndrew Lunn { 697dfafe449SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 698dfafe449SAndrew Lunn 699dfafe449SAndrew Lunn if (chip->info->ops->stats_get_sset_count) 700dfafe449SAndrew Lunn return chip->info->ops->stats_get_sset_count(chip); 701dfafe449SAndrew Lunn 702dfafe449SAndrew Lunn return 0; 703dfafe449SAndrew Lunn } 704dfafe449SAndrew Lunn 705052f947fSAndrew Lunn static void mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 706e0d8b615SAndrew Lunn uint64_t *data, int types, 707e0d8b615SAndrew Lunn u16 bank1_select, u16 histogram) 708052f947fSAndrew Lunn { 709052f947fSAndrew Lunn struct mv88e6xxx_hw_stat *stat; 710052f947fSAndrew Lunn int i, j; 711052f947fSAndrew Lunn 712052f947fSAndrew Lunn for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 713052f947fSAndrew Lunn stat = &mv88e6xxx_hw_stats[i]; 714052f947fSAndrew Lunn if (stat->type & types) { 715e0d8b615SAndrew Lunn data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 716e0d8b615SAndrew Lunn bank1_select, 717e0d8b615SAndrew Lunn histogram); 718052f947fSAndrew Lunn j++; 719052f947fSAndrew Lunn } 720052f947fSAndrew Lunn } 721052f947fSAndrew Lunn } 722052f947fSAndrew Lunn 723052f947fSAndrew Lunn static void mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 724052f947fSAndrew Lunn uint64_t *data) 725052f947fSAndrew Lunn { 726052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 727e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT, 728e0d8b615SAndrew Lunn 0, GLOBAL_STATS_OP_HIST_RX_TX); 729052f947fSAndrew Lunn } 730052f947fSAndrew Lunn 731052f947fSAndrew Lunn static void mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 732052f947fSAndrew Lunn uint64_t *data) 733052f947fSAndrew Lunn { 734052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 735e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 736e0d8b615SAndrew Lunn GLOBAL_STATS_OP_BANK_1_BIT_9, 737e0d8b615SAndrew Lunn GLOBAL_STATS_OP_HIST_RX_TX); 738e0d8b615SAndrew Lunn } 739e0d8b615SAndrew Lunn 740e0d8b615SAndrew Lunn static void mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 741e0d8b615SAndrew Lunn uint64_t *data) 742e0d8b615SAndrew Lunn { 743e0d8b615SAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 744e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 745e0d8b615SAndrew Lunn GLOBAL_STATS_OP_BANK_1_BIT_10, 0); 746052f947fSAndrew Lunn } 747052f947fSAndrew Lunn 748052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, 749052f947fSAndrew Lunn uint64_t *data) 750052f947fSAndrew Lunn { 751052f947fSAndrew Lunn if (chip->info->ops->stats_get_stats) 752052f947fSAndrew Lunn chip->info->ops->stats_get_stats(chip, port, data); 753052f947fSAndrew Lunn } 754052f947fSAndrew Lunn 755fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, 756fad09c73SVivien Didelot uint64_t *data) 757fad09c73SVivien Didelot { 75804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 759fad09c73SVivien Didelot int ret; 760fad09c73SVivien Didelot 761fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 762fad09c73SVivien Didelot 763a605a0feSAndrew Lunn ret = mv88e6xxx_stats_snapshot(chip, port); 764fad09c73SVivien Didelot if (ret < 0) { 765fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 766fad09c73SVivien Didelot return; 767fad09c73SVivien Didelot } 768052f947fSAndrew Lunn 769052f947fSAndrew Lunn mv88e6xxx_get_stats(chip, port, data); 770fad09c73SVivien Didelot 771fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 772fad09c73SVivien Didelot } 773fad09c73SVivien Didelot 774de227387SAndrew Lunn static int mv88e6xxx_stats_set_histogram(struct mv88e6xxx_chip *chip) 775de227387SAndrew Lunn { 776de227387SAndrew Lunn if (chip->info->ops->stats_set_histogram) 777de227387SAndrew Lunn return chip->info->ops->stats_set_histogram(chip); 778de227387SAndrew Lunn 779de227387SAndrew Lunn return 0; 780de227387SAndrew Lunn } 781de227387SAndrew Lunn 782fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) 783fad09c73SVivien Didelot { 784fad09c73SVivien Didelot return 32 * sizeof(u16); 785fad09c73SVivien Didelot } 786fad09c73SVivien Didelot 787fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, 788fad09c73SVivien Didelot struct ethtool_regs *regs, void *_p) 789fad09c73SVivien Didelot { 79004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 7910e7b9925SAndrew Lunn int err; 7920e7b9925SAndrew Lunn u16 reg; 793fad09c73SVivien Didelot u16 *p = _p; 794fad09c73SVivien Didelot int i; 795fad09c73SVivien Didelot 796fad09c73SVivien Didelot regs->version = 0; 797fad09c73SVivien Didelot 798fad09c73SVivien Didelot memset(p, 0xff, 32 * sizeof(u16)); 799fad09c73SVivien Didelot 800fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 801fad09c73SVivien Didelot 802fad09c73SVivien Didelot for (i = 0; i < 32; i++) { 803fad09c73SVivien Didelot 8040e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, i, ®); 8050e7b9925SAndrew Lunn if (!err) 8060e7b9925SAndrew Lunn p[i] = reg; 807fad09c73SVivien Didelot } 808fad09c73SVivien Didelot 809fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 810fad09c73SVivien Didelot } 811fad09c73SVivien Didelot 812fad09c73SVivien Didelot static int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, 813fad09c73SVivien Didelot struct ethtool_eee *e) 814fad09c73SVivien Didelot { 81504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 8169c93829cSVivien Didelot u16 reg; 8179c93829cSVivien Didelot int err; 818fad09c73SVivien Didelot 819fad09c73SVivien Didelot if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEE)) 820fad09c73SVivien Didelot return -EOPNOTSUPP; 821fad09c73SVivien Didelot 822fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 823fad09c73SVivien Didelot 8249c93829cSVivien Didelot err = mv88e6xxx_phy_read(chip, port, 16, ®); 8259c93829cSVivien Didelot if (err) 826fad09c73SVivien Didelot goto out; 827fad09c73SVivien Didelot 828fad09c73SVivien Didelot e->eee_enabled = !!(reg & 0x0200); 829fad09c73SVivien Didelot e->tx_lpi_enabled = !!(reg & 0x0100); 830fad09c73SVivien Didelot 8315f83dc93SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 8329c93829cSVivien Didelot if (err) 833fad09c73SVivien Didelot goto out; 834fad09c73SVivien Didelot 8355f83dc93SVivien Didelot e->eee_active = !!(reg & MV88E6352_PORT_STS_EEE); 836fad09c73SVivien Didelot out: 837fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 8389c93829cSVivien Didelot 8399c93829cSVivien Didelot return err; 840fad09c73SVivien Didelot } 841fad09c73SVivien Didelot 842fad09c73SVivien Didelot static int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, 843fad09c73SVivien Didelot struct phy_device *phydev, struct ethtool_eee *e) 844fad09c73SVivien Didelot { 84504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 8469c93829cSVivien Didelot u16 reg; 8479c93829cSVivien Didelot int err; 848fad09c73SVivien Didelot 849fad09c73SVivien Didelot if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEE)) 850fad09c73SVivien Didelot return -EOPNOTSUPP; 851fad09c73SVivien Didelot 852fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 853fad09c73SVivien Didelot 8549c93829cSVivien Didelot err = mv88e6xxx_phy_read(chip, port, 16, ®); 8559c93829cSVivien Didelot if (err) 856fad09c73SVivien Didelot goto out; 857fad09c73SVivien Didelot 8589c93829cSVivien Didelot reg &= ~0x0300; 859fad09c73SVivien Didelot if (e->eee_enabled) 860fad09c73SVivien Didelot reg |= 0x0200; 861fad09c73SVivien Didelot if (e->tx_lpi_enabled) 862fad09c73SVivien Didelot reg |= 0x0100; 863fad09c73SVivien Didelot 8649c93829cSVivien Didelot err = mv88e6xxx_phy_write(chip, port, 16, reg); 865fad09c73SVivien Didelot out: 866fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 867fad09c73SVivien Didelot 8689c93829cSVivien Didelot return err; 869fad09c73SVivien Didelot } 870fad09c73SVivien Didelot 871e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port) 872fad09c73SVivien Didelot { 873e5887a2aSVivien Didelot struct dsa_switch *ds = NULL; 874e5887a2aSVivien Didelot struct net_device *br; 875e5887a2aSVivien Didelot u16 pvlan; 876fad09c73SVivien Didelot int i; 877fad09c73SVivien Didelot 878e5887a2aSVivien Didelot if (dev < DSA_MAX_SWITCHES) 879e5887a2aSVivien Didelot ds = chip->ds->dst->ds[dev]; 880fad09c73SVivien Didelot 881e5887a2aSVivien Didelot /* Prevent frames from unknown switch or port */ 882e5887a2aSVivien Didelot if (!ds || port >= ds->num_ports) 883e5887a2aSVivien Didelot return 0; 884e5887a2aSVivien Didelot 885e5887a2aSVivien Didelot /* Frames from DSA links and CPU ports can egress any local port */ 886e5887a2aSVivien Didelot if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) 887e5887a2aSVivien Didelot return mv88e6xxx_port_mask(chip); 888e5887a2aSVivien Didelot 889e5887a2aSVivien Didelot br = ds->ports[port].bridge_dev; 890e5887a2aSVivien Didelot pvlan = 0; 891e5887a2aSVivien Didelot 892e5887a2aSVivien Didelot /* Frames from user ports can egress any local DSA links and CPU ports, 893e5887a2aSVivien Didelot * as well as any local member of their bridge group. 894e5887a2aSVivien Didelot */ 895e5887a2aSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 896e5887a2aSVivien Didelot if (dsa_is_cpu_port(chip->ds, i) || 897e5887a2aSVivien Didelot dsa_is_dsa_port(chip->ds, i) || 898e5887a2aSVivien Didelot (br && chip->ds->ports[i].bridge_dev == br)) 899e5887a2aSVivien Didelot pvlan |= BIT(i); 900e5887a2aSVivien Didelot 901e5887a2aSVivien Didelot return pvlan; 902fad09c73SVivien Didelot } 903e5887a2aSVivien Didelot 904240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port) 905e5887a2aSVivien Didelot { 906e5887a2aSVivien Didelot u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port); 907fad09c73SVivien Didelot 908fad09c73SVivien Didelot /* prevent frames from going back out of the port they came in on */ 909fad09c73SVivien Didelot output_ports &= ~BIT(port); 910fad09c73SVivien Didelot 9115a7921f4SVivien Didelot return mv88e6xxx_port_set_vlan_map(chip, port, output_ports); 912fad09c73SVivien Didelot } 913fad09c73SVivien Didelot 914fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, 915fad09c73SVivien Didelot u8 state) 916fad09c73SVivien Didelot { 91704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 918fad09c73SVivien Didelot int err; 919fad09c73SVivien Didelot 920fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 921f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, port, state); 922fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 923fad09c73SVivien Didelot 924fad09c73SVivien Didelot if (err) 925774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to update state\n", port); 926fad09c73SVivien Didelot } 927fad09c73SVivien Didelot 928a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) 929a2ac29d2SVivien Didelot { 930c3a7d4adSVivien Didelot int err; 931c3a7d4adSVivien Didelot 932daefc943SVivien Didelot err = mv88e6xxx_g1_atu_flush(chip, 0, true); 933daefc943SVivien Didelot if (err) 934daefc943SVivien Didelot return err; 935daefc943SVivien Didelot 936c3a7d4adSVivien Didelot err = mv88e6xxx_g1_atu_set_learn2all(chip, true); 937c3a7d4adSVivien Didelot if (err) 938c3a7d4adSVivien Didelot return err; 939c3a7d4adSVivien Didelot 940a2ac29d2SVivien Didelot return mv88e6xxx_g1_atu_set_age_time(chip, 300000); 941a2ac29d2SVivien Didelot } 942a2ac29d2SVivien Didelot 94317a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port) 94417a1594eSVivien Didelot { 94517a1594eSVivien Didelot u16 pvlan = 0; 94617a1594eSVivien Didelot 94717a1594eSVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 94817a1594eSVivien Didelot return -EOPNOTSUPP; 94917a1594eSVivien Didelot 95017a1594eSVivien Didelot /* Skip the local source device, which uses in-chip port VLAN */ 95117a1594eSVivien Didelot if (dev != chip->ds->index) 952aec5ac88SVivien Didelot pvlan = mv88e6xxx_port_vlan(chip, dev, port); 95317a1594eSVivien Didelot 95417a1594eSVivien Didelot return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan); 95517a1594eSVivien Didelot } 95617a1594eSVivien Didelot 95781228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip) 95881228996SVivien Didelot { 95917a1594eSVivien Didelot int dev, port; 96017a1594eSVivien Didelot int err; 96117a1594eSVivien Didelot 96281228996SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 96381228996SVivien Didelot return 0; 96481228996SVivien Didelot 96581228996SVivien Didelot /* Clear 5 Bit Port for usage with Marvell Link Street devices: 96681228996SVivien Didelot * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev. 96781228996SVivien Didelot */ 96817a1594eSVivien Didelot err = mv88e6xxx_g2_misc_4_bit_port(chip); 96917a1594eSVivien Didelot if (err) 97017a1594eSVivien Didelot return err; 97117a1594eSVivien Didelot 97217a1594eSVivien Didelot for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) { 97317a1594eSVivien Didelot for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) { 97417a1594eSVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 97517a1594eSVivien Didelot if (err) 97617a1594eSVivien Didelot return err; 97717a1594eSVivien Didelot } 97817a1594eSVivien Didelot } 97917a1594eSVivien Didelot 98017a1594eSVivien Didelot return 0; 98181228996SVivien Didelot } 98281228996SVivien Didelot 983749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port) 984749efcb8SVivien Didelot { 985749efcb8SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 986749efcb8SVivien Didelot int err; 987749efcb8SVivien Didelot 988749efcb8SVivien Didelot mutex_lock(&chip->reg_lock); 989e606ca36SVivien Didelot err = mv88e6xxx_g1_atu_remove(chip, 0, port, false); 990749efcb8SVivien Didelot mutex_unlock(&chip->reg_lock); 991749efcb8SVivien Didelot 992749efcb8SVivien Didelot if (err) 993774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to flush ATU\n", port); 994749efcb8SVivien Didelot } 995749efcb8SVivien Didelot 996b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip) 997b486d7c9SVivien Didelot { 998b486d7c9SVivien Didelot if (!chip->info->max_vid) 999b486d7c9SVivien Didelot return 0; 1000b486d7c9SVivien Didelot 1001b486d7c9SVivien Didelot return mv88e6xxx_g1_vtu_flush(chip); 1002b486d7c9SVivien Didelot } 1003b486d7c9SVivien Didelot 1004f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip, 1005f1394b78SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 1006f1394b78SVivien Didelot { 1007f1394b78SVivien Didelot if (!chip->info->ops->vtu_getnext) 1008f1394b78SVivien Didelot return -EOPNOTSUPP; 1009f1394b78SVivien Didelot 1010f1394b78SVivien Didelot return chip->info->ops->vtu_getnext(chip, entry); 1011f1394b78SVivien Didelot } 1012f1394b78SVivien Didelot 10130ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, 10140ad5daf6SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 10150ad5daf6SVivien Didelot { 10160ad5daf6SVivien Didelot if (!chip->info->ops->vtu_loadpurge) 10170ad5daf6SVivien Didelot return -EOPNOTSUPP; 10180ad5daf6SVivien Didelot 10190ad5daf6SVivien Didelot return chip->info->ops->vtu_loadpurge(chip, entry); 10200ad5daf6SVivien Didelot } 10210ad5daf6SVivien Didelot 1022fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, 1023fad09c73SVivien Didelot struct switchdev_obj_port_vlan *vlan, 1024438ff537SVivien Didelot switchdev_obj_dump_cb_t *cb) 1025fad09c73SVivien Didelot { 102604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 10273afb4bdeSVivien Didelot struct mv88e6xxx_vtu_entry next = { 10283afb4bdeSVivien Didelot .vid = chip->info->max_vid, 10293afb4bdeSVivien Didelot }; 1030fad09c73SVivien Didelot u16 pvid; 1031fad09c73SVivien Didelot int err; 1032fad09c73SVivien Didelot 10333cf3c846SVivien Didelot if (!chip->info->max_vid) 1034fad09c73SVivien Didelot return -EOPNOTSUPP; 1035fad09c73SVivien Didelot 1036fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1037fad09c73SVivien Didelot 103877064f37SVivien Didelot err = mv88e6xxx_port_get_pvid(chip, port, &pvid); 1039fad09c73SVivien Didelot if (err) 1040fad09c73SVivien Didelot goto unlock; 1041fad09c73SVivien Didelot 1042fad09c73SVivien Didelot do { 1043f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &next); 1044fad09c73SVivien Didelot if (err) 1045fad09c73SVivien Didelot break; 1046fad09c73SVivien Didelot 1047fad09c73SVivien Didelot if (!next.valid) 1048fad09c73SVivien Didelot break; 1049fad09c73SVivien Didelot 1050bd00e053SVivien Didelot if (next.member[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1051fad09c73SVivien Didelot continue; 1052fad09c73SVivien Didelot 1053fad09c73SVivien Didelot /* reinit and dump this VLAN obj */ 1054fad09c73SVivien Didelot vlan->vid_begin = next.vid; 1055fad09c73SVivien Didelot vlan->vid_end = next.vid; 1056fad09c73SVivien Didelot vlan->flags = 0; 1057fad09c73SVivien Didelot 1058bd00e053SVivien Didelot if (next.member[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED) 1059fad09c73SVivien Didelot vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; 1060fad09c73SVivien Didelot 1061fad09c73SVivien Didelot if (next.vid == pvid) 1062fad09c73SVivien Didelot vlan->flags |= BRIDGE_VLAN_INFO_PVID; 1063fad09c73SVivien Didelot 1064fad09c73SVivien Didelot err = cb(&vlan->obj); 1065fad09c73SVivien Didelot if (err) 1066fad09c73SVivien Didelot break; 10673cf3c846SVivien Didelot } while (next.vid < chip->info->max_vid); 1068fad09c73SVivien Didelot 1069fad09c73SVivien Didelot unlock: 1070fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1071fad09c73SVivien Didelot 1072fad09c73SVivien Didelot return err; 1073fad09c73SVivien Didelot } 1074fad09c73SVivien Didelot 1075d7f435f9SVivien Didelot static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) 1076fad09c73SVivien Didelot { 1077fad09c73SVivien Didelot DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); 10783afb4bdeSVivien Didelot struct mv88e6xxx_vtu_entry vlan = { 10793afb4bdeSVivien Didelot .vid = chip->info->max_vid, 10803afb4bdeSVivien Didelot }; 1081fad09c73SVivien Didelot int i, err; 1082fad09c73SVivien Didelot 1083fad09c73SVivien Didelot bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); 1084fad09c73SVivien Didelot 1085fad09c73SVivien Didelot /* Set every FID bit used by the (un)bridged ports */ 1086370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1087b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, i, fid); 1088fad09c73SVivien Didelot if (err) 1089fad09c73SVivien Didelot return err; 1090fad09c73SVivien Didelot 1091fad09c73SVivien Didelot set_bit(*fid, fid_bitmap); 1092fad09c73SVivien Didelot } 1093fad09c73SVivien Didelot 1094fad09c73SVivien Didelot /* Set every FID bit used by the VLAN entries */ 1095fad09c73SVivien Didelot do { 1096f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1097fad09c73SVivien Didelot if (err) 1098fad09c73SVivien Didelot return err; 1099fad09c73SVivien Didelot 1100fad09c73SVivien Didelot if (!vlan.valid) 1101fad09c73SVivien Didelot break; 1102fad09c73SVivien Didelot 1103fad09c73SVivien Didelot set_bit(vlan.fid, fid_bitmap); 11043cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 1105fad09c73SVivien Didelot 1106fad09c73SVivien Didelot /* The reset value 0x000 is used to indicate that multiple address 1107fad09c73SVivien Didelot * databases are not needed. Return the next positive available. 1108fad09c73SVivien Didelot */ 1109fad09c73SVivien Didelot *fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1); 1110fad09c73SVivien Didelot if (unlikely(*fid >= mv88e6xxx_num_databases(chip))) 1111fad09c73SVivien Didelot return -ENOSPC; 1112fad09c73SVivien Didelot 1113fad09c73SVivien Didelot /* Clear the database */ 1114daefc943SVivien Didelot return mv88e6xxx_g1_atu_flush(chip, *fid, true); 1115fad09c73SVivien Didelot } 1116fad09c73SVivien Didelot 1117567aa59aSVivien Didelot static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid, 1118567aa59aSVivien Didelot struct mv88e6xxx_vtu_entry *entry, bool new) 1119fad09c73SVivien Didelot { 1120fad09c73SVivien Didelot int err; 1121fad09c73SVivien Didelot 1122fad09c73SVivien Didelot if (!vid) 1123fad09c73SVivien Didelot return -EINVAL; 1124fad09c73SVivien Didelot 11253afb4bdeSVivien Didelot entry->vid = vid - 1; 11263afb4bdeSVivien Didelot entry->valid = false; 1127fad09c73SVivien Didelot 1128f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, entry); 1129fad09c73SVivien Didelot if (err) 1130fad09c73SVivien Didelot return err; 1131fad09c73SVivien Didelot 1132567aa59aSVivien Didelot if (entry->vid == vid && entry->valid) 1133567aa59aSVivien Didelot return 0; 1134fad09c73SVivien Didelot 1135567aa59aSVivien Didelot if (new) { 1136567aa59aSVivien Didelot int i; 1137567aa59aSVivien Didelot 1138567aa59aSVivien Didelot /* Initialize a fresh VLAN entry */ 1139567aa59aSVivien Didelot memset(entry, 0, sizeof(*entry)); 1140567aa59aSVivien Didelot entry->valid = true; 1141567aa59aSVivien Didelot entry->vid = vid; 1142567aa59aSVivien Didelot 1143553a768dSVivien Didelot /* Exclude all ports */ 1144567aa59aSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 1145553a768dSVivien Didelot entry->member[i] = 1146553a768dSVivien Didelot GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER; 1147567aa59aSVivien Didelot 1148567aa59aSVivien Didelot return mv88e6xxx_atu_new(chip, &entry->fid); 1149fad09c73SVivien Didelot } 1150fad09c73SVivien Didelot 1151567aa59aSVivien Didelot /* switchdev expects -EOPNOTSUPP to honor software VLANs */ 1152567aa59aSVivien Didelot return -EOPNOTSUPP; 1153fad09c73SVivien Didelot } 1154fad09c73SVivien Didelot 1155fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, 1156fad09c73SVivien Didelot u16 vid_begin, u16 vid_end) 1157fad09c73SVivien Didelot { 115804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 11593afb4bdeSVivien Didelot struct mv88e6xxx_vtu_entry vlan = { 11603afb4bdeSVivien Didelot .vid = vid_begin - 1, 11613afb4bdeSVivien Didelot }; 1162fad09c73SVivien Didelot int i, err; 1163fad09c73SVivien Didelot 1164fad09c73SVivien Didelot if (!vid_begin) 1165fad09c73SVivien Didelot return -EOPNOTSUPP; 1166fad09c73SVivien Didelot 1167fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1168fad09c73SVivien Didelot 1169fad09c73SVivien Didelot do { 1170f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1171fad09c73SVivien Didelot if (err) 1172fad09c73SVivien Didelot goto unlock; 1173fad09c73SVivien Didelot 1174fad09c73SVivien Didelot if (!vlan.valid) 1175fad09c73SVivien Didelot break; 1176fad09c73SVivien Didelot 1177fad09c73SVivien Didelot if (vlan.vid > vid_end) 1178fad09c73SVivien Didelot break; 1179fad09c73SVivien Didelot 1180370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1181fad09c73SVivien Didelot if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i)) 1182fad09c73SVivien Didelot continue; 1183fad09c73SVivien Didelot 118466e2809dSAndrew Lunn if (!ds->ports[port].netdev) 118566e2809dSAndrew Lunn continue; 118666e2809dSAndrew Lunn 1187bd00e053SVivien Didelot if (vlan.member[i] == 1188fad09c73SVivien Didelot GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1189fad09c73SVivien Didelot continue; 1190fad09c73SVivien Didelot 1191fae8a25eSVivien Didelot if (ds->ports[i].bridge_dev == 1192fae8a25eSVivien Didelot ds->ports[port].bridge_dev) 1193fad09c73SVivien Didelot break; /* same bridge, check next VLAN */ 1194fad09c73SVivien Didelot 1195fae8a25eSVivien Didelot if (!ds->ports[i].bridge_dev) 119666e2809dSAndrew Lunn continue; 119766e2809dSAndrew Lunn 1198774439e5SVivien Didelot dev_err(ds->dev, "p%d: hw VLAN %d already used by %s\n", 1199774439e5SVivien Didelot port, vlan.vid, 1200fae8a25eSVivien Didelot netdev_name(ds->ports[i].bridge_dev)); 1201fad09c73SVivien Didelot err = -EOPNOTSUPP; 1202fad09c73SVivien Didelot goto unlock; 1203fad09c73SVivien Didelot } 1204fad09c73SVivien Didelot } while (vlan.vid < vid_end); 1205fad09c73SVivien Didelot 1206fad09c73SVivien Didelot unlock: 1207fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1208fad09c73SVivien Didelot 1209fad09c73SVivien Didelot return err; 1210fad09c73SVivien Didelot } 1211fad09c73SVivien Didelot 1212fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, 1213fad09c73SVivien Didelot bool vlan_filtering) 1214fad09c73SVivien Didelot { 121504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1216385a0995SVivien Didelot u16 mode = vlan_filtering ? PORT_CONTROL_2_8021Q_SECURE : 1217fad09c73SVivien Didelot PORT_CONTROL_2_8021Q_DISABLED; 12180e7b9925SAndrew Lunn int err; 1219fad09c73SVivien Didelot 12203cf3c846SVivien Didelot if (!chip->info->max_vid) 1221fad09c73SVivien Didelot return -EOPNOTSUPP; 1222fad09c73SVivien Didelot 1223fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1224385a0995SVivien Didelot err = mv88e6xxx_port_set_8021q_mode(chip, port, mode); 1225fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1226fad09c73SVivien Didelot 12270e7b9925SAndrew Lunn return err; 1228fad09c73SVivien Didelot } 1229fad09c73SVivien Didelot 1230fad09c73SVivien Didelot static int 1231fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, 1232fad09c73SVivien Didelot const struct switchdev_obj_port_vlan *vlan, 1233fad09c73SVivien Didelot struct switchdev_trans *trans) 1234fad09c73SVivien Didelot { 123504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1236fad09c73SVivien Didelot int err; 1237fad09c73SVivien Didelot 12383cf3c846SVivien Didelot if (!chip->info->max_vid) 1239fad09c73SVivien Didelot return -EOPNOTSUPP; 1240fad09c73SVivien Didelot 1241fad09c73SVivien Didelot /* If the requested port doesn't belong to the same bridge as the VLAN 1242fad09c73SVivien Didelot * members, do not support it (yet) and fallback to software VLAN. 1243fad09c73SVivien Didelot */ 1244fad09c73SVivien Didelot err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin, 1245fad09c73SVivien Didelot vlan->vid_end); 1246fad09c73SVivien Didelot if (err) 1247fad09c73SVivien Didelot return err; 1248fad09c73SVivien Didelot 1249fad09c73SVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 1250fad09c73SVivien Didelot * so skip the prepare phase. 1251fad09c73SVivien Didelot */ 1252fad09c73SVivien Didelot return 0; 1253fad09c73SVivien Didelot } 1254fad09c73SVivien Didelot 1255fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port, 1256c91498e1SVivien Didelot u16 vid, u8 member) 1257fad09c73SVivien Didelot { 1258b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1259fad09c73SVivien Didelot int err; 1260fad09c73SVivien Didelot 1261567aa59aSVivien Didelot err = mv88e6xxx_vtu_get(chip, vid, &vlan, true); 1262fad09c73SVivien Didelot if (err) 1263fad09c73SVivien Didelot return err; 1264fad09c73SVivien Didelot 1265c91498e1SVivien Didelot vlan.member[port] = member; 1266fad09c73SVivien Didelot 12670ad5daf6SVivien Didelot return mv88e6xxx_vtu_loadpurge(chip, &vlan); 1268fad09c73SVivien Didelot } 1269fad09c73SVivien Didelot 1270fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, 1271fad09c73SVivien Didelot const struct switchdev_obj_port_vlan *vlan, 1272fad09c73SVivien Didelot struct switchdev_trans *trans) 1273fad09c73SVivien Didelot { 127404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1275fad09c73SVivien Didelot bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; 1276fad09c73SVivien Didelot bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 1277c91498e1SVivien Didelot u8 member; 1278fad09c73SVivien Didelot u16 vid; 1279fad09c73SVivien Didelot 12803cf3c846SVivien Didelot if (!chip->info->max_vid) 1281fad09c73SVivien Didelot return; 1282fad09c73SVivien Didelot 1283c91498e1SVivien Didelot if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 1284c91498e1SVivien Didelot member = GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED; 1285c91498e1SVivien Didelot else if (untagged) 1286c91498e1SVivien Didelot member = GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED; 1287c91498e1SVivien Didelot else 1288c91498e1SVivien Didelot member = GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED; 1289c91498e1SVivien Didelot 1290fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1291fad09c73SVivien Didelot 1292fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) 1293c91498e1SVivien Didelot if (_mv88e6xxx_port_vlan_add(chip, port, vid, member)) 1294774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port, 1295fad09c73SVivien Didelot vid, untagged ? 'u' : 't'); 1296fad09c73SVivien Didelot 129777064f37SVivien Didelot if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end)) 1298774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to set PVID %d\n", port, 1299fad09c73SVivien Didelot vlan->vid_end); 1300fad09c73SVivien Didelot 1301fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1302fad09c73SVivien Didelot } 1303fad09c73SVivien Didelot 1304fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip, 1305fad09c73SVivien Didelot int port, u16 vid) 1306fad09c73SVivien Didelot { 1307b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1308fad09c73SVivien Didelot int i, err; 1309fad09c73SVivien Didelot 1310567aa59aSVivien Didelot err = mv88e6xxx_vtu_get(chip, vid, &vlan, false); 1311fad09c73SVivien Didelot if (err) 1312fad09c73SVivien Didelot return err; 1313fad09c73SVivien Didelot 1314fad09c73SVivien Didelot /* Tell switchdev if this VLAN is handled in software */ 1315bd00e053SVivien Didelot if (vlan.member[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1316fad09c73SVivien Didelot return -EOPNOTSUPP; 1317fad09c73SVivien Didelot 1318bd00e053SVivien Didelot vlan.member[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER; 1319fad09c73SVivien Didelot 1320fad09c73SVivien Didelot /* keep the VLAN unless all ports are excluded */ 1321fad09c73SVivien Didelot vlan.valid = false; 1322370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1323bd00e053SVivien Didelot if (vlan.member[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) { 1324fad09c73SVivien Didelot vlan.valid = true; 1325fad09c73SVivien Didelot break; 1326fad09c73SVivien Didelot } 1327fad09c73SVivien Didelot } 1328fad09c73SVivien Didelot 13290ad5daf6SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 1330fad09c73SVivien Didelot if (err) 1331fad09c73SVivien Didelot return err; 1332fad09c73SVivien Didelot 1333e606ca36SVivien Didelot return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); 1334fad09c73SVivien Didelot } 1335fad09c73SVivien Didelot 1336fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, 1337fad09c73SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1338fad09c73SVivien Didelot { 133904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1340fad09c73SVivien Didelot u16 pvid, vid; 1341fad09c73SVivien Didelot int err = 0; 1342fad09c73SVivien Didelot 13433cf3c846SVivien Didelot if (!chip->info->max_vid) 1344fad09c73SVivien Didelot return -EOPNOTSUPP; 1345fad09c73SVivien Didelot 1346fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1347fad09c73SVivien Didelot 134877064f37SVivien Didelot err = mv88e6xxx_port_get_pvid(chip, port, &pvid); 1349fad09c73SVivien Didelot if (err) 1350fad09c73SVivien Didelot goto unlock; 1351fad09c73SVivien Didelot 1352fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { 1353fad09c73SVivien Didelot err = _mv88e6xxx_port_vlan_del(chip, port, vid); 1354fad09c73SVivien Didelot if (err) 1355fad09c73SVivien Didelot goto unlock; 1356fad09c73SVivien Didelot 1357fad09c73SVivien Didelot if (vid == pvid) { 135877064f37SVivien Didelot err = mv88e6xxx_port_set_pvid(chip, port, 0); 1359fad09c73SVivien Didelot if (err) 1360fad09c73SVivien Didelot goto unlock; 1361fad09c73SVivien Didelot } 1362fad09c73SVivien Didelot } 1363fad09c73SVivien Didelot 1364fad09c73SVivien Didelot unlock: 1365fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1366fad09c73SVivien Didelot 1367fad09c73SVivien Didelot return err; 1368fad09c73SVivien Didelot } 1369fad09c73SVivien Didelot 137083dabd1fSVivien Didelot static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, 1371fad09c73SVivien Didelot const unsigned char *addr, u16 vid, 1372fad09c73SVivien Didelot u8 state) 1373fad09c73SVivien Didelot { 1374b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 137588472939SVivien Didelot struct mv88e6xxx_atu_entry entry; 1376fad09c73SVivien Didelot int err; 1377fad09c73SVivien Didelot 1378fad09c73SVivien Didelot /* Null VLAN ID corresponds to the port private database */ 1379fad09c73SVivien Didelot if (vid == 0) 1380b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid); 1381fad09c73SVivien Didelot else 1382567aa59aSVivien Didelot err = mv88e6xxx_vtu_get(chip, vid, &vlan, false); 1383fad09c73SVivien Didelot if (err) 1384fad09c73SVivien Didelot return err; 1385fad09c73SVivien Didelot 1386dabc1a96SVivien Didelot entry.state = GLOBAL_ATU_DATA_STATE_UNUSED; 1387dabc1a96SVivien Didelot ether_addr_copy(entry.mac, addr); 1388dabc1a96SVivien Didelot eth_addr_dec(entry.mac); 1389dabc1a96SVivien Didelot 1390dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry); 139188472939SVivien Didelot if (err) 139288472939SVivien Didelot return err; 139388472939SVivien Didelot 1394dabc1a96SVivien Didelot /* Initialize a fresh ATU entry if it isn't found */ 1395dabc1a96SVivien Didelot if (entry.state == GLOBAL_ATU_DATA_STATE_UNUSED || 1396dabc1a96SVivien Didelot !ether_addr_equal(entry.mac, addr)) { 1397dabc1a96SVivien Didelot memset(&entry, 0, sizeof(entry)); 1398dabc1a96SVivien Didelot ether_addr_copy(entry.mac, addr); 1399dabc1a96SVivien Didelot } 1400dabc1a96SVivien Didelot 140188472939SVivien Didelot /* Purge the ATU entry only if no port is using it anymore */ 140288472939SVivien Didelot if (state == GLOBAL_ATU_DATA_STATE_UNUSED) { 140301bd96c8SVivien Didelot entry.portvec &= ~BIT(port); 140401bd96c8SVivien Didelot if (!entry.portvec) 140588472939SVivien Didelot entry.state = GLOBAL_ATU_DATA_STATE_UNUSED; 140688472939SVivien Didelot } else { 140701bd96c8SVivien Didelot entry.portvec |= BIT(port); 1408fad09c73SVivien Didelot entry.state = state; 1409fad09c73SVivien Didelot } 1410fad09c73SVivien Didelot 14119c13c026SVivien Didelot return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry); 1412fad09c73SVivien Didelot } 1413fad09c73SVivien Didelot 1414fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port, 1415fad09c73SVivien Didelot const struct switchdev_obj_port_fdb *fdb, 1416fad09c73SVivien Didelot struct switchdev_trans *trans) 1417fad09c73SVivien Didelot { 1418fad09c73SVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 1419fad09c73SVivien Didelot * so skip the prepare phase. 1420fad09c73SVivien Didelot */ 1421fad09c73SVivien Didelot return 0; 1422fad09c73SVivien Didelot } 1423fad09c73SVivien Didelot 1424fad09c73SVivien Didelot static void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, 1425fad09c73SVivien Didelot const struct switchdev_obj_port_fdb *fdb, 1426fad09c73SVivien Didelot struct switchdev_trans *trans) 1427fad09c73SVivien Didelot { 142804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1429fad09c73SVivien Didelot 1430fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 143183dabd1fSVivien Didelot if (mv88e6xxx_port_db_load_purge(chip, port, fdb->addr, fdb->vid, 143283dabd1fSVivien Didelot GLOBAL_ATU_DATA_STATE_UC_STATIC)) 1433774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to load unicast MAC address\n", 1434774439e5SVivien Didelot port); 1435fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1436fad09c73SVivien Didelot } 1437fad09c73SVivien Didelot 1438fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, 1439fad09c73SVivien Didelot const struct switchdev_obj_port_fdb *fdb) 1440fad09c73SVivien Didelot { 144104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 144283dabd1fSVivien Didelot int err; 1443fad09c73SVivien Didelot 1444fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 144583dabd1fSVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, fdb->addr, fdb->vid, 1446fad09c73SVivien Didelot GLOBAL_ATU_DATA_STATE_UNUSED); 1447fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1448fad09c73SVivien Didelot 144983dabd1fSVivien Didelot return err; 1450fad09c73SVivien Didelot } 1451fad09c73SVivien Didelot 145283dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, 1453fad09c73SVivien Didelot u16 fid, u16 vid, int port, 145483dabd1fSVivien Didelot struct switchdev_obj *obj, 1455438ff537SVivien Didelot switchdev_obj_dump_cb_t *cb) 1456fad09c73SVivien Didelot { 1457dabc1a96SVivien Didelot struct mv88e6xxx_atu_entry addr; 1458fad09c73SVivien Didelot int err; 1459fad09c73SVivien Didelot 1460dabc1a96SVivien Didelot addr.state = GLOBAL_ATU_DATA_STATE_UNUSED; 1461dabc1a96SVivien Didelot eth_broadcast_addr(addr.mac); 1462fad09c73SVivien Didelot 1463fad09c73SVivien Didelot do { 1464dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); 1465fad09c73SVivien Didelot if (err) 146683dabd1fSVivien Didelot return err; 1467fad09c73SVivien Didelot 1468fad09c73SVivien Didelot if (addr.state == GLOBAL_ATU_DATA_STATE_UNUSED) 1469fad09c73SVivien Didelot break; 1470fad09c73SVivien Didelot 147101bd96c8SVivien Didelot if (addr.trunk || (addr.portvec & BIT(port)) == 0) 147283dabd1fSVivien Didelot continue; 1473fad09c73SVivien Didelot 147483dabd1fSVivien Didelot if (obj->id == SWITCHDEV_OBJ_ID_PORT_FDB) { 147583dabd1fSVivien Didelot struct switchdev_obj_port_fdb *fdb; 147683dabd1fSVivien Didelot 147783dabd1fSVivien Didelot if (!is_unicast_ether_addr(addr.mac)) 147883dabd1fSVivien Didelot continue; 147983dabd1fSVivien Didelot 148083dabd1fSVivien Didelot fdb = SWITCHDEV_OBJ_PORT_FDB(obj); 1481fad09c73SVivien Didelot fdb->vid = vid; 1482fad09c73SVivien Didelot ether_addr_copy(fdb->addr, addr.mac); 148383dabd1fSVivien Didelot if (addr.state == GLOBAL_ATU_DATA_STATE_UC_STATIC) 148483dabd1fSVivien Didelot fdb->ndm_state = NUD_NOARP; 148583dabd1fSVivien Didelot else 148683dabd1fSVivien Didelot fdb->ndm_state = NUD_REACHABLE; 14877df8fbddSVivien Didelot } else if (obj->id == SWITCHDEV_OBJ_ID_PORT_MDB) { 14887df8fbddSVivien Didelot struct switchdev_obj_port_mdb *mdb; 14897df8fbddSVivien Didelot 14907df8fbddSVivien Didelot if (!is_multicast_ether_addr(addr.mac)) 14917df8fbddSVivien Didelot continue; 14927df8fbddSVivien Didelot 14937df8fbddSVivien Didelot mdb = SWITCHDEV_OBJ_PORT_MDB(obj); 14947df8fbddSVivien Didelot mdb->vid = vid; 14957df8fbddSVivien Didelot ether_addr_copy(mdb->addr, addr.mac); 149683dabd1fSVivien Didelot } else { 149783dabd1fSVivien Didelot return -EOPNOTSUPP; 1498fad09c73SVivien Didelot } 149983dabd1fSVivien Didelot 150083dabd1fSVivien Didelot err = cb(obj); 150183dabd1fSVivien Didelot if (err) 150283dabd1fSVivien Didelot return err; 1503fad09c73SVivien Didelot } while (!is_broadcast_ether_addr(addr.mac)); 1504fad09c73SVivien Didelot 1505fad09c73SVivien Didelot return err; 1506fad09c73SVivien Didelot } 1507fad09c73SVivien Didelot 150883dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, 150983dabd1fSVivien Didelot struct switchdev_obj *obj, 1510438ff537SVivien Didelot switchdev_obj_dump_cb_t *cb) 151183dabd1fSVivien Didelot { 1512b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan = { 15133cf3c846SVivien Didelot .vid = chip->info->max_vid, 151483dabd1fSVivien Didelot }; 151583dabd1fSVivien Didelot u16 fid; 151683dabd1fSVivien Didelot int err; 151783dabd1fSVivien Didelot 151883dabd1fSVivien Didelot /* Dump port's default Filtering Information Database (VLAN ID 0) */ 1519b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &fid); 152083dabd1fSVivien Didelot if (err) 152183dabd1fSVivien Didelot return err; 152283dabd1fSVivien Didelot 152383dabd1fSVivien Didelot err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, obj, cb); 152483dabd1fSVivien Didelot if (err) 152583dabd1fSVivien Didelot return err; 152683dabd1fSVivien Didelot 152783dabd1fSVivien Didelot /* Dump VLANs' Filtering Information Databases */ 152883dabd1fSVivien Didelot do { 1529f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 153083dabd1fSVivien Didelot if (err) 153183dabd1fSVivien Didelot return err; 153283dabd1fSVivien Didelot 153383dabd1fSVivien Didelot if (!vlan.valid) 153483dabd1fSVivien Didelot break; 153583dabd1fSVivien Didelot 153683dabd1fSVivien Didelot err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port, 153783dabd1fSVivien Didelot obj, cb); 153883dabd1fSVivien Didelot if (err) 153983dabd1fSVivien Didelot return err; 15403cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 154183dabd1fSVivien Didelot 154283dabd1fSVivien Didelot return err; 154383dabd1fSVivien Didelot } 154483dabd1fSVivien Didelot 1545fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, 1546fad09c73SVivien Didelot struct switchdev_obj_port_fdb *fdb, 1547438ff537SVivien Didelot switchdev_obj_dump_cb_t *cb) 1548fad09c73SVivien Didelot { 154904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1550fad09c73SVivien Didelot int err; 1551fad09c73SVivien Didelot 1552fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 155383dabd1fSVivien Didelot err = mv88e6xxx_port_db_dump(chip, port, &fdb->obj, cb); 1554fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1555fad09c73SVivien Didelot 1556fad09c73SVivien Didelot return err; 1557fad09c73SVivien Didelot } 1558fad09c73SVivien Didelot 1559240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, 1560240ea3efSVivien Didelot struct net_device *br) 1561240ea3efSVivien Didelot { 1562e96a6e02SVivien Didelot struct dsa_switch *ds; 1563240ea3efSVivien Didelot int port; 1564e96a6e02SVivien Didelot int dev; 1565240ea3efSVivien Didelot int err; 1566240ea3efSVivien Didelot 1567240ea3efSVivien Didelot /* Remap the Port VLAN of each local bridge group member */ 1568240ea3efSVivien Didelot for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) { 1569240ea3efSVivien Didelot if (chip->ds->ports[port].bridge_dev == br) { 1570240ea3efSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, port); 1571240ea3efSVivien Didelot if (err) 1572240ea3efSVivien Didelot return err; 1573240ea3efSVivien Didelot } 1574240ea3efSVivien Didelot } 1575240ea3efSVivien Didelot 1576e96a6e02SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1577e96a6e02SVivien Didelot return 0; 1578e96a6e02SVivien Didelot 1579e96a6e02SVivien Didelot /* Remap the Port VLAN of each cross-chip bridge group member */ 1580e96a6e02SVivien Didelot for (dev = 0; dev < DSA_MAX_SWITCHES; ++dev) { 1581e96a6e02SVivien Didelot ds = chip->ds->dst->ds[dev]; 1582e96a6e02SVivien Didelot if (!ds) 1583e96a6e02SVivien Didelot break; 1584e96a6e02SVivien Didelot 1585e96a6e02SVivien Didelot for (port = 0; port < ds->num_ports; ++port) { 1586e96a6e02SVivien Didelot if (ds->ports[port].bridge_dev == br) { 1587e96a6e02SVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 1588e96a6e02SVivien Didelot if (err) 1589e96a6e02SVivien Didelot return err; 1590e96a6e02SVivien Didelot } 1591e96a6e02SVivien Didelot } 1592e96a6e02SVivien Didelot } 1593e96a6e02SVivien Didelot 1594240ea3efSVivien Didelot return 0; 1595240ea3efSVivien Didelot } 1596240ea3efSVivien Didelot 1597fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, 1598fae8a25eSVivien Didelot struct net_device *br) 1599fad09c73SVivien Didelot { 160004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1601240ea3efSVivien Didelot int err; 1602fad09c73SVivien Didelot 1603fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1604240ea3efSVivien Didelot err = mv88e6xxx_bridge_map(chip, br); 1605fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1606fad09c73SVivien Didelot 1607fad09c73SVivien Didelot return err; 1608fad09c73SVivien Didelot } 1609fad09c73SVivien Didelot 1610f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, 1611f123f2fbSVivien Didelot struct net_device *br) 1612fad09c73SVivien Didelot { 161304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1614fad09c73SVivien Didelot 1615fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1616240ea3efSVivien Didelot if (mv88e6xxx_bridge_map(chip, br) || 1617240ea3efSVivien Didelot mv88e6xxx_port_vlan_map(chip, port)) 1618240ea3efSVivien Didelot dev_err(ds->dev, "failed to remap in-chip Port VLAN\n"); 1619fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1620fad09c73SVivien Didelot } 1621fad09c73SVivien Didelot 1622aec5ac88SVivien Didelot static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev, 1623aec5ac88SVivien Didelot int port, struct net_device *br) 1624aec5ac88SVivien Didelot { 1625aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1626aec5ac88SVivien Didelot int err; 1627aec5ac88SVivien Didelot 1628aec5ac88SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1629aec5ac88SVivien Didelot return 0; 1630aec5ac88SVivien Didelot 1631aec5ac88SVivien Didelot mutex_lock(&chip->reg_lock); 1632aec5ac88SVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 1633aec5ac88SVivien Didelot mutex_unlock(&chip->reg_lock); 1634aec5ac88SVivien Didelot 1635aec5ac88SVivien Didelot return err; 1636aec5ac88SVivien Didelot } 1637aec5ac88SVivien Didelot 1638aec5ac88SVivien Didelot static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev, 1639aec5ac88SVivien Didelot int port, struct net_device *br) 1640aec5ac88SVivien Didelot { 1641aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1642aec5ac88SVivien Didelot 1643aec5ac88SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1644aec5ac88SVivien Didelot return; 1645aec5ac88SVivien Didelot 1646aec5ac88SVivien Didelot mutex_lock(&chip->reg_lock); 1647aec5ac88SVivien Didelot if (mv88e6xxx_pvt_map(chip, dev, port)) 1648aec5ac88SVivien Didelot dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); 1649aec5ac88SVivien Didelot mutex_unlock(&chip->reg_lock); 1650aec5ac88SVivien Didelot } 1651aec5ac88SVivien Didelot 165217e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip) 165317e708baSVivien Didelot { 165417e708baSVivien Didelot if (chip->info->ops->reset) 165517e708baSVivien Didelot return chip->info->ops->reset(chip); 165617e708baSVivien Didelot 165717e708baSVivien Didelot return 0; 165817e708baSVivien Didelot } 165917e708baSVivien Didelot 1660309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) 1661309eca6dSVivien Didelot { 1662309eca6dSVivien Didelot struct gpio_desc *gpiod = chip->reset; 1663309eca6dSVivien Didelot 1664309eca6dSVivien Didelot /* If there is a GPIO connected to the reset pin, toggle it */ 1665309eca6dSVivien Didelot if (gpiod) { 1666309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 1); 1667309eca6dSVivien Didelot usleep_range(10000, 20000); 1668309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 0); 1669309eca6dSVivien Didelot usleep_range(10000, 20000); 1670309eca6dSVivien Didelot } 1671309eca6dSVivien Didelot } 1672309eca6dSVivien Didelot 16734ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip) 16744ac4b5a6SVivien Didelot { 16754ac4b5a6SVivien Didelot int i, err; 16764ac4b5a6SVivien Didelot 16774ac4b5a6SVivien Didelot /* Set all ports to the Disabled state */ 16784ac4b5a6SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 1679f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED); 16804ac4b5a6SVivien Didelot if (err) 16814ac4b5a6SVivien Didelot return err; 16824ac4b5a6SVivien Didelot } 16834ac4b5a6SVivien Didelot 16844ac4b5a6SVivien Didelot /* Wait for transmit queues to drain, 16854ac4b5a6SVivien Didelot * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps. 16864ac4b5a6SVivien Didelot */ 16874ac4b5a6SVivien Didelot usleep_range(2000, 4000); 16884ac4b5a6SVivien Didelot 16894ac4b5a6SVivien Didelot return 0; 16904ac4b5a6SVivien Didelot } 16914ac4b5a6SVivien Didelot 1692fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip) 1693fad09c73SVivien Didelot { 1694a935c052SVivien Didelot int err; 1695fad09c73SVivien Didelot 16964ac4b5a6SVivien Didelot err = mv88e6xxx_disable_ports(chip); 16970e7b9925SAndrew Lunn if (err) 16980e7b9925SAndrew Lunn return err; 1699fad09c73SVivien Didelot 1700309eca6dSVivien Didelot mv88e6xxx_hardware_reset(chip); 1701fad09c73SVivien Didelot 170217e708baSVivien Didelot return mv88e6xxx_software_reset(chip); 1703fad09c73SVivien Didelot } 1704fad09c73SVivien Didelot 17054314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, 170631bef4e9SVivien Didelot enum mv88e6xxx_frame_mode frame, 170731bef4e9SVivien Didelot enum mv88e6xxx_egress_mode egress, u16 etype) 170856995cbcSAndrew Lunn { 170956995cbcSAndrew Lunn int err; 171056995cbcSAndrew Lunn 17114314557cSVivien Didelot if (!chip->info->ops->port_set_frame_mode) 17124314557cSVivien Didelot return -EOPNOTSUPP; 17134314557cSVivien Didelot 17144314557cSVivien Didelot err = mv88e6xxx_port_set_egress_mode(chip, port, egress); 171556995cbcSAndrew Lunn if (err) 171656995cbcSAndrew Lunn return err; 171756995cbcSAndrew Lunn 17184314557cSVivien Didelot err = chip->info->ops->port_set_frame_mode(chip, port, frame); 17194314557cSVivien Didelot if (err) 17204314557cSVivien Didelot return err; 17214314557cSVivien Didelot 17224314557cSVivien Didelot if (chip->info->ops->port_set_ether_type) 17234314557cSVivien Didelot return chip->info->ops->port_set_ether_type(chip, port, etype); 17244314557cSVivien Didelot 17254314557cSVivien Didelot return 0; 17264314557cSVivien Didelot } 17274314557cSVivien Didelot 17284314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port) 17294314557cSVivien Didelot { 17304314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL, 173131bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 17324314557cSVivien Didelot PORT_ETH_TYPE_DEFAULT); 17334314557cSVivien Didelot } 17344314557cSVivien Didelot 17354314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port) 17364314557cSVivien Didelot { 17374314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA, 173831bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 17394314557cSVivien Didelot PORT_ETH_TYPE_DEFAULT); 17404314557cSVivien Didelot } 17414314557cSVivien Didelot 17424314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port) 17434314557cSVivien Didelot { 17444314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, 17454314557cSVivien Didelot MV88E6XXX_FRAME_MODE_ETHERTYPE, 174631bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_ETHERTYPE, 174731bef4e9SVivien Didelot ETH_P_EDSA); 17484314557cSVivien Didelot } 17494314557cSVivien Didelot 17504314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port) 17514314557cSVivien Didelot { 17524314557cSVivien Didelot if (dsa_is_dsa_port(chip->ds, port)) 17534314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 17544314557cSVivien Didelot 17554314557cSVivien Didelot if (dsa_is_normal_port(chip->ds, port)) 17564314557cSVivien Didelot return mv88e6xxx_set_port_mode_normal(chip, port); 17574314557cSVivien Didelot 17584314557cSVivien Didelot /* Setup CPU port mode depending on its supported tag format */ 17594314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA) 17604314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 17614314557cSVivien Didelot 17624314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA) 17634314557cSVivien Didelot return mv88e6xxx_set_port_mode_edsa(chip, port); 17644314557cSVivien Didelot 17654314557cSVivien Didelot return -EINVAL; 17664314557cSVivien Didelot } 17674314557cSVivien Didelot 1768ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port) 1769ea698f4fSVivien Didelot { 1770ea698f4fSVivien Didelot bool message = dsa_is_dsa_port(chip->ds, port); 1771ea698f4fSVivien Didelot 1772ea698f4fSVivien Didelot return mv88e6xxx_port_set_message_port(chip, port, message); 1773ea698f4fSVivien Didelot } 1774ea698f4fSVivien Didelot 1775601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) 1776601aeed3SVivien Didelot { 1777601aeed3SVivien Didelot bool flood = port == dsa_upstream_port(chip->ds); 1778601aeed3SVivien Didelot 1779601aeed3SVivien Didelot /* Upstream ports flood frames with unknown unicast or multicast DA */ 1780601aeed3SVivien Didelot if (chip->info->ops->port_set_egress_floods) 1781601aeed3SVivien Didelot return chip->info->ops->port_set_egress_floods(chip, port, 1782601aeed3SVivien Didelot flood, flood); 1783601aeed3SVivien Didelot 1784601aeed3SVivien Didelot return 0; 1785601aeed3SVivien Didelot } 1786601aeed3SVivien Didelot 17876d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, 17886d91782fSAndrew Lunn bool on) 17896d91782fSAndrew Lunn { 1790523a8904SVivien Didelot if (chip->info->ops->serdes_power) 1791523a8904SVivien Didelot return chip->info->ops->serdes_power(chip, port, on); 17926d91782fSAndrew Lunn 1793523a8904SVivien Didelot return 0; 17946d91782fSAndrew Lunn } 17956d91782fSAndrew Lunn 1796fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) 1797fad09c73SVivien Didelot { 1798fad09c73SVivien Didelot struct dsa_switch *ds = chip->ds; 17990e7b9925SAndrew Lunn int err; 1800fad09c73SVivien Didelot u16 reg; 1801fad09c73SVivien Didelot 1802d78343d2SVivien Didelot /* MAC Forcing register: don't force link, speed, duplex or flow control 1803d78343d2SVivien Didelot * state to any particular values on physical ports, but force the CPU 1804d78343d2SVivien Didelot * port and all DSA ports to their maximum bandwidth and full duplex. 1805fad09c73SVivien Didelot */ 1806d78343d2SVivien Didelot if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) 1807d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP, 1808d78343d2SVivien Didelot SPEED_MAX, DUPLEX_FULL, 1809d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 1810fad09c73SVivien Didelot else 1811d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, 1812d78343d2SVivien Didelot SPEED_UNFORCED, DUPLEX_UNFORCED, 1813d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 18140e7b9925SAndrew Lunn if (err) 18150e7b9925SAndrew Lunn return err; 1816fad09c73SVivien Didelot 1817fad09c73SVivien Didelot /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, 1818fad09c73SVivien Didelot * disable Header mode, enable IGMP/MLD snooping, disable VLAN 1819fad09c73SVivien Didelot * tunneling, determine priority by looking at 802.1p and IP 1820fad09c73SVivien Didelot * priority fields (IP prio has precedence), and set STP state 1821fad09c73SVivien Didelot * to Forwarding. 1822fad09c73SVivien Didelot * 1823fad09c73SVivien Didelot * If this is the CPU link, use DSA or EDSA tagging depending 1824fad09c73SVivien Didelot * on which tagging mode was configured. 1825fad09c73SVivien Didelot * 1826fad09c73SVivien Didelot * If this is a link to another switch, use DSA tagging mode. 1827fad09c73SVivien Didelot * 1828fad09c73SVivien Didelot * If this is the upstream port for this switch, enable 1829fad09c73SVivien Didelot * forwarding of unknown unicasts and multicasts. 1830fad09c73SVivien Didelot */ 1831a89b433bSVivien Didelot reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP | 1832a89b433bSVivien Didelot MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | 1833a89b433bSVivien Didelot MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 1834a89b433bSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 18350e7b9925SAndrew Lunn if (err) 18360e7b9925SAndrew Lunn return err; 183756995cbcSAndrew Lunn 1838601aeed3SVivien Didelot err = mv88e6xxx_setup_port_mode(chip, port); 183956995cbcSAndrew Lunn if (err) 184056995cbcSAndrew Lunn return err; 1841fad09c73SVivien Didelot 1842601aeed3SVivien Didelot err = mv88e6xxx_setup_egress_floods(chip, port); 18434314557cSVivien Didelot if (err) 18444314557cSVivien Didelot return err; 18454314557cSVivien Didelot 184604aca993SAndrew Lunn /* Enable the SERDES interface for DSA and CPU ports. Normal 184704aca993SAndrew Lunn * ports SERDES are enabled when the port is enabled, thus 184804aca993SAndrew Lunn * saving a bit of power. 1849fad09c73SVivien Didelot */ 185004aca993SAndrew Lunn if ((dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) { 18516d91782fSAndrew Lunn err = mv88e6xxx_serdes_power(chip, port, true); 18520e7b9925SAndrew Lunn if (err) 18530e7b9925SAndrew Lunn return err; 185404aca993SAndrew Lunn } 1855fad09c73SVivien Didelot 1856fad09c73SVivien Didelot /* Port Control 2: don't force a good FCS, set the maximum frame size to 1857fad09c73SVivien Didelot * 10240 bytes, disable 802.1q tags checking, don't discard tagged or 1858fad09c73SVivien Didelot * untagged frames on this port, do a destination address lookup on all 1859fad09c73SVivien Didelot * received packets as usual, disable ARP mirroring and don't send a 1860fad09c73SVivien Didelot * copy of all transmitted/received frames on this port to the CPU. 1861fad09c73SVivien Didelot */ 1862a23b2961SAndrew Lunn err = mv88e6xxx_port_set_map_da(chip, port); 1863a23b2961SAndrew Lunn if (err) 1864a23b2961SAndrew Lunn return err; 1865a23b2961SAndrew Lunn 1866fad09c73SVivien Didelot reg = 0; 1867a23b2961SAndrew Lunn if (chip->info->ops->port_set_upstream_port) { 1868a23b2961SAndrew Lunn err = chip->info->ops->port_set_upstream_port( 1869a23b2961SAndrew Lunn chip, port, dsa_upstream_port(ds)); 18700e7b9925SAndrew Lunn if (err) 18710e7b9925SAndrew Lunn return err; 1872fad09c73SVivien Didelot } 1873fad09c73SVivien Didelot 1874a23b2961SAndrew Lunn err = mv88e6xxx_port_set_8021q_mode(chip, port, 1875a23b2961SAndrew Lunn PORT_CONTROL_2_8021Q_DISABLED); 1876a23b2961SAndrew Lunn if (err) 1877a23b2961SAndrew Lunn return err; 1878a23b2961SAndrew Lunn 1879cd782656SVivien Didelot if (chip->info->ops->port_set_jumbo_size) { 1880cd782656SVivien Didelot err = chip->info->ops->port_set_jumbo_size(chip, port, 10240); 18815f436666SAndrew Lunn if (err) 18825f436666SAndrew Lunn return err; 18835f436666SAndrew Lunn } 18845f436666SAndrew Lunn 1885fad09c73SVivien Didelot /* Port Association Vector: when learning source addresses 1886fad09c73SVivien Didelot * of packets, add the address to the address database using 1887fad09c73SVivien Didelot * a port bitmap that has only the bit for this port set and 1888fad09c73SVivien Didelot * the other bits clear. 1889fad09c73SVivien Didelot */ 1890fad09c73SVivien Didelot reg = 1 << port; 1891fad09c73SVivien Didelot /* Disable learning for CPU port */ 1892fad09c73SVivien Didelot if (dsa_is_cpu_port(ds, port)) 1893fad09c73SVivien Didelot reg = 0; 1894fad09c73SVivien Didelot 18950e7b9925SAndrew Lunn err = mv88e6xxx_port_write(chip, port, PORT_ASSOC_VECTOR, reg); 18960e7b9925SAndrew Lunn if (err) 18970e7b9925SAndrew Lunn return err; 1898fad09c73SVivien Didelot 1899fad09c73SVivien Didelot /* Egress rate control 2: disable egress rate control. */ 19000e7b9925SAndrew Lunn err = mv88e6xxx_port_write(chip, port, PORT_RATE_CONTROL_2, 0x0000); 19010e7b9925SAndrew Lunn if (err) 19020e7b9925SAndrew Lunn return err; 1903fad09c73SVivien Didelot 19040898432cSVivien Didelot if (chip->info->ops->port_pause_limit) { 19050898432cSVivien Didelot err = chip->info->ops->port_pause_limit(chip, port, 0, 0); 1906b35d322aSAndrew Lunn if (err) 1907b35d322aSAndrew Lunn return err; 1908b35d322aSAndrew Lunn } 1909b35d322aSAndrew Lunn 1910c8c94891SVivien Didelot if (chip->info->ops->port_disable_learn_limit) { 1911c8c94891SVivien Didelot err = chip->info->ops->port_disable_learn_limit(chip, port); 1912c8c94891SVivien Didelot if (err) 1913c8c94891SVivien Didelot return err; 1914c8c94891SVivien Didelot } 1915c8c94891SVivien Didelot 19169dbfb4e1SVivien Didelot if (chip->info->ops->port_disable_pri_override) { 19179dbfb4e1SVivien Didelot err = chip->info->ops->port_disable_pri_override(chip, port); 19180e7b9925SAndrew Lunn if (err) 19190e7b9925SAndrew Lunn return err; 1920ef0a7318SAndrew Lunn } 19212bbb33beSAndrew Lunn 1922ef0a7318SAndrew Lunn if (chip->info->ops->port_tag_remap) { 1923ef0a7318SAndrew Lunn err = chip->info->ops->port_tag_remap(chip, port); 19240e7b9925SAndrew Lunn if (err) 19250e7b9925SAndrew Lunn return err; 1926fad09c73SVivien Didelot } 1927fad09c73SVivien Didelot 1928ef70b111SAndrew Lunn if (chip->info->ops->port_egress_rate_limiting) { 1929ef70b111SAndrew Lunn err = chip->info->ops->port_egress_rate_limiting(chip, port); 19300e7b9925SAndrew Lunn if (err) 19310e7b9925SAndrew Lunn return err; 1932fad09c73SVivien Didelot } 1933fad09c73SVivien Didelot 1934ea698f4fSVivien Didelot err = mv88e6xxx_setup_message_port(chip, port); 19350e7b9925SAndrew Lunn if (err) 19360e7b9925SAndrew Lunn return err; 1937fad09c73SVivien Didelot 1938fad09c73SVivien Didelot /* Port based VLAN map: give each port the same default address 1939fad09c73SVivien Didelot * database, and allow bidirectional communication between the 1940fad09c73SVivien Didelot * CPU and DSA port(s), and the other ports. 1941fad09c73SVivien Didelot */ 1942b4e48c50SVivien Didelot err = mv88e6xxx_port_set_fid(chip, port, 0); 19430e7b9925SAndrew Lunn if (err) 19440e7b9925SAndrew Lunn return err; 1945fad09c73SVivien Didelot 1946240ea3efSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, port); 19470e7b9925SAndrew Lunn if (err) 19480e7b9925SAndrew Lunn return err; 1949fad09c73SVivien Didelot 1950fad09c73SVivien Didelot /* Default VLAN ID and priority: don't set a default VLAN 1951fad09c73SVivien Didelot * ID, and set the default packet priority to zero. 1952fad09c73SVivien Didelot */ 1953b7929fb3SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0); 1954fad09c73SVivien Didelot } 1955fad09c73SVivien Didelot 195604aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port, 195704aca993SAndrew Lunn struct phy_device *phydev) 195804aca993SAndrew Lunn { 195904aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 1960523a8904SVivien Didelot int err; 196104aca993SAndrew Lunn 196204aca993SAndrew Lunn mutex_lock(&chip->reg_lock); 1963523a8904SVivien Didelot err = mv88e6xxx_serdes_power(chip, port, true); 196404aca993SAndrew Lunn mutex_unlock(&chip->reg_lock); 196504aca993SAndrew Lunn 196604aca993SAndrew Lunn return err; 196704aca993SAndrew Lunn } 196804aca993SAndrew Lunn 196904aca993SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port, 197004aca993SAndrew Lunn struct phy_device *phydev) 197104aca993SAndrew Lunn { 197204aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 197304aca993SAndrew Lunn 197404aca993SAndrew Lunn mutex_lock(&chip->reg_lock); 1975523a8904SVivien Didelot if (mv88e6xxx_serdes_power(chip, port, false)) 1976523a8904SVivien Didelot dev_err(chip->dev, "failed to power off SERDES\n"); 197704aca993SAndrew Lunn mutex_unlock(&chip->reg_lock); 197804aca993SAndrew Lunn } 197904aca993SAndrew Lunn 1980aa0938c6SWei Yongjun static int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) 19813b4caa1bSVivien Didelot { 19823b4caa1bSVivien Didelot int err; 19833b4caa1bSVivien Didelot 1984a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]); 19853b4caa1bSVivien Didelot if (err) 19863b4caa1bSVivien Didelot return err; 19873b4caa1bSVivien Didelot 1988a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]); 19893b4caa1bSVivien Didelot if (err) 19903b4caa1bSVivien Didelot return err; 19913b4caa1bSVivien Didelot 1992a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]); 1993a935c052SVivien Didelot if (err) 1994a935c052SVivien Didelot return err; 1995a935c052SVivien Didelot 1996a935c052SVivien Didelot return 0; 19973b4caa1bSVivien Didelot } 19983b4caa1bSVivien Didelot 19992cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, 20002cfcd964SVivien Didelot unsigned int ageing_time) 20012cfcd964SVivien Didelot { 200204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 20032cfcd964SVivien Didelot int err; 20042cfcd964SVivien Didelot 20052cfcd964SVivien Didelot mutex_lock(&chip->reg_lock); 2006720c6343SVivien Didelot err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time); 20072cfcd964SVivien Didelot mutex_unlock(&chip->reg_lock); 20082cfcd964SVivien Didelot 20092cfcd964SVivien Didelot return err; 20102cfcd964SVivien Didelot } 20112cfcd964SVivien Didelot 20129729934cSVivien Didelot static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) 2013fad09c73SVivien Didelot { 2014fad09c73SVivien Didelot struct dsa_switch *ds = chip->ds; 2015fad09c73SVivien Didelot u32 upstream_port = dsa_upstream_port(ds); 2016fad09c73SVivien Didelot int err; 2017fad09c73SVivien Didelot 2018fa8d1179SVivien Didelot if (chip->info->ops->set_cpu_port) { 2019fa8d1179SVivien Didelot err = chip->info->ops->set_cpu_port(chip, upstream_port); 2020fad09c73SVivien Didelot if (err) 2021fad09c73SVivien Didelot return err; 202233641994SAndrew Lunn } 202333641994SAndrew Lunn 2024fa8d1179SVivien Didelot if (chip->info->ops->set_egress_port) { 2025fa8d1179SVivien Didelot err = chip->info->ops->set_egress_port(chip, upstream_port); 202633641994SAndrew Lunn if (err) 202733641994SAndrew Lunn return err; 202833641994SAndrew Lunn } 2029fad09c73SVivien Didelot 2030fad09c73SVivien Didelot /* Disable remote management, and set the switch's DSA device number. */ 2031a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, 2032fad09c73SVivien Didelot GLOBAL_CONTROL_2_MULTIPLE_CASCADE | 2033fad09c73SVivien Didelot (ds->index & 0x1f)); 2034fad09c73SVivien Didelot if (err) 2035fad09c73SVivien Didelot return err; 2036fad09c73SVivien Didelot 2037fad09c73SVivien Didelot /* Configure the IP ToS mapping registers. */ 2038a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_0, 0x0000); 2039fad09c73SVivien Didelot if (err) 2040fad09c73SVivien Didelot return err; 2041a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_1, 0x0000); 2042fad09c73SVivien Didelot if (err) 2043fad09c73SVivien Didelot return err; 2044a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_2, 0x5555); 2045fad09c73SVivien Didelot if (err) 2046fad09c73SVivien Didelot return err; 2047a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_3, 0x5555); 2048fad09c73SVivien Didelot if (err) 2049fad09c73SVivien Didelot return err; 2050a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_4, 0xaaaa); 2051fad09c73SVivien Didelot if (err) 2052fad09c73SVivien Didelot return err; 2053a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_5, 0xaaaa); 2054fad09c73SVivien Didelot if (err) 2055fad09c73SVivien Didelot return err; 2056a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_6, 0xffff); 2057fad09c73SVivien Didelot if (err) 2058fad09c73SVivien Didelot return err; 2059a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_7, 0xffff); 2060fad09c73SVivien Didelot if (err) 2061fad09c73SVivien Didelot return err; 2062fad09c73SVivien Didelot 2063fad09c73SVivien Didelot /* Configure the IEEE 802.1p priority mapping register. */ 2064a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_IEEE_PRI, 0xfa41); 2065fad09c73SVivien Didelot if (err) 2066fad09c73SVivien Didelot return err; 2067fad09c73SVivien Didelot 2068de227387SAndrew Lunn /* Initialize the statistics unit */ 2069de227387SAndrew Lunn err = mv88e6xxx_stats_set_histogram(chip); 2070de227387SAndrew Lunn if (err) 2071de227387SAndrew Lunn return err; 2072de227387SAndrew Lunn 20739729934cSVivien Didelot /* Clear the statistics counters for all ports */ 2074a935c052SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP, 20759729934cSVivien Didelot GLOBAL_STATS_OP_FLUSH_ALL); 20769729934cSVivien Didelot if (err) 20779729934cSVivien Didelot return err; 20789729934cSVivien Didelot 20799729934cSVivien Didelot /* Wait for the flush to complete. */ 20807f9ef3afSAndrew Lunn err = mv88e6xxx_g1_stats_wait(chip); 20819729934cSVivien Didelot if (err) 20829729934cSVivien Didelot return err; 20839729934cSVivien Didelot 20849729934cSVivien Didelot return 0; 20859729934cSVivien Didelot } 20869729934cSVivien Didelot 2087fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds) 2088fad09c73SVivien Didelot { 208904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2090fad09c73SVivien Didelot int err; 2091fad09c73SVivien Didelot int i; 2092fad09c73SVivien Didelot 2093fad09c73SVivien Didelot chip->ds = ds; 2094a3c53be5SAndrew Lunn ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); 2095fad09c73SVivien Didelot 2096fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 2097fad09c73SVivien Didelot 20989729934cSVivien Didelot /* Setup Switch Port Registers */ 2099370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 21009729934cSVivien Didelot err = mv88e6xxx_setup_port(chip, i); 21019729934cSVivien Didelot if (err) 21029729934cSVivien Didelot goto unlock; 21039729934cSVivien Didelot } 21049729934cSVivien Didelot 21059729934cSVivien Didelot /* Setup Switch Global 1 Registers */ 21069729934cSVivien Didelot err = mv88e6xxx_g1_setup(chip); 2107fad09c73SVivien Didelot if (err) 2108fad09c73SVivien Didelot goto unlock; 2109fad09c73SVivien Didelot 21109729934cSVivien Didelot /* Setup Switch Global 2 Registers */ 21119729934cSVivien Didelot if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_GLOBAL2)) { 21129729934cSVivien Didelot err = mv88e6xxx_g2_setup(chip); 2113fad09c73SVivien Didelot if (err) 2114fad09c73SVivien Didelot goto unlock; 2115fad09c73SVivien Didelot } 2116fad09c73SVivien Didelot 21171b17aedfSVivien Didelot err = mv88e6xxx_phy_setup(chip); 21181b17aedfSVivien Didelot if (err) 21191b17aedfSVivien Didelot goto unlock; 21201b17aedfSVivien Didelot 2121b486d7c9SVivien Didelot err = mv88e6xxx_vtu_setup(chip); 2122b486d7c9SVivien Didelot if (err) 2123b486d7c9SVivien Didelot goto unlock; 2124b486d7c9SVivien Didelot 212581228996SVivien Didelot err = mv88e6xxx_pvt_setup(chip); 212681228996SVivien Didelot if (err) 212781228996SVivien Didelot goto unlock; 212881228996SVivien Didelot 2129a2ac29d2SVivien Didelot err = mv88e6xxx_atu_setup(chip); 2130a2ac29d2SVivien Didelot if (err) 2131a2ac29d2SVivien Didelot goto unlock; 2132a2ac29d2SVivien Didelot 21336e55f698SAndrew Lunn /* Some generations have the configuration of sending reserved 21346e55f698SAndrew Lunn * management frames to the CPU in global2, others in 21356e55f698SAndrew Lunn * global1. Hence it does not fit the two setup functions 21366e55f698SAndrew Lunn * above. 21376e55f698SAndrew Lunn */ 21386e55f698SAndrew Lunn if (chip->info->ops->mgmt_rsvd2cpu) { 21396e55f698SAndrew Lunn err = chip->info->ops->mgmt_rsvd2cpu(chip); 21406e55f698SAndrew Lunn if (err) 21416e55f698SAndrew Lunn goto unlock; 21426e55f698SAndrew Lunn } 21436e55f698SAndrew Lunn 2144fad09c73SVivien Didelot unlock: 2145fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 2146fad09c73SVivien Didelot 2147fad09c73SVivien Didelot return err; 2148fad09c73SVivien Didelot } 2149fad09c73SVivien Didelot 21503b4caa1bSVivien Didelot static int mv88e6xxx_set_addr(struct dsa_switch *ds, u8 *addr) 21513b4caa1bSVivien Didelot { 215204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 21533b4caa1bSVivien Didelot int err; 21543b4caa1bSVivien Didelot 2155b073d4e2SVivien Didelot if (!chip->info->ops->set_switch_mac) 2156b073d4e2SVivien Didelot return -EOPNOTSUPP; 2157b073d4e2SVivien Didelot 21583b4caa1bSVivien Didelot mutex_lock(&chip->reg_lock); 2159b073d4e2SVivien Didelot err = chip->info->ops->set_switch_mac(chip, addr); 21603b4caa1bSVivien Didelot mutex_unlock(&chip->reg_lock); 21613b4caa1bSVivien Didelot 21623b4caa1bSVivien Didelot return err; 21633b4caa1bSVivien Didelot } 21643b4caa1bSVivien Didelot 2165e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) 2166fad09c73SVivien Didelot { 21670dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 21680dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 2169e57e5e77SVivien Didelot u16 val; 2170e57e5e77SVivien Didelot int err; 2171fad09c73SVivien Didelot 2172ee26a228SAndrew Lunn if (!chip->info->ops->phy_read) 2173ee26a228SAndrew Lunn return -EOPNOTSUPP; 2174ee26a228SAndrew Lunn 2175fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 2176ee26a228SAndrew Lunn err = chip->info->ops->phy_read(chip, bus, phy, reg, &val); 2177fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 2178e57e5e77SVivien Didelot 2179da9f3301SAndrew Lunn if (reg == MII_PHYSID2) { 2180da9f3301SAndrew Lunn /* Some internal PHYS don't have a model number. Use 2181da9f3301SAndrew Lunn * the mv88e6390 family model number instead. 2182da9f3301SAndrew Lunn */ 2183da9f3301SAndrew Lunn if (!(val & 0x3f0)) 2184107fcc10SVivien Didelot val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4; 2185da9f3301SAndrew Lunn } 2186da9f3301SAndrew Lunn 2187e57e5e77SVivien Didelot return err ? err : val; 2188fad09c73SVivien Didelot } 2189fad09c73SVivien Didelot 2190e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 2191fad09c73SVivien Didelot { 21920dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 21930dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 2194e57e5e77SVivien Didelot int err; 2195fad09c73SVivien Didelot 2196ee26a228SAndrew Lunn if (!chip->info->ops->phy_write) 2197ee26a228SAndrew Lunn return -EOPNOTSUPP; 2198ee26a228SAndrew Lunn 2199fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 2200ee26a228SAndrew Lunn err = chip->info->ops->phy_write(chip, bus, phy, reg, val); 2201fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 2202e57e5e77SVivien Didelot 2203e57e5e77SVivien Didelot return err; 2204fad09c73SVivien Didelot } 2205fad09c73SVivien Didelot 2206fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, 2207a3c53be5SAndrew Lunn struct device_node *np, 2208a3c53be5SAndrew Lunn bool external) 2209fad09c73SVivien Didelot { 2210fad09c73SVivien Didelot static int index; 22110dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 2212fad09c73SVivien Didelot struct mii_bus *bus; 2213fad09c73SVivien Didelot int err; 2214fad09c73SVivien Didelot 22150dd12d54SAndrew Lunn bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus)); 2216fad09c73SVivien Didelot if (!bus) 2217fad09c73SVivien Didelot return -ENOMEM; 2218fad09c73SVivien Didelot 22190dd12d54SAndrew Lunn mdio_bus = bus->priv; 2220a3c53be5SAndrew Lunn mdio_bus->bus = bus; 22210dd12d54SAndrew Lunn mdio_bus->chip = chip; 2222a3c53be5SAndrew Lunn INIT_LIST_HEAD(&mdio_bus->list); 2223a3c53be5SAndrew Lunn mdio_bus->external = external; 22240dd12d54SAndrew Lunn 2225fad09c73SVivien Didelot if (np) { 2226fad09c73SVivien Didelot bus->name = np->full_name; 2227fad09c73SVivien Didelot snprintf(bus->id, MII_BUS_ID_SIZE, "%s", np->full_name); 2228fad09c73SVivien Didelot } else { 2229fad09c73SVivien Didelot bus->name = "mv88e6xxx SMI"; 2230fad09c73SVivien Didelot snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++); 2231fad09c73SVivien Didelot } 2232fad09c73SVivien Didelot 2233fad09c73SVivien Didelot bus->read = mv88e6xxx_mdio_read; 2234fad09c73SVivien Didelot bus->write = mv88e6xxx_mdio_write; 2235fad09c73SVivien Didelot bus->parent = chip->dev; 2236fad09c73SVivien Didelot 2237a3c53be5SAndrew Lunn if (np) 2238a3c53be5SAndrew Lunn err = of_mdiobus_register(bus, np); 2239fad09c73SVivien Didelot else 2240fad09c73SVivien Didelot err = mdiobus_register(bus); 2241fad09c73SVivien Didelot if (err) { 2242fad09c73SVivien Didelot dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err); 2243fad09c73SVivien Didelot return err; 2244fad09c73SVivien Didelot } 2245fad09c73SVivien Didelot 2246a3c53be5SAndrew Lunn if (external) 2247a3c53be5SAndrew Lunn list_add_tail(&mdio_bus->list, &chip->mdios); 2248a3c53be5SAndrew Lunn else 2249a3c53be5SAndrew Lunn list_add(&mdio_bus->list, &chip->mdios); 2250a3c53be5SAndrew Lunn 2251a3c53be5SAndrew Lunn return 0; 2252a3c53be5SAndrew Lunn } 2253a3c53be5SAndrew Lunn 2254a3c53be5SAndrew Lunn static const struct of_device_id mv88e6xxx_mdio_external_match[] = { 2255a3c53be5SAndrew Lunn { .compatible = "marvell,mv88e6xxx-mdio-external", 2256a3c53be5SAndrew Lunn .data = (void *)true }, 2257a3c53be5SAndrew Lunn { }, 2258a3c53be5SAndrew Lunn }; 2259a3c53be5SAndrew Lunn 2260a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, 2261a3c53be5SAndrew Lunn struct device_node *np) 2262a3c53be5SAndrew Lunn { 2263a3c53be5SAndrew Lunn const struct of_device_id *match; 2264a3c53be5SAndrew Lunn struct device_node *child; 2265a3c53be5SAndrew Lunn int err; 2266a3c53be5SAndrew Lunn 2267a3c53be5SAndrew Lunn /* Always register one mdio bus for the internal/default mdio 2268a3c53be5SAndrew Lunn * bus. This maybe represented in the device tree, but is 2269a3c53be5SAndrew Lunn * optional. 2270a3c53be5SAndrew Lunn */ 2271a3c53be5SAndrew Lunn child = of_get_child_by_name(np, "mdio"); 2272a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, false); 2273a3c53be5SAndrew Lunn if (err) 2274a3c53be5SAndrew Lunn return err; 2275a3c53be5SAndrew Lunn 2276a3c53be5SAndrew Lunn /* Walk the device tree, and see if there are any other nodes 2277a3c53be5SAndrew Lunn * which say they are compatible with the external mdio 2278a3c53be5SAndrew Lunn * bus. 2279a3c53be5SAndrew Lunn */ 2280a3c53be5SAndrew Lunn for_each_available_child_of_node(np, child) { 2281a3c53be5SAndrew Lunn match = of_match_node(mv88e6xxx_mdio_external_match, child); 2282a3c53be5SAndrew Lunn if (match) { 2283a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, true); 2284a3c53be5SAndrew Lunn if (err) 2285a3c53be5SAndrew Lunn return err; 2286a3c53be5SAndrew Lunn } 2287a3c53be5SAndrew Lunn } 2288a3c53be5SAndrew Lunn 2289a3c53be5SAndrew Lunn return 0; 2290a3c53be5SAndrew Lunn } 2291a3c53be5SAndrew Lunn 2292a3c53be5SAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) 2293fad09c73SVivien Didelot 2294fad09c73SVivien Didelot { 2295a3c53be5SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 2296a3c53be5SAndrew Lunn struct mii_bus *bus; 2297a3c53be5SAndrew Lunn 2298a3c53be5SAndrew Lunn list_for_each_entry(mdio_bus, &chip->mdios, list) { 2299a3c53be5SAndrew Lunn bus = mdio_bus->bus; 2300fad09c73SVivien Didelot 2301fad09c73SVivien Didelot mdiobus_unregister(bus); 2302a3c53be5SAndrew Lunn } 2303fad09c73SVivien Didelot } 2304fad09c73SVivien Didelot 2305855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) 2306855b1932SVivien Didelot { 230704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2308855b1932SVivien Didelot 2309855b1932SVivien Didelot return chip->eeprom_len; 2310855b1932SVivien Didelot } 2311855b1932SVivien Didelot 2312855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds, 2313855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 2314855b1932SVivien Didelot { 231504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2316855b1932SVivien Didelot int err; 2317855b1932SVivien Didelot 2318ee4dc2e7SVivien Didelot if (!chip->info->ops->get_eeprom) 2319ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 2320ee4dc2e7SVivien Didelot 2321855b1932SVivien Didelot mutex_lock(&chip->reg_lock); 2322ee4dc2e7SVivien Didelot err = chip->info->ops->get_eeprom(chip, eeprom, data); 2323855b1932SVivien Didelot mutex_unlock(&chip->reg_lock); 2324855b1932SVivien Didelot 2325855b1932SVivien Didelot if (err) 2326855b1932SVivien Didelot return err; 2327855b1932SVivien Didelot 2328855b1932SVivien Didelot eeprom->magic = 0xc3ec4951; 2329855b1932SVivien Didelot 2330855b1932SVivien Didelot return 0; 2331855b1932SVivien Didelot } 2332855b1932SVivien Didelot 2333855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, 2334855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 2335855b1932SVivien Didelot { 233604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2337855b1932SVivien Didelot int err; 2338855b1932SVivien Didelot 2339ee4dc2e7SVivien Didelot if (!chip->info->ops->set_eeprom) 2340ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 2341ee4dc2e7SVivien Didelot 2342855b1932SVivien Didelot if (eeprom->magic != 0xc3ec4951) 2343855b1932SVivien Didelot return -EINVAL; 2344855b1932SVivien Didelot 2345855b1932SVivien Didelot mutex_lock(&chip->reg_lock); 2346ee4dc2e7SVivien Didelot err = chip->info->ops->set_eeprom(chip, eeprom, data); 2347855b1932SVivien Didelot mutex_unlock(&chip->reg_lock); 2348855b1932SVivien Didelot 2349855b1932SVivien Didelot return err; 2350855b1932SVivien Didelot } 2351855b1932SVivien Didelot 2352b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = { 23534b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6097 */ 2354b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 23557e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 23567e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 235708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 23587f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 235996a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2360ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 236156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2362601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 236356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2364ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 23650898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2366c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 23679dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2368a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 2369dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2370dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2371052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2372fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2373fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2374fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 23756e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 2376a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 2377a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 237817e708baSVivien Didelot .reset = mv88e6185_g1_reset, 2379f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 23800ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2381b3469dd8SVivien Didelot }; 2382b3469dd8SVivien Didelot 2383b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = { 23844b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6095 */ 2385b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 23867e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 23877e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 238808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 23897f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 239096a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 239156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 2392601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 2393a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 2394a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 2395dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2396dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2397052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 23986e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 2399a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 2400a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 240117e708baSVivien Didelot .reset = mv88e6185_g1_reset, 2402f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 24030ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 2404b3469dd8SVivien Didelot }; 2405b3469dd8SVivien Didelot 24067d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = { 240715da3cc8SStefan Eichenberger /* MV88E6XXX_FAMILY_6097 */ 24087d381a02SStefan Eichenberger .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 24097d381a02SStefan Eichenberger .phy_read = mv88e6xxx_g2_smi_phy_read, 24107d381a02SStefan Eichenberger .phy_write = mv88e6xxx_g2_smi_phy_write, 24117d381a02SStefan Eichenberger .port_set_link = mv88e6xxx_port_set_link, 24127d381a02SStefan Eichenberger .port_set_duplex = mv88e6xxx_port_set_duplex, 24137d381a02SStefan Eichenberger .port_set_speed = mv88e6185_port_set_speed, 2414ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 241556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2416601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 241756995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2418cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2419ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 24200898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2421c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 24229dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 24237d381a02SStefan Eichenberger .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 24247d381a02SStefan Eichenberger .stats_get_sset_count = mv88e6095_stats_get_sset_count, 24257d381a02SStefan Eichenberger .stats_get_strings = mv88e6095_stats_get_strings, 24267d381a02SStefan Eichenberger .stats_get_stats = mv88e6095_stats_get_stats, 2427fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2428fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 242991eaa475SVolodymyr Bendiuga .watchdog_ops = &mv88e6097_watchdog_ops, 24306e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 243117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2432f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 24330ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 24347d381a02SStefan Eichenberger }; 24357d381a02SStefan Eichenberger 2436b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = { 24374b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 2438b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2439ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 2440ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 244108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 24427f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 244396a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 244456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 2445601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 2446c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 24479dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 24480ac64c39SAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2449dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2450dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2451052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2452fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2453fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2454fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 24556e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 245617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2457f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 24580ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2459b3469dd8SVivien Didelot }; 2460b3469dd8SVivien Didelot 2461b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = { 24624b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 2463b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 24647e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 24657e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 246608ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 24677f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 246896a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2469ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 247056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2471601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 247256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2473a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 2474cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2475ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 24760898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2477a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 2478dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2479dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2480052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2481fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2482fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2483fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 24846e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 2485a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 2486a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 248717e708baSVivien Didelot .reset = mv88e6185_g1_reset, 2488f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 24890ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 2490b3469dd8SVivien Didelot }; 2491b3469dd8SVivien Didelot 2492990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = { 2493990e27b0SVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 2494990e27b0SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 2495990e27b0SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 2496990e27b0SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2497990e27b0SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2498990e27b0SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 2499990e27b0SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 2500990e27b0SVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 2501990e27b0SVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 2502990e27b0SVivien Didelot .port_set_speed = mv88e6390_port_set_speed, 2503990e27b0SVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 2504990e27b0SVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2505990e27b0SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 2506990e27b0SVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 2507cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2508990e27b0SVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 25090898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2510990e27b0SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 2511990e27b0SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2512990e27b0SVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 2513990e27b0SVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2514990e27b0SVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 2515990e27b0SVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 2516fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 2517fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 2518990e27b0SVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 2519990e27b0SVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 2520990e27b0SVivien Didelot .reset = mv88e6352_g1_reset, 2521f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 25220ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2523990e27b0SVivien Didelot }; 2524990e27b0SVivien Didelot 2525b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = { 25264b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 2527b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2528ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 2529ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 253008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 25317f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 253296a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2533ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 253456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2535601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 253656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2537cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2538ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 25390898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2540c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 25419dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 25420ac64c39SAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2543dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2544dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2545052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2546fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2547fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2548fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 25496e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 255017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2551f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 25520ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2553b3469dd8SVivien Didelot }; 2554b3469dd8SVivien Didelot 2555b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = { 25564b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 2557b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2558efb3e74dSAndrew Lunn .phy_read = mv88e6165_phy_read, 2559efb3e74dSAndrew Lunn .phy_write = mv88e6165_phy_write, 256008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 25617f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 256296a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2563c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 25649dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2565a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 2566dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2567dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2568052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2569fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2570fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2571fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 25726e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 257317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2574f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 25750ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2576b3469dd8SVivien Didelot }; 2577b3469dd8SVivien Didelot 2578b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = { 25794b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 2580b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2581b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2582b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 258308ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 25847f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 258594d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 258696a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2587ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 258856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2589601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 259056995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2591cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2592ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 25930898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2594c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 25959dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2596a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2597dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2598dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2599052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2600fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2601fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2602fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 26036e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 260417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2605f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 26060ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2607b3469dd8SVivien Didelot }; 2608b3469dd8SVivien Didelot 2609b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = { 26104b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 2611ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 2612ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 2613b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2614b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2615b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 261608ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 26177f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 2618a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 261996a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 2620ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 262156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2622601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 262356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2624cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2625ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 26260898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2627c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 26289dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2629a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2630dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2631dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2632052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2633fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2634fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2635fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 26366e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 263717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2638f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 26390ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 26406d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 2641b3469dd8SVivien Didelot }; 2642b3469dd8SVivien Didelot 2643b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = { 26444b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 2645b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2646b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2647b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 264808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 26497f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 265094d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 265196a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2652ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 265356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2654601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 265556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2656cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2657ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 26580898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2659c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 26609dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2661a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2662dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2663dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2664052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2665fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2666fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2667fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 26686e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 266917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2670f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 26710ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2672b3469dd8SVivien Didelot }; 2673b3469dd8SVivien Didelot 2674b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = { 26754b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 2676ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 2677ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 2678b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2679b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2680b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 268108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 26827f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 2683a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 268496a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 2685ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 268656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2687601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 268856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2689cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2690ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 26910898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2692c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 26939dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2694a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2695dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2696dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2697052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2698fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2699fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2700fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 27016e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 270217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2703f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 27040ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 27056d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 2706b3469dd8SVivien Didelot }; 2707b3469dd8SVivien Didelot 2708b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = { 27094b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 2710b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 27117e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 27127e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 271308ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 27147f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 271596a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 271656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 2717601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 2718ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 2719a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 2720a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 2721dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2722dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2723052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2724fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2725fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2726fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 27276e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 2728a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 2729a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 273017e708baSVivien Didelot .reset = mv88e6185_g1_reset, 2731f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 27320ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 2733b3469dd8SVivien Didelot }; 2734b3469dd8SVivien Didelot 27351a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = { 27364b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 273798fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 273898fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 27391a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 27401a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 27411a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 27421a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 27431a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 27441a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 27451a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 2746ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 274756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2748601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 274956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 27500898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 2751c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 27529dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 275379523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 2754de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 2755dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2756dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 2757e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 2758fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 2759fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 276061303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 27616e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 276217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2763931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 2764931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 27656335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 27661a3b39ecSAndrew Lunn }; 27671a3b39ecSAndrew Lunn 27681a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = { 27694b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 277098fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 277198fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 27721a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 27731a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 27741a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 27751a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 27761a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 27771a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 27781a3b39ecSAndrew Lunn .port_set_speed = mv88e6390x_port_set_speed, 2779ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 278056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2781601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 278256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 27830898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 2784c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 27859dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 278679523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 2787de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 2788dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2789dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 2790e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 2791fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 2792fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 279361303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 27946e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 279517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2796931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 2797931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 27986335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 27991a3b39ecSAndrew Lunn }; 28001a3b39ecSAndrew Lunn 28011a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = { 28024b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 280398fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 280498fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 28051a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 28061a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 28071a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 28081a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 28091a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 28101a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 28111a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 2812ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 281356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2814601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 281556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 28160898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 2817c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 28189dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 281979523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 2820de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 2821dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2822dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 2823e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 2824fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 2825fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 282661303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 28276e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 282817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2829931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 2830931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 28316335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 28321a3b39ecSAndrew Lunn }; 28331a3b39ecSAndrew Lunn 2834b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = { 28354b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 2836ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 2837ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 2838b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2839b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2840b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 284108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 28427f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 2843a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 284496a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 2845ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 284656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2847601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 284856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2849cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2850ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 28510898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2852c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 28539dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2854a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2855dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2856dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2857052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2858fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2859fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2860fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 28616e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 286217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2863f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 28640ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 28656d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 2866b3469dd8SVivien Didelot }; 2867b3469dd8SVivien Didelot 28681a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = { 28694b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 287098fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 287198fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 28721a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 28731a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 28741a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 28751a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 28761a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 28771a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 28781a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 2879ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 288056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2881601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 288256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 28830898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 2884f39908d3SAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 2885c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 28869dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 288779523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 2888de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 2889dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2890dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 2891e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 2892fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 2893fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 289461303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 28956e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 289617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2897931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 2898931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 28996335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 29001a3b39ecSAndrew Lunn }; 29011a3b39ecSAndrew Lunn 2902b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = { 29034b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6320 */ 2904ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 2905ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 2906b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2907b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2908b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 290908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 29107f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 291196a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2912ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 291356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2914601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 291556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2916cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2917ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 29180898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2919c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 29209dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2921a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2922dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2923dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 2924052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 2925fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2926fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 29276e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 292817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2929f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 29300ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 2931b3469dd8SVivien Didelot }; 2932b3469dd8SVivien Didelot 2933b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = { 29344b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6321 */ 2935ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 2936ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 2937b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2938b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2939b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 294008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 29417f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 294296a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2943ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 294456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2945601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 294656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2947cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2948ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 29490898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2950c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 29519dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 2952a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 2953dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2954dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 2955052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 2956fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2957fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 295817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2959f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 29600ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 2961b3469dd8SVivien Didelot }; 2962b3469dd8SVivien Didelot 296316e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = { 296416e329aeSVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 296516e329aeSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 296616e329aeSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 296716e329aeSVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 296816e329aeSVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 296916e329aeSVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 297016e329aeSVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 297116e329aeSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 297216e329aeSVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 297316e329aeSVivien Didelot .port_set_speed = mv88e6390_port_set_speed, 297416e329aeSVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 297516e329aeSVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 297616e329aeSVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 297716e329aeSVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 2978cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 297916e329aeSVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 29800898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 298116e329aeSVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 298216e329aeSVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 298316e329aeSVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 298416e329aeSVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 298516e329aeSVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 298616e329aeSVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 2987fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 2988fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 298916e329aeSVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 299016e329aeSVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 299116e329aeSVivien Didelot .reset = mv88e6352_g1_reset, 2992f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 29930ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 299416e329aeSVivien Didelot }; 299516e329aeSVivien Didelot 2996b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = { 29974b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 2998b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2999b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3000b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 300108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 30027f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 300394d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 300496a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3005ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 300656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3007601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 300856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3009cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3010ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 30110898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3012c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 30139dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 3014a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 3015dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3016dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3017052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3018fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3019fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3020fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 30216e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 302217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3023f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 30240ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3025b3469dd8SVivien Didelot }; 3026b3469dd8SVivien Didelot 3027b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = { 30284b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 3029b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3030b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3031b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 303208ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 30337f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 303494d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 303596a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3036ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 303756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3038601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 303956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3040cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3041ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 30420898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3043c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 30449dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 3045a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 3046dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3047dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3048052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3049fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3050fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3051fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 30526e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 305317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3054f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 30550ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3056b3469dd8SVivien Didelot }; 3057b3469dd8SVivien Didelot 3058b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = { 30594b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 3060ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3061ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3062b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3063b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3064b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 306508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 30667f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3067a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 306896a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 3069ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 307056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3071601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 307256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3073cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3074ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 30750898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3076c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 30779dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 3078a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 3079dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3080dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3081052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3082fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3083fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3084fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 30856e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, 308617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3087f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 30880ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 30896d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 3090b3469dd8SVivien Didelot }; 3091b3469dd8SVivien Didelot 30921a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = { 30934b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 309498fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 309598fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 30961a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 30971a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 30981a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 30991a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 31001a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 31011a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 31021a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 3103ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 310456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3105601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 310656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3107cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3108ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 31090898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3110f39908d3SAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 3111c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 31129dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 311379523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3114de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3115dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3116dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3117e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3118fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3119fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 312061303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 31216e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 312217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3123931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3124931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 31256335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 31261a3b39ecSAndrew Lunn }; 31271a3b39ecSAndrew Lunn 31281a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = { 31294b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 313098fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 313198fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 31321a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 31331a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 31341a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 31351a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 31361a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 31371a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 31381a3b39ecSAndrew Lunn .port_set_speed = mv88e6390x_port_set_speed, 3139ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 314056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3141601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 314256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3143cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3144ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 31450898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3146c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 31479dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 314879523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3149de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3150dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3151dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3152e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3153fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3154fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 315561303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 31566e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 315717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3158931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3159931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 31606335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 31611a3b39ecSAndrew Lunn }; 31621a3b39ecSAndrew Lunn 3163fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = { 3164fad09c73SVivien Didelot [MV88E6085] = { 3165107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085, 3166fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6097, 3167fad09c73SVivien Didelot .name = "Marvell 88E6085", 3168fad09c73SVivien Didelot .num_databases = 4096, 3169fad09c73SVivien Didelot .num_ports = 10, 31703cf3c846SVivien Didelot .max_vid = 4095, 3171fad09c73SVivien Didelot .port_base_addr = 0x10, 3172a935c052SVivien Didelot .global1_addr = 0x1b, 3173acddbd21SVivien Didelot .age_time_coeff = 15000, 3174dc30c35bSAndrew Lunn .g1_irqs = 8, 3175e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3176f3645652SVivien Didelot .pvt = true, 3177443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3178fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6097, 3179b3469dd8SVivien Didelot .ops = &mv88e6085_ops, 3180fad09c73SVivien Didelot }, 3181fad09c73SVivien Didelot 3182fad09c73SVivien Didelot [MV88E6095] = { 3183107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095, 3184fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6095, 3185fad09c73SVivien Didelot .name = "Marvell 88E6095/88E6095F", 3186fad09c73SVivien Didelot .num_databases = 256, 3187fad09c73SVivien Didelot .num_ports = 11, 31883cf3c846SVivien Didelot .max_vid = 4095, 3189fad09c73SVivien Didelot .port_base_addr = 0x10, 3190a935c052SVivien Didelot .global1_addr = 0x1b, 3191acddbd21SVivien Didelot .age_time_coeff = 15000, 3192dc30c35bSAndrew Lunn .g1_irqs = 8, 3193e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3194443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3195fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6095, 3196b3469dd8SVivien Didelot .ops = &mv88e6095_ops, 3197fad09c73SVivien Didelot }, 3198fad09c73SVivien Didelot 31997d381a02SStefan Eichenberger [MV88E6097] = { 3200107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097, 32017d381a02SStefan Eichenberger .family = MV88E6XXX_FAMILY_6097, 32027d381a02SStefan Eichenberger .name = "Marvell 88E6097/88E6097F", 32037d381a02SStefan Eichenberger .num_databases = 4096, 32047d381a02SStefan Eichenberger .num_ports = 11, 32053cf3c846SVivien Didelot .max_vid = 4095, 32067d381a02SStefan Eichenberger .port_base_addr = 0x10, 32077d381a02SStefan Eichenberger .global1_addr = 0x1b, 32087d381a02SStefan Eichenberger .age_time_coeff = 15000, 3209c534178bSStefan Eichenberger .g1_irqs = 8, 3210e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3211f3645652SVivien Didelot .pvt = true, 32122bfcfcd3SStefan Eichenberger .tag_protocol = DSA_TAG_PROTO_EDSA, 32137d381a02SStefan Eichenberger .flags = MV88E6XXX_FLAGS_FAMILY_6097, 32147d381a02SStefan Eichenberger .ops = &mv88e6097_ops, 32157d381a02SStefan Eichenberger }, 32167d381a02SStefan Eichenberger 3217fad09c73SVivien Didelot [MV88E6123] = { 3218107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123, 3219fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 3220fad09c73SVivien Didelot .name = "Marvell 88E6123", 3221fad09c73SVivien Didelot .num_databases = 4096, 3222fad09c73SVivien Didelot .num_ports = 3, 32233cf3c846SVivien Didelot .max_vid = 4095, 3224fad09c73SVivien Didelot .port_base_addr = 0x10, 3225a935c052SVivien Didelot .global1_addr = 0x1b, 3226acddbd21SVivien Didelot .age_time_coeff = 15000, 3227dc30c35bSAndrew Lunn .g1_irqs = 9, 3228e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3229f3645652SVivien Didelot .pvt = true, 32305ebe31d7SAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3231fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6165, 3232b3469dd8SVivien Didelot .ops = &mv88e6123_ops, 3233fad09c73SVivien Didelot }, 3234fad09c73SVivien Didelot 3235fad09c73SVivien Didelot [MV88E6131] = { 3236107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131, 3237fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 3238fad09c73SVivien Didelot .name = "Marvell 88E6131", 3239fad09c73SVivien Didelot .num_databases = 256, 3240fad09c73SVivien Didelot .num_ports = 8, 32413cf3c846SVivien Didelot .max_vid = 4095, 3242fad09c73SVivien Didelot .port_base_addr = 0x10, 3243a935c052SVivien Didelot .global1_addr = 0x1b, 3244acddbd21SVivien Didelot .age_time_coeff = 15000, 3245dc30c35bSAndrew Lunn .g1_irqs = 9, 3246e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3247443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3248fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6185, 3249b3469dd8SVivien Didelot .ops = &mv88e6131_ops, 3250fad09c73SVivien Didelot }, 3251fad09c73SVivien Didelot 3252990e27b0SVivien Didelot [MV88E6141] = { 3253107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141, 3254990e27b0SVivien Didelot .family = MV88E6XXX_FAMILY_6341, 3255990e27b0SVivien Didelot .name = "Marvell 88E6341", 3256990e27b0SVivien Didelot .num_databases = 4096, 3257990e27b0SVivien Didelot .num_ports = 6, 32583cf3c846SVivien Didelot .max_vid = 4095, 3259990e27b0SVivien Didelot .port_base_addr = 0x10, 3260990e27b0SVivien Didelot .global1_addr = 0x1b, 3261990e27b0SVivien Didelot .age_time_coeff = 3750, 3262990e27b0SVivien Didelot .atu_move_port_mask = 0x1f, 3263f3645652SVivien Didelot .pvt = true, 3264990e27b0SVivien Didelot .tag_protocol = DSA_TAG_PROTO_EDSA, 3265990e27b0SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6341, 3266990e27b0SVivien Didelot .ops = &mv88e6141_ops, 3267990e27b0SVivien Didelot }, 3268990e27b0SVivien Didelot 3269fad09c73SVivien Didelot [MV88E6161] = { 3270107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161, 3271fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 3272fad09c73SVivien Didelot .name = "Marvell 88E6161", 3273fad09c73SVivien Didelot .num_databases = 4096, 3274fad09c73SVivien Didelot .num_ports = 6, 32753cf3c846SVivien Didelot .max_vid = 4095, 3276fad09c73SVivien Didelot .port_base_addr = 0x10, 3277a935c052SVivien Didelot .global1_addr = 0x1b, 3278acddbd21SVivien Didelot .age_time_coeff = 15000, 3279dc30c35bSAndrew Lunn .g1_irqs = 9, 3280e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3281f3645652SVivien Didelot .pvt = true, 32825ebe31d7SAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3283fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6165, 3284b3469dd8SVivien Didelot .ops = &mv88e6161_ops, 3285fad09c73SVivien Didelot }, 3286fad09c73SVivien Didelot 3287fad09c73SVivien Didelot [MV88E6165] = { 3288107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165, 3289fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 3290fad09c73SVivien Didelot .name = "Marvell 88E6165", 3291fad09c73SVivien Didelot .num_databases = 4096, 3292fad09c73SVivien Didelot .num_ports = 6, 32933cf3c846SVivien Didelot .max_vid = 4095, 3294fad09c73SVivien Didelot .port_base_addr = 0x10, 3295a935c052SVivien Didelot .global1_addr = 0x1b, 3296acddbd21SVivien Didelot .age_time_coeff = 15000, 3297dc30c35bSAndrew Lunn .g1_irqs = 9, 3298e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3299f3645652SVivien Didelot .pvt = true, 3300443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3301fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6165, 3302b3469dd8SVivien Didelot .ops = &mv88e6165_ops, 3303fad09c73SVivien Didelot }, 3304fad09c73SVivien Didelot 3305fad09c73SVivien Didelot [MV88E6171] = { 3306107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171, 3307fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 3308fad09c73SVivien Didelot .name = "Marvell 88E6171", 3309fad09c73SVivien Didelot .num_databases = 4096, 3310fad09c73SVivien Didelot .num_ports = 7, 33113cf3c846SVivien Didelot .max_vid = 4095, 3312fad09c73SVivien Didelot .port_base_addr = 0x10, 3313a935c052SVivien Didelot .global1_addr = 0x1b, 3314acddbd21SVivien Didelot .age_time_coeff = 15000, 3315dc30c35bSAndrew Lunn .g1_irqs = 9, 3316e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3317f3645652SVivien Didelot .pvt = true, 3318443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3319fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6351, 3320b3469dd8SVivien Didelot .ops = &mv88e6171_ops, 3321fad09c73SVivien Didelot }, 3322fad09c73SVivien Didelot 3323fad09c73SVivien Didelot [MV88E6172] = { 3324107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172, 3325fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 3326fad09c73SVivien Didelot .name = "Marvell 88E6172", 3327fad09c73SVivien Didelot .num_databases = 4096, 3328fad09c73SVivien Didelot .num_ports = 7, 33293cf3c846SVivien Didelot .max_vid = 4095, 3330fad09c73SVivien Didelot .port_base_addr = 0x10, 3331a935c052SVivien Didelot .global1_addr = 0x1b, 3332acddbd21SVivien Didelot .age_time_coeff = 15000, 3333dc30c35bSAndrew Lunn .g1_irqs = 9, 3334e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3335f3645652SVivien Didelot .pvt = true, 3336443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3337fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6352, 3338b3469dd8SVivien Didelot .ops = &mv88e6172_ops, 3339fad09c73SVivien Didelot }, 3340fad09c73SVivien Didelot 3341fad09c73SVivien Didelot [MV88E6175] = { 3342107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175, 3343fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 3344fad09c73SVivien Didelot .name = "Marvell 88E6175", 3345fad09c73SVivien Didelot .num_databases = 4096, 3346fad09c73SVivien Didelot .num_ports = 7, 33473cf3c846SVivien Didelot .max_vid = 4095, 3348fad09c73SVivien Didelot .port_base_addr = 0x10, 3349a935c052SVivien Didelot .global1_addr = 0x1b, 3350acddbd21SVivien Didelot .age_time_coeff = 15000, 3351dc30c35bSAndrew Lunn .g1_irqs = 9, 3352e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3353f3645652SVivien Didelot .pvt = true, 3354443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3355fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6351, 3356b3469dd8SVivien Didelot .ops = &mv88e6175_ops, 3357fad09c73SVivien Didelot }, 3358fad09c73SVivien Didelot 3359fad09c73SVivien Didelot [MV88E6176] = { 3360107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176, 3361fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 3362fad09c73SVivien Didelot .name = "Marvell 88E6176", 3363fad09c73SVivien Didelot .num_databases = 4096, 3364fad09c73SVivien Didelot .num_ports = 7, 33653cf3c846SVivien Didelot .max_vid = 4095, 3366fad09c73SVivien Didelot .port_base_addr = 0x10, 3367a935c052SVivien Didelot .global1_addr = 0x1b, 3368acddbd21SVivien Didelot .age_time_coeff = 15000, 3369dc30c35bSAndrew Lunn .g1_irqs = 9, 3370e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3371f3645652SVivien Didelot .pvt = true, 3372443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3373fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6352, 3374b3469dd8SVivien Didelot .ops = &mv88e6176_ops, 3375fad09c73SVivien Didelot }, 3376fad09c73SVivien Didelot 3377fad09c73SVivien Didelot [MV88E6185] = { 3378107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185, 3379fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 3380fad09c73SVivien Didelot .name = "Marvell 88E6185", 3381fad09c73SVivien Didelot .num_databases = 256, 3382fad09c73SVivien Didelot .num_ports = 10, 33833cf3c846SVivien Didelot .max_vid = 4095, 3384fad09c73SVivien Didelot .port_base_addr = 0x10, 3385a935c052SVivien Didelot .global1_addr = 0x1b, 3386acddbd21SVivien Didelot .age_time_coeff = 15000, 3387dc30c35bSAndrew Lunn .g1_irqs = 8, 3388e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3389443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3390fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6185, 3391b3469dd8SVivien Didelot .ops = &mv88e6185_ops, 3392fad09c73SVivien Didelot }, 3393fad09c73SVivien Didelot 33941a3b39ecSAndrew Lunn [MV88E6190] = { 3395107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190, 33961a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 33971a3b39ecSAndrew Lunn .name = "Marvell 88E6190", 33981a3b39ecSAndrew Lunn .num_databases = 4096, 33991a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 3400931d1822SVivien Didelot .max_vid = 8191, 34011a3b39ecSAndrew Lunn .port_base_addr = 0x0, 34021a3b39ecSAndrew Lunn .global1_addr = 0x1b, 3403443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3404b91e055cSAndrew Lunn .age_time_coeff = 3750, 34051a3b39ecSAndrew Lunn .g1_irqs = 9, 3406f3645652SVivien Didelot .pvt = true, 3407e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 34081a3b39ecSAndrew Lunn .flags = MV88E6XXX_FLAGS_FAMILY_6390, 34091a3b39ecSAndrew Lunn .ops = &mv88e6190_ops, 34101a3b39ecSAndrew Lunn }, 34111a3b39ecSAndrew Lunn 34121a3b39ecSAndrew Lunn [MV88E6190X] = { 3413107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X, 34141a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 34151a3b39ecSAndrew Lunn .name = "Marvell 88E6190X", 34161a3b39ecSAndrew Lunn .num_databases = 4096, 34171a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 3418931d1822SVivien Didelot .max_vid = 8191, 34191a3b39ecSAndrew Lunn .port_base_addr = 0x0, 34201a3b39ecSAndrew Lunn .global1_addr = 0x1b, 3421b91e055cSAndrew Lunn .age_time_coeff = 3750, 34221a3b39ecSAndrew Lunn .g1_irqs = 9, 3423e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 3424f3645652SVivien Didelot .pvt = true, 3425443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 34261a3b39ecSAndrew Lunn .flags = MV88E6XXX_FLAGS_FAMILY_6390, 34271a3b39ecSAndrew Lunn .ops = &mv88e6190x_ops, 34281a3b39ecSAndrew Lunn }, 34291a3b39ecSAndrew Lunn 34301a3b39ecSAndrew Lunn [MV88E6191] = { 3431107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191, 34321a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 34331a3b39ecSAndrew Lunn .name = "Marvell 88E6191", 34341a3b39ecSAndrew Lunn .num_databases = 4096, 34351a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 3436931d1822SVivien Didelot .max_vid = 8191, 34371a3b39ecSAndrew Lunn .port_base_addr = 0x0, 34381a3b39ecSAndrew Lunn .global1_addr = 0x1b, 3439b91e055cSAndrew Lunn .age_time_coeff = 3750, 3440443d5a1bSAndrew Lunn .g1_irqs = 9, 3441e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 3442f3645652SVivien Didelot .pvt = true, 3443443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 34441a3b39ecSAndrew Lunn .flags = MV88E6XXX_FLAGS_FAMILY_6390, 34452cf4cefbSVivien Didelot .ops = &mv88e6191_ops, 34461a3b39ecSAndrew Lunn }, 34471a3b39ecSAndrew Lunn 3448fad09c73SVivien Didelot [MV88E6240] = { 3449107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240, 3450fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 3451fad09c73SVivien Didelot .name = "Marvell 88E6240", 3452fad09c73SVivien Didelot .num_databases = 4096, 3453fad09c73SVivien Didelot .num_ports = 7, 34543cf3c846SVivien Didelot .max_vid = 4095, 3455fad09c73SVivien Didelot .port_base_addr = 0x10, 3456a935c052SVivien Didelot .global1_addr = 0x1b, 3457acddbd21SVivien Didelot .age_time_coeff = 15000, 3458dc30c35bSAndrew Lunn .g1_irqs = 9, 3459e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3460f3645652SVivien Didelot .pvt = true, 3461443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3462fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6352, 3463b3469dd8SVivien Didelot .ops = &mv88e6240_ops, 3464fad09c73SVivien Didelot }, 3465fad09c73SVivien Didelot 34661a3b39ecSAndrew Lunn [MV88E6290] = { 3467107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290, 34681a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 34691a3b39ecSAndrew Lunn .name = "Marvell 88E6290", 34701a3b39ecSAndrew Lunn .num_databases = 4096, 34711a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 3472931d1822SVivien Didelot .max_vid = 8191, 34731a3b39ecSAndrew Lunn .port_base_addr = 0x0, 34741a3b39ecSAndrew Lunn .global1_addr = 0x1b, 3475b91e055cSAndrew Lunn .age_time_coeff = 3750, 34761a3b39ecSAndrew Lunn .g1_irqs = 9, 3477e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 3478f3645652SVivien Didelot .pvt = true, 3479443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 34801a3b39ecSAndrew Lunn .flags = MV88E6XXX_FLAGS_FAMILY_6390, 34811a3b39ecSAndrew Lunn .ops = &mv88e6290_ops, 34821a3b39ecSAndrew Lunn }, 34831a3b39ecSAndrew Lunn 3484fad09c73SVivien Didelot [MV88E6320] = { 3485107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320, 3486fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 3487fad09c73SVivien Didelot .name = "Marvell 88E6320", 3488fad09c73SVivien Didelot .num_databases = 4096, 3489fad09c73SVivien Didelot .num_ports = 7, 34903cf3c846SVivien Didelot .max_vid = 4095, 3491fad09c73SVivien Didelot .port_base_addr = 0x10, 3492a935c052SVivien Didelot .global1_addr = 0x1b, 3493acddbd21SVivien Didelot .age_time_coeff = 15000, 3494dc30c35bSAndrew Lunn .g1_irqs = 8, 3495e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3496f3645652SVivien Didelot .pvt = true, 3497443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3498fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6320, 3499b3469dd8SVivien Didelot .ops = &mv88e6320_ops, 3500fad09c73SVivien Didelot }, 3501fad09c73SVivien Didelot 3502fad09c73SVivien Didelot [MV88E6321] = { 3503107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321, 3504fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 3505fad09c73SVivien Didelot .name = "Marvell 88E6321", 3506fad09c73SVivien Didelot .num_databases = 4096, 3507fad09c73SVivien Didelot .num_ports = 7, 35083cf3c846SVivien Didelot .max_vid = 4095, 3509fad09c73SVivien Didelot .port_base_addr = 0x10, 3510a935c052SVivien Didelot .global1_addr = 0x1b, 3511acddbd21SVivien Didelot .age_time_coeff = 15000, 3512dc30c35bSAndrew Lunn .g1_irqs = 8, 3513e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3514443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3515fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6320, 3516b3469dd8SVivien Didelot .ops = &mv88e6321_ops, 3517fad09c73SVivien Didelot }, 3518fad09c73SVivien Didelot 3519a75961d0SGregory CLEMENT [MV88E6341] = { 3520107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, 3521a75961d0SGregory CLEMENT .family = MV88E6XXX_FAMILY_6341, 3522a75961d0SGregory CLEMENT .name = "Marvell 88E6341", 3523a75961d0SGregory CLEMENT .num_databases = 4096, 3524a75961d0SGregory CLEMENT .num_ports = 6, 35253cf3c846SVivien Didelot .max_vid = 4095, 3526a75961d0SGregory CLEMENT .port_base_addr = 0x10, 3527a75961d0SGregory CLEMENT .global1_addr = 0x1b, 3528a75961d0SGregory CLEMENT .age_time_coeff = 3750, 3529e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 3530f3645652SVivien Didelot .pvt = true, 3531a75961d0SGregory CLEMENT .tag_protocol = DSA_TAG_PROTO_EDSA, 3532a75961d0SGregory CLEMENT .flags = MV88E6XXX_FLAGS_FAMILY_6341, 3533a75961d0SGregory CLEMENT .ops = &mv88e6341_ops, 3534a75961d0SGregory CLEMENT }, 3535a75961d0SGregory CLEMENT 3536fad09c73SVivien Didelot [MV88E6350] = { 3537107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350, 3538fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 3539fad09c73SVivien Didelot .name = "Marvell 88E6350", 3540fad09c73SVivien Didelot .num_databases = 4096, 3541fad09c73SVivien Didelot .num_ports = 7, 35423cf3c846SVivien Didelot .max_vid = 4095, 3543fad09c73SVivien Didelot .port_base_addr = 0x10, 3544a935c052SVivien Didelot .global1_addr = 0x1b, 3545acddbd21SVivien Didelot .age_time_coeff = 15000, 3546dc30c35bSAndrew Lunn .g1_irqs = 9, 3547e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3548f3645652SVivien Didelot .pvt = true, 3549443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3550fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6351, 3551b3469dd8SVivien Didelot .ops = &mv88e6350_ops, 3552fad09c73SVivien Didelot }, 3553fad09c73SVivien Didelot 3554fad09c73SVivien Didelot [MV88E6351] = { 3555107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351, 3556fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 3557fad09c73SVivien Didelot .name = "Marvell 88E6351", 3558fad09c73SVivien Didelot .num_databases = 4096, 3559fad09c73SVivien Didelot .num_ports = 7, 35603cf3c846SVivien Didelot .max_vid = 4095, 3561fad09c73SVivien Didelot .port_base_addr = 0x10, 3562a935c052SVivien Didelot .global1_addr = 0x1b, 3563acddbd21SVivien Didelot .age_time_coeff = 15000, 3564dc30c35bSAndrew Lunn .g1_irqs = 9, 3565e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3566f3645652SVivien Didelot .pvt = true, 3567443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3568fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6351, 3569b3469dd8SVivien Didelot .ops = &mv88e6351_ops, 3570fad09c73SVivien Didelot }, 3571fad09c73SVivien Didelot 3572fad09c73SVivien Didelot [MV88E6352] = { 3573107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352, 3574fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 3575fad09c73SVivien Didelot .name = "Marvell 88E6352", 3576fad09c73SVivien Didelot .num_databases = 4096, 3577fad09c73SVivien Didelot .num_ports = 7, 35783cf3c846SVivien Didelot .max_vid = 4095, 3579fad09c73SVivien Didelot .port_base_addr = 0x10, 3580a935c052SVivien Didelot .global1_addr = 0x1b, 3581acddbd21SVivien Didelot .age_time_coeff = 15000, 3582dc30c35bSAndrew Lunn .g1_irqs = 9, 3583e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3584f3645652SVivien Didelot .pvt = true, 3585443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3586fad09c73SVivien Didelot .flags = MV88E6XXX_FLAGS_FAMILY_6352, 3587b3469dd8SVivien Didelot .ops = &mv88e6352_ops, 3588fad09c73SVivien Didelot }, 35891a3b39ecSAndrew Lunn [MV88E6390] = { 3590107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, 35911a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 35921a3b39ecSAndrew Lunn .name = "Marvell 88E6390", 35931a3b39ecSAndrew Lunn .num_databases = 4096, 35941a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 3595931d1822SVivien Didelot .max_vid = 8191, 35961a3b39ecSAndrew Lunn .port_base_addr = 0x0, 35971a3b39ecSAndrew Lunn .global1_addr = 0x1b, 3598b91e055cSAndrew Lunn .age_time_coeff = 3750, 35991a3b39ecSAndrew Lunn .g1_irqs = 9, 3600e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 3601f3645652SVivien Didelot .pvt = true, 3602443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 36031a3b39ecSAndrew Lunn .flags = MV88E6XXX_FLAGS_FAMILY_6390, 36041a3b39ecSAndrew Lunn .ops = &mv88e6390_ops, 36051a3b39ecSAndrew Lunn }, 36061a3b39ecSAndrew Lunn [MV88E6390X] = { 3607107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X, 36081a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 36091a3b39ecSAndrew Lunn .name = "Marvell 88E6390X", 36101a3b39ecSAndrew Lunn .num_databases = 4096, 36111a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 3612931d1822SVivien Didelot .max_vid = 8191, 36131a3b39ecSAndrew Lunn .port_base_addr = 0x0, 36141a3b39ecSAndrew Lunn .global1_addr = 0x1b, 3615b91e055cSAndrew Lunn .age_time_coeff = 3750, 36161a3b39ecSAndrew Lunn .g1_irqs = 9, 3617e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 3618f3645652SVivien Didelot .pvt = true, 3619443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 36201a3b39ecSAndrew Lunn .flags = MV88E6XXX_FLAGS_FAMILY_6390, 36211a3b39ecSAndrew Lunn .ops = &mv88e6390x_ops, 36221a3b39ecSAndrew Lunn }, 3623fad09c73SVivien Didelot }; 3624fad09c73SVivien Didelot 3625fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) 3626fad09c73SVivien Didelot { 3627fad09c73SVivien Didelot int i; 3628fad09c73SVivien Didelot 3629fad09c73SVivien Didelot for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i) 3630fad09c73SVivien Didelot if (mv88e6xxx_table[i].prod_num == prod_num) 3631fad09c73SVivien Didelot return &mv88e6xxx_table[i]; 3632fad09c73SVivien Didelot 3633fad09c73SVivien Didelot return NULL; 3634fad09c73SVivien Didelot } 3635fad09c73SVivien Didelot 3636fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip) 3637fad09c73SVivien Didelot { 3638fad09c73SVivien Didelot const struct mv88e6xxx_info *info; 36398f6345b2SVivien Didelot unsigned int prod_num, rev; 36408f6345b2SVivien Didelot u16 id; 36418f6345b2SVivien Didelot int err; 3642fad09c73SVivien Didelot 36438f6345b2SVivien Didelot mutex_lock(&chip->reg_lock); 3644107fcc10SVivien Didelot err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id); 36458f6345b2SVivien Didelot mutex_unlock(&chip->reg_lock); 36468f6345b2SVivien Didelot if (err) 36478f6345b2SVivien Didelot return err; 3648fad09c73SVivien Didelot 3649107fcc10SVivien Didelot prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK; 3650107fcc10SVivien Didelot rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK; 3651fad09c73SVivien Didelot 3652fad09c73SVivien Didelot info = mv88e6xxx_lookup_info(prod_num); 3653fad09c73SVivien Didelot if (!info) 3654fad09c73SVivien Didelot return -ENODEV; 3655fad09c73SVivien Didelot 3656fad09c73SVivien Didelot /* Update the compatible info with the probed one */ 3657fad09c73SVivien Didelot chip->info = info; 3658fad09c73SVivien Didelot 3659ca070c10SVivien Didelot err = mv88e6xxx_g2_require(chip); 3660ca070c10SVivien Didelot if (err) 3661ca070c10SVivien Didelot return err; 3662ca070c10SVivien Didelot 3663fad09c73SVivien Didelot dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n", 3664fad09c73SVivien Didelot chip->info->prod_num, chip->info->name, rev); 3665fad09c73SVivien Didelot 3666fad09c73SVivien Didelot return 0; 3667fad09c73SVivien Didelot } 3668fad09c73SVivien Didelot 3669fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) 3670fad09c73SVivien Didelot { 3671fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 3672fad09c73SVivien Didelot 3673fad09c73SVivien Didelot chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 3674fad09c73SVivien Didelot if (!chip) 3675fad09c73SVivien Didelot return NULL; 3676fad09c73SVivien Didelot 3677fad09c73SVivien Didelot chip->dev = dev; 3678fad09c73SVivien Didelot 3679fad09c73SVivien Didelot mutex_init(&chip->reg_lock); 3680a3c53be5SAndrew Lunn INIT_LIST_HEAD(&chip->mdios); 3681fad09c73SVivien Didelot 3682fad09c73SVivien Didelot return chip; 3683fad09c73SVivien Didelot } 3684fad09c73SVivien Didelot 3685fad09c73SVivien Didelot static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip, 3686fad09c73SVivien Didelot struct mii_bus *bus, int sw_addr) 3687fad09c73SVivien Didelot { 3688fad09c73SVivien Didelot if (sw_addr == 0) 3689fad09c73SVivien Didelot chip->smi_ops = &mv88e6xxx_smi_single_chip_ops; 3690a0ffff24SVivien Didelot else if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_MULTI_CHIP)) 3691fad09c73SVivien Didelot chip->smi_ops = &mv88e6xxx_smi_multi_chip_ops; 3692fad09c73SVivien Didelot else 3693fad09c73SVivien Didelot return -EINVAL; 3694fad09c73SVivien Didelot 3695fad09c73SVivien Didelot chip->bus = bus; 3696fad09c73SVivien Didelot chip->sw_addr = sw_addr; 3697fad09c73SVivien Didelot 3698fad09c73SVivien Didelot return 0; 3699fad09c73SVivien Didelot } 3700fad09c73SVivien Didelot 37017b314362SAndrew Lunn static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds) 37027b314362SAndrew Lunn { 370304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 37042bbb33beSAndrew Lunn 3705443d5a1bSAndrew Lunn return chip->info->tag_protocol; 37067b314362SAndrew Lunn } 37077b314362SAndrew Lunn 3708fad09c73SVivien Didelot static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, 3709fad09c73SVivien Didelot struct device *host_dev, int sw_addr, 3710fad09c73SVivien Didelot void **priv) 3711fad09c73SVivien Didelot { 3712fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 3713fad09c73SVivien Didelot struct mii_bus *bus; 3714fad09c73SVivien Didelot int err; 3715fad09c73SVivien Didelot 3716fad09c73SVivien Didelot bus = dsa_host_dev_to_mii_bus(host_dev); 3717fad09c73SVivien Didelot if (!bus) 3718fad09c73SVivien Didelot return NULL; 3719fad09c73SVivien Didelot 3720fad09c73SVivien Didelot chip = mv88e6xxx_alloc_chip(dsa_dev); 3721fad09c73SVivien Didelot if (!chip) 3722fad09c73SVivien Didelot return NULL; 3723fad09c73SVivien Didelot 3724fad09c73SVivien Didelot /* Legacy SMI probing will only support chips similar to 88E6085 */ 3725fad09c73SVivien Didelot chip->info = &mv88e6xxx_table[MV88E6085]; 3726fad09c73SVivien Didelot 3727fad09c73SVivien Didelot err = mv88e6xxx_smi_init(chip, bus, sw_addr); 3728fad09c73SVivien Didelot if (err) 3729fad09c73SVivien Didelot goto free; 3730fad09c73SVivien Didelot 3731fad09c73SVivien Didelot err = mv88e6xxx_detect(chip); 3732fad09c73SVivien Didelot if (err) 3733fad09c73SVivien Didelot goto free; 3734fad09c73SVivien Didelot 3735dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 3736dc30c35bSAndrew Lunn err = mv88e6xxx_switch_reset(chip); 3737dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 3738dc30c35bSAndrew Lunn if (err) 3739dc30c35bSAndrew Lunn goto free; 3740dc30c35bSAndrew Lunn 3741e57e5e77SVivien Didelot mv88e6xxx_phy_init(chip); 3742e57e5e77SVivien Didelot 3743a3c53be5SAndrew Lunn err = mv88e6xxx_mdios_register(chip, NULL); 3744fad09c73SVivien Didelot if (err) 3745fad09c73SVivien Didelot goto free; 3746fad09c73SVivien Didelot 3747fad09c73SVivien Didelot *priv = chip; 3748fad09c73SVivien Didelot 3749fad09c73SVivien Didelot return chip->info->name; 3750fad09c73SVivien Didelot free: 3751fad09c73SVivien Didelot devm_kfree(dsa_dev, chip); 3752fad09c73SVivien Didelot 3753fad09c73SVivien Didelot return NULL; 3754fad09c73SVivien Didelot } 3755fad09c73SVivien Didelot 37567df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port, 37577df8fbddSVivien Didelot const struct switchdev_obj_port_mdb *mdb, 37587df8fbddSVivien Didelot struct switchdev_trans *trans) 37597df8fbddSVivien Didelot { 37607df8fbddSVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 37617df8fbddSVivien Didelot * so skip the prepare phase. 37627df8fbddSVivien Didelot */ 37637df8fbddSVivien Didelot 37647df8fbddSVivien Didelot return 0; 37657df8fbddSVivien Didelot } 37667df8fbddSVivien Didelot 37677df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port, 37687df8fbddSVivien Didelot const struct switchdev_obj_port_mdb *mdb, 37697df8fbddSVivien Didelot struct switchdev_trans *trans) 37707df8fbddSVivien Didelot { 377104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 37727df8fbddSVivien Didelot 37737df8fbddSVivien Didelot mutex_lock(&chip->reg_lock); 37747df8fbddSVivien Didelot if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 37757df8fbddSVivien Didelot GLOBAL_ATU_DATA_STATE_MC_STATIC)) 3776774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to load multicast MAC address\n", 3777774439e5SVivien Didelot port); 37787df8fbddSVivien Didelot mutex_unlock(&chip->reg_lock); 37797df8fbddSVivien Didelot } 37807df8fbddSVivien Didelot 37817df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, 37827df8fbddSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 37837df8fbddSVivien Didelot { 378404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 37857df8fbddSVivien Didelot int err; 37867df8fbddSVivien Didelot 37877df8fbddSVivien Didelot mutex_lock(&chip->reg_lock); 37887df8fbddSVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 37897df8fbddSVivien Didelot GLOBAL_ATU_DATA_STATE_UNUSED); 37907df8fbddSVivien Didelot mutex_unlock(&chip->reg_lock); 37917df8fbddSVivien Didelot 37927df8fbddSVivien Didelot return err; 37937df8fbddSVivien Didelot } 37947df8fbddSVivien Didelot 37957df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_dump(struct dsa_switch *ds, int port, 37967df8fbddSVivien Didelot struct switchdev_obj_port_mdb *mdb, 3797438ff537SVivien Didelot switchdev_obj_dump_cb_t *cb) 37987df8fbddSVivien Didelot { 379904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 38007df8fbddSVivien Didelot int err; 38017df8fbddSVivien Didelot 38027df8fbddSVivien Didelot mutex_lock(&chip->reg_lock); 38037df8fbddSVivien Didelot err = mv88e6xxx_port_db_dump(chip, port, &mdb->obj, cb); 38047df8fbddSVivien Didelot mutex_unlock(&chip->reg_lock); 38057df8fbddSVivien Didelot 38067df8fbddSVivien Didelot return err; 38077df8fbddSVivien Didelot } 38087df8fbddSVivien Didelot 3809a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = { 3810fad09c73SVivien Didelot .probe = mv88e6xxx_drv_probe, 38117b314362SAndrew Lunn .get_tag_protocol = mv88e6xxx_get_tag_protocol, 3812fad09c73SVivien Didelot .setup = mv88e6xxx_setup, 3813fad09c73SVivien Didelot .set_addr = mv88e6xxx_set_addr, 3814fad09c73SVivien Didelot .adjust_link = mv88e6xxx_adjust_link, 3815fad09c73SVivien Didelot .get_strings = mv88e6xxx_get_strings, 3816fad09c73SVivien Didelot .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, 3817fad09c73SVivien Didelot .get_sset_count = mv88e6xxx_get_sset_count, 381804aca993SAndrew Lunn .port_enable = mv88e6xxx_port_enable, 381904aca993SAndrew Lunn .port_disable = mv88e6xxx_port_disable, 3820fad09c73SVivien Didelot .set_eee = mv88e6xxx_set_eee, 3821fad09c73SVivien Didelot .get_eee = mv88e6xxx_get_eee, 3822fad09c73SVivien Didelot .get_eeprom_len = mv88e6xxx_get_eeprom_len, 3823fad09c73SVivien Didelot .get_eeprom = mv88e6xxx_get_eeprom, 3824fad09c73SVivien Didelot .set_eeprom = mv88e6xxx_set_eeprom, 3825fad09c73SVivien Didelot .get_regs_len = mv88e6xxx_get_regs_len, 3826fad09c73SVivien Didelot .get_regs = mv88e6xxx_get_regs, 38272cfcd964SVivien Didelot .set_ageing_time = mv88e6xxx_set_ageing_time, 3828fad09c73SVivien Didelot .port_bridge_join = mv88e6xxx_port_bridge_join, 3829fad09c73SVivien Didelot .port_bridge_leave = mv88e6xxx_port_bridge_leave, 3830fad09c73SVivien Didelot .port_stp_state_set = mv88e6xxx_port_stp_state_set, 3831749efcb8SVivien Didelot .port_fast_age = mv88e6xxx_port_fast_age, 3832fad09c73SVivien Didelot .port_vlan_filtering = mv88e6xxx_port_vlan_filtering, 3833fad09c73SVivien Didelot .port_vlan_prepare = mv88e6xxx_port_vlan_prepare, 3834fad09c73SVivien Didelot .port_vlan_add = mv88e6xxx_port_vlan_add, 3835fad09c73SVivien Didelot .port_vlan_del = mv88e6xxx_port_vlan_del, 3836fad09c73SVivien Didelot .port_vlan_dump = mv88e6xxx_port_vlan_dump, 3837fad09c73SVivien Didelot .port_fdb_prepare = mv88e6xxx_port_fdb_prepare, 3838fad09c73SVivien Didelot .port_fdb_add = mv88e6xxx_port_fdb_add, 3839fad09c73SVivien Didelot .port_fdb_del = mv88e6xxx_port_fdb_del, 3840fad09c73SVivien Didelot .port_fdb_dump = mv88e6xxx_port_fdb_dump, 38417df8fbddSVivien Didelot .port_mdb_prepare = mv88e6xxx_port_mdb_prepare, 38427df8fbddSVivien Didelot .port_mdb_add = mv88e6xxx_port_mdb_add, 38437df8fbddSVivien Didelot .port_mdb_del = mv88e6xxx_port_mdb_del, 38447df8fbddSVivien Didelot .port_mdb_dump = mv88e6xxx_port_mdb_dump, 3845aec5ac88SVivien Didelot .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join, 3846aec5ac88SVivien Didelot .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave, 3847fad09c73SVivien Didelot }; 3848fad09c73SVivien Didelot 3849ab3d408dSFlorian Fainelli static struct dsa_switch_driver mv88e6xxx_switch_drv = { 3850ab3d408dSFlorian Fainelli .ops = &mv88e6xxx_switch_ops, 3851ab3d408dSFlorian Fainelli }; 3852ab3d408dSFlorian Fainelli 385355ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) 3854fad09c73SVivien Didelot { 3855fad09c73SVivien Didelot struct device *dev = chip->dev; 3856fad09c73SVivien Didelot struct dsa_switch *ds; 3857fad09c73SVivien Didelot 385873b1204dSVivien Didelot ds = dsa_switch_alloc(dev, mv88e6xxx_num_ports(chip)); 3859fad09c73SVivien Didelot if (!ds) 3860fad09c73SVivien Didelot return -ENOMEM; 3861fad09c73SVivien Didelot 3862fad09c73SVivien Didelot ds->priv = chip; 38639d490b4eSVivien Didelot ds->ops = &mv88e6xxx_switch_ops; 38649ff74f24SVivien Didelot ds->ageing_time_min = chip->info->age_time_coeff; 38659ff74f24SVivien Didelot ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; 3866fad09c73SVivien Didelot 3867fad09c73SVivien Didelot dev_set_drvdata(dev, ds); 3868fad09c73SVivien Didelot 386923c9ee49SVivien Didelot return dsa_register_switch(ds); 3870fad09c73SVivien Didelot } 3871fad09c73SVivien Didelot 3872fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip) 3873fad09c73SVivien Didelot { 3874fad09c73SVivien Didelot dsa_unregister_switch(chip->ds); 3875fad09c73SVivien Didelot } 3876fad09c73SVivien Didelot 3877fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev) 3878fad09c73SVivien Didelot { 3879fad09c73SVivien Didelot struct device *dev = &mdiodev->dev; 3880fad09c73SVivien Didelot struct device_node *np = dev->of_node; 3881fad09c73SVivien Didelot const struct mv88e6xxx_info *compat_info; 3882fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 3883fad09c73SVivien Didelot u32 eeprom_len; 3884fad09c73SVivien Didelot int err; 3885fad09c73SVivien Didelot 3886fad09c73SVivien Didelot compat_info = of_device_get_match_data(dev); 3887fad09c73SVivien Didelot if (!compat_info) 3888fad09c73SVivien Didelot return -EINVAL; 3889fad09c73SVivien Didelot 3890fad09c73SVivien Didelot chip = mv88e6xxx_alloc_chip(dev); 3891fad09c73SVivien Didelot if (!chip) 3892fad09c73SVivien Didelot return -ENOMEM; 3893fad09c73SVivien Didelot 3894fad09c73SVivien Didelot chip->info = compat_info; 3895fad09c73SVivien Didelot 3896fad09c73SVivien Didelot err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr); 3897fad09c73SVivien Didelot if (err) 3898fad09c73SVivien Didelot return err; 3899fad09c73SVivien Didelot 3900b4308f04SAndrew Lunn chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 3901b4308f04SAndrew Lunn if (IS_ERR(chip->reset)) 3902b4308f04SAndrew Lunn return PTR_ERR(chip->reset); 3903b4308f04SAndrew Lunn 3904fad09c73SVivien Didelot err = mv88e6xxx_detect(chip); 3905fad09c73SVivien Didelot if (err) 3906fad09c73SVivien Didelot return err; 3907fad09c73SVivien Didelot 3908e57e5e77SVivien Didelot mv88e6xxx_phy_init(chip); 3909e57e5e77SVivien Didelot 3910ee4dc2e7SVivien Didelot if (chip->info->ops->get_eeprom && 3911fad09c73SVivien Didelot !of_property_read_u32(np, "eeprom-length", &eeprom_len)) 3912fad09c73SVivien Didelot chip->eeprom_len = eeprom_len; 3913fad09c73SVivien Didelot 3914dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 3915dc30c35bSAndrew Lunn err = mv88e6xxx_switch_reset(chip); 3916dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 3917fad09c73SVivien Didelot if (err) 3918dc30c35bSAndrew Lunn goto out; 3919fad09c73SVivien Didelot 3920dc30c35bSAndrew Lunn chip->irq = of_irq_get(np, 0); 3921dc30c35bSAndrew Lunn if (chip->irq == -EPROBE_DEFER) { 3922dc30c35bSAndrew Lunn err = chip->irq; 3923dc30c35bSAndrew Lunn goto out; 3924fad09c73SVivien Didelot } 3925fad09c73SVivien Didelot 3926dc30c35bSAndrew Lunn if (chip->irq > 0) { 3927dc30c35bSAndrew Lunn /* Has to be performed before the MDIO bus is created, 3928dc30c35bSAndrew Lunn * because the PHYs will link there interrupts to these 3929dc30c35bSAndrew Lunn * interrupt controllers 3930dc30c35bSAndrew Lunn */ 3931dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 3932dc30c35bSAndrew Lunn err = mv88e6xxx_g1_irq_setup(chip); 3933dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 3934dc30c35bSAndrew Lunn 3935dc30c35bSAndrew Lunn if (err) 3936dc30c35bSAndrew Lunn goto out; 3937dc30c35bSAndrew Lunn 3938dc30c35bSAndrew Lunn if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT)) { 3939dc30c35bSAndrew Lunn err = mv88e6xxx_g2_irq_setup(chip); 3940dc30c35bSAndrew Lunn if (err) 3941dc30c35bSAndrew Lunn goto out_g1_irq; 3942dc30c35bSAndrew Lunn } 3943dc30c35bSAndrew Lunn } 3944dc30c35bSAndrew Lunn 3945a3c53be5SAndrew Lunn err = mv88e6xxx_mdios_register(chip, np); 3946dc30c35bSAndrew Lunn if (err) 3947dc30c35bSAndrew Lunn goto out_g2_irq; 3948dc30c35bSAndrew Lunn 394955ed0ce0SFlorian Fainelli err = mv88e6xxx_register_switch(chip); 3950dc30c35bSAndrew Lunn if (err) 3951dc30c35bSAndrew Lunn goto out_mdio; 3952dc30c35bSAndrew Lunn 3953fad09c73SVivien Didelot return 0; 3954dc30c35bSAndrew Lunn 3955dc30c35bSAndrew Lunn out_mdio: 3956a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 3957dc30c35bSAndrew Lunn out_g2_irq: 395846712644SAndrew Lunn if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT) && chip->irq > 0) 3959dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 3960dc30c35bSAndrew Lunn out_g1_irq: 396161f7c3f8SAndrew Lunn if (chip->irq > 0) { 396261f7c3f8SAndrew Lunn mutex_lock(&chip->reg_lock); 3963dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 396461f7c3f8SAndrew Lunn mutex_unlock(&chip->reg_lock); 396561f7c3f8SAndrew Lunn } 3966dc30c35bSAndrew Lunn out: 3967dc30c35bSAndrew Lunn return err; 3968fad09c73SVivien Didelot } 3969fad09c73SVivien Didelot 3970fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev) 3971fad09c73SVivien Didelot { 3972fad09c73SVivien Didelot struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 397304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3974fad09c73SVivien Didelot 3975930188ceSAndrew Lunn mv88e6xxx_phy_destroy(chip); 3976fad09c73SVivien Didelot mv88e6xxx_unregister_switch(chip); 3977a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 3978dc30c35bSAndrew Lunn 397946712644SAndrew Lunn if (chip->irq > 0) { 3980dc30c35bSAndrew Lunn if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT)) 3981dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 3982dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 3983fad09c73SVivien Didelot } 398446712644SAndrew Lunn } 3985fad09c73SVivien Didelot 3986fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = { 3987fad09c73SVivien Didelot { 3988fad09c73SVivien Didelot .compatible = "marvell,mv88e6085", 3989fad09c73SVivien Didelot .data = &mv88e6xxx_table[MV88E6085], 3990fad09c73SVivien Didelot }, 39911a3b39ecSAndrew Lunn { 39921a3b39ecSAndrew Lunn .compatible = "marvell,mv88e6190", 39931a3b39ecSAndrew Lunn .data = &mv88e6xxx_table[MV88E6190], 39941a3b39ecSAndrew Lunn }, 3995fad09c73SVivien Didelot { /* sentinel */ }, 3996fad09c73SVivien Didelot }; 3997fad09c73SVivien Didelot 3998fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match); 3999fad09c73SVivien Didelot 4000fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = { 4001fad09c73SVivien Didelot .probe = mv88e6xxx_probe, 4002fad09c73SVivien Didelot .remove = mv88e6xxx_remove, 4003fad09c73SVivien Didelot .mdiodrv.driver = { 4004fad09c73SVivien Didelot .name = "mv88e6085", 4005fad09c73SVivien Didelot .of_match_table = mv88e6xxx_of_match, 4006fad09c73SVivien Didelot }, 4007fad09c73SVivien Didelot }; 4008fad09c73SVivien Didelot 4009fad09c73SVivien Didelot static int __init mv88e6xxx_init(void) 4010fad09c73SVivien Didelot { 4011ab3d408dSFlorian Fainelli register_switch_driver(&mv88e6xxx_switch_drv); 4012fad09c73SVivien Didelot return mdio_driver_register(&mv88e6xxx_driver); 4013fad09c73SVivien Didelot } 4014fad09c73SVivien Didelot module_init(mv88e6xxx_init); 4015fad09c73SVivien Didelot 4016fad09c73SVivien Didelot static void __exit mv88e6xxx_cleanup(void) 4017fad09c73SVivien Didelot { 4018fad09c73SVivien Didelot mdio_driver_unregister(&mv88e6xxx_driver); 4019ab3d408dSFlorian Fainelli unregister_switch_driver(&mv88e6xxx_switch_drv); 4020fad09c73SVivien Didelot } 4021fad09c73SVivien Didelot module_exit(mv88e6xxx_cleanup); 4022fad09c73SVivien Didelot 4023fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); 4024fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips"); 4025fad09c73SVivien Didelot MODULE_LICENSE("GPL"); 4026