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