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 459342a0ee7SAndrew Lunn mutex_unlock(&chip->reg_lock); 460294d711eSAndrew Lunn err = request_threaded_irq(chip->irq, NULL, 461294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_fn, 4620340376eSMarek Behún IRQF_ONESHOT | IRQF_SHARED, 463294d711eSAndrew Lunn dev_name(chip->dev), chip); 464342a0ee7SAndrew Lunn mutex_lock(&chip->reg_lock); 465294d711eSAndrew Lunn if (err) 466294d711eSAndrew Lunn mv88e6xxx_g1_irq_free_common(chip); 467294d711eSAndrew Lunn 468294d711eSAndrew Lunn return err; 469294d711eSAndrew Lunn } 470294d711eSAndrew Lunn 471294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work) 472294d711eSAndrew Lunn { 473294d711eSAndrew Lunn struct mv88e6xxx_chip *chip = container_of(work, 474294d711eSAndrew Lunn struct mv88e6xxx_chip, 475294d711eSAndrew Lunn irq_poll_work.work); 476294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_work(chip); 477294d711eSAndrew Lunn 478294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 479294d711eSAndrew Lunn msecs_to_jiffies(100)); 480294d711eSAndrew Lunn } 481294d711eSAndrew Lunn 482294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip) 483294d711eSAndrew Lunn { 484294d711eSAndrew Lunn int err; 485294d711eSAndrew Lunn 486294d711eSAndrew Lunn err = mv88e6xxx_g1_irq_setup_common(chip); 487294d711eSAndrew Lunn if (err) 488294d711eSAndrew Lunn return err; 489294d711eSAndrew Lunn 490294d711eSAndrew Lunn kthread_init_delayed_work(&chip->irq_poll_work, 491294d711eSAndrew Lunn mv88e6xxx_irq_poll); 492294d711eSAndrew Lunn 4933f8b8696SFlorian Fainelli chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev)); 494294d711eSAndrew Lunn if (IS_ERR(chip->kworker)) 495294d711eSAndrew Lunn return PTR_ERR(chip->kworker); 496294d711eSAndrew Lunn 497294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 498294d711eSAndrew Lunn msecs_to_jiffies(100)); 499294d711eSAndrew Lunn 500294d711eSAndrew Lunn return 0; 501294d711eSAndrew Lunn } 502294d711eSAndrew Lunn 503294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip) 504294d711eSAndrew Lunn { 505294d711eSAndrew Lunn kthread_cancel_delayed_work_sync(&chip->irq_poll_work); 506294d711eSAndrew Lunn kthread_destroy_worker(chip->kworker); 5073d82475aSUwe Kleine-König 5083d82475aSUwe Kleine-König mutex_lock(&chip->reg_lock); 5093d82475aSUwe Kleine-König mv88e6xxx_g1_irq_free_common(chip); 5103d82475aSUwe Kleine-König mutex_unlock(&chip->reg_lock); 511294d711eSAndrew Lunn } 512294d711eSAndrew Lunn 513ec561276SVivien Didelot int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask) 5142d79af6eSVivien Didelot { 5156441e669SAndrew Lunn int i; 5162d79af6eSVivien Didelot 5176441e669SAndrew Lunn for (i = 0; i < 16; i++) { 5182d79af6eSVivien Didelot u16 val; 5192d79af6eSVivien Didelot int err; 5202d79af6eSVivien Didelot 5212d79af6eSVivien Didelot err = mv88e6xxx_read(chip, addr, reg, &val); 5222d79af6eSVivien Didelot if (err) 5232d79af6eSVivien Didelot return err; 5242d79af6eSVivien Didelot 5252d79af6eSVivien Didelot if (!(val & mask)) 5262d79af6eSVivien Didelot return 0; 5272d79af6eSVivien Didelot 5282d79af6eSVivien Didelot usleep_range(1000, 2000); 5292d79af6eSVivien Didelot } 5302d79af6eSVivien Didelot 53130853553SAndrew Lunn dev_err(chip->dev, "Timeout while waiting for switch\n"); 5322d79af6eSVivien Didelot return -ETIMEDOUT; 5332d79af6eSVivien Didelot } 5342d79af6eSVivien Didelot 535f22ab641SVivien Didelot /* Indirect write to single pointer-data register with an Update bit */ 536ec561276SVivien Didelot int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update) 537f22ab641SVivien Didelot { 538f22ab641SVivien Didelot u16 val; 5390f02b4f7SAndrew Lunn int err; 540f22ab641SVivien Didelot 541f22ab641SVivien Didelot /* Wait until the previous operation is completed */ 5420f02b4f7SAndrew Lunn err = mv88e6xxx_wait(chip, addr, reg, BIT(15)); 543f22ab641SVivien Didelot if (err) 544f22ab641SVivien Didelot return err; 545f22ab641SVivien Didelot 546f22ab641SVivien Didelot /* Set the Update bit to trigger a write operation */ 547f22ab641SVivien Didelot val = BIT(15) | update; 548f22ab641SVivien Didelot 549f22ab641SVivien Didelot return mv88e6xxx_write(chip, addr, reg, val); 550f22ab641SVivien Didelot } 551f22ab641SVivien Didelot 55272d8b4fdSHeiner Kallweit int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link, 55372d8b4fdSHeiner Kallweit int speed, int duplex, int pause, 554d78343d2SVivien Didelot phy_interface_t mode) 555d78343d2SVivien Didelot { 556d78343d2SVivien Didelot int err; 557d78343d2SVivien Didelot 558d78343d2SVivien Didelot if (!chip->info->ops->port_set_link) 559d78343d2SVivien Didelot return 0; 560d78343d2SVivien Didelot 561d78343d2SVivien Didelot /* Port's MAC control must not be changed unless the link is down */ 562d78343d2SVivien Didelot err = chip->info->ops->port_set_link(chip, port, 0); 563d78343d2SVivien Didelot if (err) 564d78343d2SVivien Didelot return err; 565d78343d2SVivien Didelot 566d78343d2SVivien Didelot if (chip->info->ops->port_set_speed) { 567d78343d2SVivien Didelot err = chip->info->ops->port_set_speed(chip, port, speed); 568d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 569d78343d2SVivien Didelot goto restore_link; 570d78343d2SVivien Didelot } 571d78343d2SVivien Didelot 57254186b91SAndrew Lunn if (chip->info->ops->port_set_pause) { 57354186b91SAndrew Lunn err = chip->info->ops->port_set_pause(chip, port, pause); 57454186b91SAndrew Lunn if (err) 57554186b91SAndrew Lunn goto restore_link; 57654186b91SAndrew Lunn } 57754186b91SAndrew Lunn 578d78343d2SVivien Didelot if (chip->info->ops->port_set_duplex) { 579d78343d2SVivien Didelot err = chip->info->ops->port_set_duplex(chip, port, duplex); 580d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 581d78343d2SVivien Didelot goto restore_link; 582d78343d2SVivien Didelot } 583d78343d2SVivien Didelot 584d78343d2SVivien Didelot if (chip->info->ops->port_set_rgmii_delay) { 585d78343d2SVivien Didelot err = chip->info->ops->port_set_rgmii_delay(chip, port, mode); 586d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 587d78343d2SVivien Didelot goto restore_link; 588d78343d2SVivien Didelot } 589d78343d2SVivien Didelot 590f39908d3SAndrew Lunn if (chip->info->ops->port_set_cmode) { 591f39908d3SAndrew Lunn err = chip->info->ops->port_set_cmode(chip, port, mode); 592f39908d3SAndrew Lunn if (err && err != -EOPNOTSUPP) 593f39908d3SAndrew Lunn goto restore_link; 594f39908d3SAndrew Lunn } 595f39908d3SAndrew Lunn 596d78343d2SVivien Didelot err = 0; 597d78343d2SVivien Didelot restore_link: 598d78343d2SVivien Didelot if (chip->info->ops->port_set_link(chip, port, link)) 599774439e5SVivien Didelot dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port); 600d78343d2SVivien Didelot 601d78343d2SVivien Didelot return err; 602d78343d2SVivien Didelot } 603d78343d2SVivien Didelot 604d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) 605d700ec41SMarek Vasut { 606d700ec41SMarek Vasut struct mv88e6xxx_chip *chip = ds->priv; 607d700ec41SMarek Vasut 608d700ec41SMarek Vasut return port < chip->info->num_internal_phys; 609d700ec41SMarek Vasut } 610d700ec41SMarek Vasut 611fad09c73SVivien Didelot /* We expect the switch to perform auto negotiation if there is a real 612fad09c73SVivien Didelot * phy. However, in the case of a fixed link phy, we force the port 613fad09c73SVivien Didelot * settings from the fixed link settings. 614fad09c73SVivien Didelot */ 615fad09c73SVivien Didelot static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, 616fad09c73SVivien Didelot struct phy_device *phydev) 617fad09c73SVivien Didelot { 61804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 6190e7b9925SAndrew Lunn int err; 620fad09c73SVivien Didelot 621d700ec41SMarek Vasut if (!phy_is_pseudo_fixed_link(phydev) && 622d700ec41SMarek Vasut mv88e6xxx_phy_is_internal(ds, port)) 623fad09c73SVivien Didelot return; 624fad09c73SVivien Didelot 625fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 626d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed, 62754186b91SAndrew Lunn phydev->duplex, phydev->pause, 62854186b91SAndrew Lunn phydev->interface); 629fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 630d78343d2SVivien Didelot 631d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 632774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to configure MAC\n", port); 633fad09c73SVivien Didelot } 634fad09c73SVivien Didelot 6356c422e34SRussell King static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port, 6366c422e34SRussell King unsigned long *mask, 6376c422e34SRussell King struct phylink_link_state *state) 6386c422e34SRussell King { 6396c422e34SRussell King if (!phy_interface_mode_is_8023z(state->interface)) { 6406c422e34SRussell King /* 10M and 100M are only supported in non-802.3z mode */ 6416c422e34SRussell King phylink_set(mask, 10baseT_Half); 6426c422e34SRussell King phylink_set(mask, 10baseT_Full); 6436c422e34SRussell King phylink_set(mask, 100baseT_Half); 6446c422e34SRussell King phylink_set(mask, 100baseT_Full); 6456c422e34SRussell King } 6466c422e34SRussell King } 6476c422e34SRussell King 6486c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port, 6496c422e34SRussell King unsigned long *mask, 6506c422e34SRussell King struct phylink_link_state *state) 6516c422e34SRussell King { 6526c422e34SRussell King /* FIXME: if the port is in 1000Base-X mode, then it only supports 6536c422e34SRussell King * 1000M FD speeds. In this case, CMODE will indicate 5. 6546c422e34SRussell King */ 6556c422e34SRussell King phylink_set(mask, 1000baseT_Full); 6566c422e34SRussell King phylink_set(mask, 1000baseX_Full); 6576c422e34SRussell King 6586c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 6596c422e34SRussell King } 6606c422e34SRussell King 661e3af71a3SMarek Behún static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port, 662e3af71a3SMarek Behún unsigned long *mask, 663e3af71a3SMarek Behún struct phylink_link_state *state) 664e3af71a3SMarek Behún { 665e3af71a3SMarek Behún if (port >= 5) 666e3af71a3SMarek Behún phylink_set(mask, 2500baseX_Full); 667e3af71a3SMarek Behún 668e3af71a3SMarek Behún /* No ethtool bits for 200Mbps */ 669e3af71a3SMarek Behún phylink_set(mask, 1000baseT_Full); 670e3af71a3SMarek Behún phylink_set(mask, 1000baseX_Full); 671e3af71a3SMarek Behún 672e3af71a3SMarek Behún mv88e6065_phylink_validate(chip, port, mask, state); 673e3af71a3SMarek Behún } 674e3af71a3SMarek Behún 6756c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port, 6766c422e34SRussell King unsigned long *mask, 6776c422e34SRussell King struct phylink_link_state *state) 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 mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port, 6876c422e34SRussell King unsigned long *mask, 6886c422e34SRussell King struct phylink_link_state *state) 6896c422e34SRussell King { 690ec26016bSAndrew Lunn if (port >= 9) { 6916c422e34SRussell King phylink_set(mask, 2500baseX_Full); 692ec26016bSAndrew Lunn phylink_set(mask, 2500baseT_Full); 693ec26016bSAndrew Lunn } 6946c422e34SRussell King 6956c422e34SRussell King /* No ethtool bits for 200Mbps */ 6966c422e34SRussell King phylink_set(mask, 1000baseT_Full); 6976c422e34SRussell King phylink_set(mask, 1000baseX_Full); 6986c422e34SRussell King 6996c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 7006c422e34SRussell King } 7016c422e34SRussell King 7026c422e34SRussell King static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port, 7036c422e34SRussell King unsigned long *mask, 7046c422e34SRussell King struct phylink_link_state *state) 7056c422e34SRussell King { 7066c422e34SRussell King if (port >= 9) { 7076c422e34SRussell King phylink_set(mask, 10000baseT_Full); 7086c422e34SRussell King phylink_set(mask, 10000baseKR_Full); 7096c422e34SRussell King } 7106c422e34SRussell King 7116c422e34SRussell King mv88e6390_phylink_validate(chip, port, mask, state); 7126c422e34SRussell King } 7136c422e34SRussell King 714c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port, 715c9a2356fSRussell King unsigned long *supported, 716c9a2356fSRussell King struct phylink_link_state *state) 717c9a2356fSRussell King { 7186c422e34SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 7196c422e34SRussell King struct mv88e6xxx_chip *chip = ds->priv; 7206c422e34SRussell King 7216c422e34SRussell King /* Allow all the expected bits */ 7226c422e34SRussell King phylink_set(mask, Autoneg); 7236c422e34SRussell King phylink_set(mask, Pause); 7246c422e34SRussell King phylink_set_port_modes(mask); 7256c422e34SRussell King 7266c422e34SRussell King if (chip->info->ops->phylink_validate) 7276c422e34SRussell King chip->info->ops->phylink_validate(chip, port, mask, state); 7286c422e34SRussell King 7296c422e34SRussell King bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); 7306c422e34SRussell King bitmap_and(state->advertising, state->advertising, mask, 7316c422e34SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS); 7326c422e34SRussell King 7336c422e34SRussell King /* We can only operate at 2500BaseX or 1000BaseX. If requested 7346c422e34SRussell King * to advertise both, only report advertising at 2500BaseX. 7356c422e34SRussell King */ 7366c422e34SRussell King phylink_helper_basex_speed(state); 737c9a2356fSRussell King } 738c9a2356fSRussell King 739c9a2356fSRussell King static int mv88e6xxx_link_state(struct dsa_switch *ds, int port, 740c9a2356fSRussell King struct phylink_link_state *state) 741c9a2356fSRussell King { 742c9a2356fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 743c9a2356fSRussell King int err; 744c9a2356fSRussell King 745c9a2356fSRussell King mutex_lock(&chip->reg_lock); 7466c422e34SRussell King if (chip->info->ops->port_link_state) 7476c422e34SRussell King err = chip->info->ops->port_link_state(chip, port, state); 7486c422e34SRussell King else 7496c422e34SRussell King err = -EOPNOTSUPP; 750c9a2356fSRussell King mutex_unlock(&chip->reg_lock); 751c9a2356fSRussell King 752c9a2356fSRussell King return err; 753c9a2356fSRussell King } 754c9a2356fSRussell King 755c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, 756c9a2356fSRussell King unsigned int mode, 757c9a2356fSRussell King const struct phylink_link_state *state) 758c9a2356fSRussell King { 759c9a2356fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 76054186b91SAndrew Lunn int speed, duplex, link, pause, err; 761c9a2356fSRussell King 762d700ec41SMarek Vasut if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port)) 763c9a2356fSRussell King return; 764c9a2356fSRussell King 765c9a2356fSRussell King if (mode == MLO_AN_FIXED) { 766c9a2356fSRussell King link = LINK_FORCED_UP; 767c9a2356fSRussell King speed = state->speed; 768c9a2356fSRussell King duplex = state->duplex; 769d700ec41SMarek Vasut } else if (!mv88e6xxx_phy_is_internal(ds, port)) { 770d700ec41SMarek Vasut link = state->link; 771d700ec41SMarek Vasut speed = state->speed; 772d700ec41SMarek Vasut duplex = state->duplex; 773c9a2356fSRussell King } else { 774c9a2356fSRussell King speed = SPEED_UNFORCED; 775c9a2356fSRussell King duplex = DUPLEX_UNFORCED; 776c9a2356fSRussell King link = LINK_UNFORCED; 777c9a2356fSRussell King } 77854186b91SAndrew Lunn pause = !!phylink_test(state->advertising, Pause); 779c9a2356fSRussell King 780c9a2356fSRussell King mutex_lock(&chip->reg_lock); 78154186b91SAndrew Lunn err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, pause, 782c9a2356fSRussell King state->interface); 783c9a2356fSRussell King mutex_unlock(&chip->reg_lock); 784c9a2356fSRussell King 785c9a2356fSRussell King if (err && err != -EOPNOTSUPP) 786c9a2356fSRussell King dev_err(ds->dev, "p%d: failed to configure MAC\n", port); 787c9a2356fSRussell King } 788c9a2356fSRussell King 789c9a2356fSRussell King static void mv88e6xxx_mac_link_force(struct dsa_switch *ds, int port, int link) 790c9a2356fSRussell King { 791c9a2356fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 792c9a2356fSRussell King int err; 793c9a2356fSRussell King 794c9a2356fSRussell King mutex_lock(&chip->reg_lock); 795c9a2356fSRussell King err = chip->info->ops->port_set_link(chip, port, link); 796c9a2356fSRussell King mutex_unlock(&chip->reg_lock); 797c9a2356fSRussell King 798c9a2356fSRussell King if (err) 799c9a2356fSRussell King dev_err(chip->dev, "p%d: failed to force MAC link\n", port); 800c9a2356fSRussell King } 801c9a2356fSRussell King 802c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port, 803c9a2356fSRussell King unsigned int mode, 804c9a2356fSRussell King phy_interface_t interface) 805c9a2356fSRussell King { 806c9a2356fSRussell King if (mode == MLO_AN_FIXED) 807c9a2356fSRussell King mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_DOWN); 808c9a2356fSRussell King } 809c9a2356fSRussell King 810c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, 811c9a2356fSRussell King unsigned int mode, phy_interface_t interface, 812c9a2356fSRussell King struct phy_device *phydev) 813c9a2356fSRussell King { 814c9a2356fSRussell King if (mode == MLO_AN_FIXED) 815c9a2356fSRussell King mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_UP); 816c9a2356fSRussell King } 817c9a2356fSRussell King 818a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 819fad09c73SVivien Didelot { 820a605a0feSAndrew Lunn if (!chip->info->ops->stats_snapshot) 821a605a0feSAndrew Lunn return -EOPNOTSUPP; 822fad09c73SVivien Didelot 823a605a0feSAndrew Lunn return chip->info->ops->stats_snapshot(chip, port); 824fad09c73SVivien Didelot } 825fad09c73SVivien Didelot 826fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = { 827dfafe449SAndrew Lunn { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, }, 828dfafe449SAndrew Lunn { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, }, 829dfafe449SAndrew Lunn { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, }, 830dfafe449SAndrew Lunn { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, }, 831dfafe449SAndrew Lunn { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, }, 832dfafe449SAndrew Lunn { "in_pause", 4, 0x16, STATS_TYPE_BANK0, }, 833dfafe449SAndrew Lunn { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, }, 834dfafe449SAndrew Lunn { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, }, 835dfafe449SAndrew Lunn { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, }, 836dfafe449SAndrew Lunn { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, }, 837dfafe449SAndrew Lunn { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, }, 838dfafe449SAndrew Lunn { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, }, 839dfafe449SAndrew Lunn { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, }, 840dfafe449SAndrew Lunn { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, }, 841dfafe449SAndrew Lunn { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, }, 842dfafe449SAndrew Lunn { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, }, 843dfafe449SAndrew Lunn { "out_pause", 4, 0x15, STATS_TYPE_BANK0, }, 844dfafe449SAndrew Lunn { "excessive", 4, 0x11, STATS_TYPE_BANK0, }, 845dfafe449SAndrew Lunn { "collisions", 4, 0x1e, STATS_TYPE_BANK0, }, 846dfafe449SAndrew Lunn { "deferred", 4, 0x05, STATS_TYPE_BANK0, }, 847dfafe449SAndrew Lunn { "single", 4, 0x14, STATS_TYPE_BANK0, }, 848dfafe449SAndrew Lunn { "multiple", 4, 0x17, STATS_TYPE_BANK0, }, 849dfafe449SAndrew Lunn { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, }, 850dfafe449SAndrew Lunn { "late", 4, 0x1f, STATS_TYPE_BANK0, }, 851dfafe449SAndrew Lunn { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, }, 852dfafe449SAndrew Lunn { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, }, 853dfafe449SAndrew Lunn { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, }, 854dfafe449SAndrew Lunn { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, }, 855dfafe449SAndrew Lunn { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, }, 856dfafe449SAndrew Lunn { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, }, 857dfafe449SAndrew Lunn { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, }, 858dfafe449SAndrew Lunn { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, }, 859dfafe449SAndrew Lunn { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, }, 860dfafe449SAndrew Lunn { "in_discards", 4, 0x00, STATS_TYPE_BANK1, }, 861dfafe449SAndrew Lunn { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, }, 862dfafe449SAndrew Lunn { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, }, 863dfafe449SAndrew Lunn { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, }, 864dfafe449SAndrew Lunn { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, }, 865dfafe449SAndrew Lunn { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, }, 866dfafe449SAndrew Lunn { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, }, 867dfafe449SAndrew Lunn { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, }, 868dfafe449SAndrew Lunn { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, }, 869dfafe449SAndrew Lunn { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, }, 870dfafe449SAndrew Lunn { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, }, 871dfafe449SAndrew Lunn { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, }, 872dfafe449SAndrew Lunn { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, }, 873dfafe449SAndrew Lunn { "in_management", 4, 0x0f, STATS_TYPE_BANK1, }, 874dfafe449SAndrew Lunn { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, }, 875dfafe449SAndrew Lunn { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, }, 876dfafe449SAndrew Lunn { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, }, 877dfafe449SAndrew Lunn { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, }, 878dfafe449SAndrew Lunn { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, }, 879dfafe449SAndrew Lunn { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, }, 880dfafe449SAndrew Lunn { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, }, 881dfafe449SAndrew Lunn { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, }, 882dfafe449SAndrew Lunn { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, }, 883dfafe449SAndrew Lunn { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, }, 884dfafe449SAndrew Lunn { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, }, 885dfafe449SAndrew Lunn { "out_management", 4, 0x1f, STATS_TYPE_BANK1, }, 886fad09c73SVivien Didelot }; 887fad09c73SVivien Didelot 888fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, 889fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *s, 890e0d8b615SAndrew Lunn int port, u16 bank1_select, 891e0d8b615SAndrew Lunn u16 histogram) 892fad09c73SVivien Didelot { 893fad09c73SVivien Didelot u32 low; 894fad09c73SVivien Didelot u32 high = 0; 895dfafe449SAndrew Lunn u16 reg = 0; 8960e7b9925SAndrew Lunn int err; 897fad09c73SVivien Didelot u64 value; 898fad09c73SVivien Didelot 899fad09c73SVivien Didelot switch (s->type) { 900dfafe449SAndrew Lunn case STATS_TYPE_PORT: 9010e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg, ®); 9020e7b9925SAndrew Lunn if (err) 9036c3442f5SJisheng Zhang return U64_MAX; 904fad09c73SVivien Didelot 9050e7b9925SAndrew Lunn low = reg; 906cda9f4aaSAndrew Lunn if (s->size == 4) { 9070e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg + 1, ®); 9080e7b9925SAndrew Lunn if (err) 9096c3442f5SJisheng Zhang return U64_MAX; 9100e7b9925SAndrew Lunn high = reg; 911fad09c73SVivien Didelot } 912fad09c73SVivien Didelot break; 913dfafe449SAndrew Lunn case STATS_TYPE_BANK1: 914e0d8b615SAndrew Lunn reg = bank1_select; 915dfafe449SAndrew Lunn /* fall through */ 916dfafe449SAndrew Lunn case STATS_TYPE_BANK0: 917e0d8b615SAndrew Lunn reg |= s->reg | histogram; 9187f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg, &low); 919cda9f4aaSAndrew Lunn if (s->size == 8) 9207f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg + 1, &high); 9219fc3e4dcSGustavo A. R. Silva break; 9229fc3e4dcSGustavo A. R. Silva default: 9236c3442f5SJisheng Zhang return U64_MAX; 924fad09c73SVivien Didelot } 9256e46e2d8SAndrew Lunn value = (((u64)high) << 32) | low; 926fad09c73SVivien Didelot return value; 927fad09c73SVivien Didelot } 928fad09c73SVivien Didelot 929436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, 930dfafe449SAndrew Lunn uint8_t *data, int types) 931fad09c73SVivien Didelot { 932fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 933fad09c73SVivien Didelot int i, j; 934fad09c73SVivien Didelot 935fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 936fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 937dfafe449SAndrew Lunn if (stat->type & types) { 938fad09c73SVivien Didelot memcpy(data + j * ETH_GSTRING_LEN, stat->string, 939fad09c73SVivien Didelot ETH_GSTRING_LEN); 940fad09c73SVivien Didelot j++; 941fad09c73SVivien Didelot } 942fad09c73SVivien Didelot } 943436fe17dSAndrew Lunn 944436fe17dSAndrew Lunn return j; 945fad09c73SVivien Didelot } 946fad09c73SVivien Didelot 947436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, 948dfafe449SAndrew Lunn uint8_t *data) 949dfafe449SAndrew Lunn { 950436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 951dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT); 952dfafe449SAndrew Lunn } 953dfafe449SAndrew Lunn 954436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, 955dfafe449SAndrew Lunn uint8_t *data) 956dfafe449SAndrew Lunn { 957436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 958dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1); 959dfafe449SAndrew Lunn } 960dfafe449SAndrew Lunn 96165f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = { 96265f60e45SAndrew Lunn "atu_member_violation", 96365f60e45SAndrew Lunn "atu_miss_violation", 96465f60e45SAndrew Lunn "atu_full_violation", 96565f60e45SAndrew Lunn "vtu_member_violation", 96665f60e45SAndrew Lunn "vtu_miss_violation", 96765f60e45SAndrew Lunn }; 96865f60e45SAndrew Lunn 96965f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data) 97065f60e45SAndrew Lunn { 97165f60e45SAndrew Lunn unsigned int i; 97265f60e45SAndrew Lunn 97365f60e45SAndrew Lunn for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++) 97465f60e45SAndrew Lunn strlcpy(data + i * ETH_GSTRING_LEN, 97565f60e45SAndrew Lunn mv88e6xxx_atu_vtu_stats_strings[i], 97665f60e45SAndrew Lunn ETH_GSTRING_LEN); 97765f60e45SAndrew Lunn } 97865f60e45SAndrew Lunn 979dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, 98089f09048SFlorian Fainelli u32 stringset, uint8_t *data) 981fad09c73SVivien Didelot { 98204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 983436fe17dSAndrew Lunn int count = 0; 984dfafe449SAndrew Lunn 98589f09048SFlorian Fainelli if (stringset != ETH_SS_STATS) 98689f09048SFlorian Fainelli return; 98789f09048SFlorian Fainelli 988c6c8cd5eSAndrew Lunn mutex_lock(&chip->reg_lock); 989c6c8cd5eSAndrew Lunn 990dfafe449SAndrew Lunn if (chip->info->ops->stats_get_strings) 991436fe17dSAndrew Lunn count = chip->info->ops->stats_get_strings(chip, data); 992436fe17dSAndrew Lunn 993436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_strings) { 994436fe17dSAndrew Lunn data += count * ETH_GSTRING_LEN; 99565f60e45SAndrew Lunn count = chip->info->ops->serdes_get_strings(chip, port, data); 996436fe17dSAndrew Lunn } 997c6c8cd5eSAndrew Lunn 99865f60e45SAndrew Lunn data += count * ETH_GSTRING_LEN; 99965f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_strings(data); 100065f60e45SAndrew Lunn 1001c6c8cd5eSAndrew Lunn mutex_unlock(&chip->reg_lock); 1002dfafe449SAndrew Lunn } 1003dfafe449SAndrew Lunn 1004dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip, 1005dfafe449SAndrew Lunn int types) 1006dfafe449SAndrew Lunn { 1007fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 1008fad09c73SVivien Didelot int i, j; 1009fad09c73SVivien Didelot 1010fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 1011fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 1012dfafe449SAndrew Lunn if (stat->type & types) 1013fad09c73SVivien Didelot j++; 1014fad09c73SVivien Didelot } 1015fad09c73SVivien Didelot return j; 1016fad09c73SVivien Didelot } 1017fad09c73SVivien Didelot 1018dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip) 1019dfafe449SAndrew Lunn { 1020dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 1021dfafe449SAndrew Lunn STATS_TYPE_PORT); 1022dfafe449SAndrew Lunn } 1023dfafe449SAndrew Lunn 1024dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip) 1025dfafe449SAndrew Lunn { 1026dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 1027dfafe449SAndrew Lunn STATS_TYPE_BANK1); 1028dfafe449SAndrew Lunn } 1029dfafe449SAndrew Lunn 103089f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset) 1031dfafe449SAndrew Lunn { 1032dfafe449SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 1033436fe17dSAndrew Lunn int serdes_count = 0; 1034436fe17dSAndrew Lunn int count = 0; 1035dfafe449SAndrew Lunn 103689f09048SFlorian Fainelli if (sset != ETH_SS_STATS) 103789f09048SFlorian Fainelli return 0; 103889f09048SFlorian Fainelli 1039c6c8cd5eSAndrew Lunn mutex_lock(&chip->reg_lock); 1040dfafe449SAndrew Lunn if (chip->info->ops->stats_get_sset_count) 1041436fe17dSAndrew Lunn count = chip->info->ops->stats_get_sset_count(chip); 1042436fe17dSAndrew Lunn if (count < 0) 1043436fe17dSAndrew Lunn goto out; 1044436fe17dSAndrew Lunn 1045436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_sset_count) 1046436fe17dSAndrew Lunn serdes_count = chip->info->ops->serdes_get_sset_count(chip, 1047436fe17dSAndrew Lunn port); 104865f60e45SAndrew Lunn if (serdes_count < 0) { 1049436fe17dSAndrew Lunn count = serdes_count; 105065f60e45SAndrew Lunn goto out; 105165f60e45SAndrew Lunn } 1052436fe17dSAndrew Lunn count += serdes_count; 105365f60e45SAndrew Lunn count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); 105465f60e45SAndrew Lunn 1055436fe17dSAndrew Lunn out: 1056c6c8cd5eSAndrew Lunn mutex_unlock(&chip->reg_lock); 1057dfafe449SAndrew Lunn 1058436fe17dSAndrew Lunn return count; 1059dfafe449SAndrew Lunn } 1060dfafe449SAndrew Lunn 1061436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1062e0d8b615SAndrew Lunn uint64_t *data, int types, 1063e0d8b615SAndrew Lunn u16 bank1_select, u16 histogram) 1064052f947fSAndrew Lunn { 1065052f947fSAndrew Lunn struct mv88e6xxx_hw_stat *stat; 1066052f947fSAndrew Lunn int i, j; 1067052f947fSAndrew Lunn 1068052f947fSAndrew Lunn for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 1069052f947fSAndrew Lunn stat = &mv88e6xxx_hw_stats[i]; 1070052f947fSAndrew Lunn if (stat->type & types) { 1071377cda13SAndrew Lunn mutex_lock(&chip->reg_lock); 1072e0d8b615SAndrew Lunn data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 1073e0d8b615SAndrew Lunn bank1_select, 1074e0d8b615SAndrew Lunn histogram); 1075377cda13SAndrew Lunn mutex_unlock(&chip->reg_lock); 1076377cda13SAndrew Lunn 1077052f947fSAndrew Lunn j++; 1078052f947fSAndrew Lunn } 1079052f947fSAndrew Lunn } 1080436fe17dSAndrew Lunn return j; 1081052f947fSAndrew Lunn } 1082052f947fSAndrew Lunn 1083436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1084052f947fSAndrew Lunn uint64_t *data) 1085052f947fSAndrew Lunn { 1086052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1087e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT, 108857d1ef38SVivien Didelot 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 1089052f947fSAndrew Lunn } 1090052f947fSAndrew Lunn 1091436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1092052f947fSAndrew Lunn uint64_t *data) 1093052f947fSAndrew Lunn { 1094052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1095e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 109657d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9, 109757d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 1098e0d8b615SAndrew Lunn } 1099e0d8b615SAndrew Lunn 1100436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1101e0d8b615SAndrew Lunn uint64_t *data) 1102e0d8b615SAndrew Lunn { 1103e0d8b615SAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1104e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 110557d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10, 110657d1ef38SVivien Didelot 0); 1107052f947fSAndrew Lunn } 1108052f947fSAndrew Lunn 110965f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port, 111065f60e45SAndrew Lunn uint64_t *data) 111165f60e45SAndrew Lunn { 111265f60e45SAndrew Lunn *data++ = chip->ports[port].atu_member_violation; 111365f60e45SAndrew Lunn *data++ = chip->ports[port].atu_miss_violation; 111465f60e45SAndrew Lunn *data++ = chip->ports[port].atu_full_violation; 111565f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_member_violation; 111665f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_miss_violation; 111765f60e45SAndrew Lunn } 111865f60e45SAndrew Lunn 1119052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, 1120052f947fSAndrew Lunn uint64_t *data) 1121052f947fSAndrew Lunn { 1122436fe17dSAndrew Lunn int count = 0; 1123436fe17dSAndrew Lunn 1124052f947fSAndrew Lunn if (chip->info->ops->stats_get_stats) 1125436fe17dSAndrew Lunn count = chip->info->ops->stats_get_stats(chip, port, data); 1126436fe17dSAndrew Lunn 112765f60e45SAndrew Lunn mutex_lock(&chip->reg_lock); 1128436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_stats) { 1129436fe17dSAndrew Lunn data += count; 113065f60e45SAndrew Lunn count = chip->info->ops->serdes_get_stats(chip, port, data); 1131436fe17dSAndrew Lunn } 113265f60e45SAndrew Lunn data += count; 113365f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_stats(chip, port, data); 113465f60e45SAndrew Lunn mutex_unlock(&chip->reg_lock); 1135052f947fSAndrew Lunn } 1136052f947fSAndrew Lunn 1137fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, 1138fad09c73SVivien Didelot uint64_t *data) 1139fad09c73SVivien Didelot { 114004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1141fad09c73SVivien Didelot int ret; 1142fad09c73SVivien Didelot 1143fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1144fad09c73SVivien Didelot 1145a605a0feSAndrew Lunn ret = mv88e6xxx_stats_snapshot(chip, port); 1146fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1147377cda13SAndrew Lunn 1148377cda13SAndrew Lunn if (ret < 0) 1149fad09c73SVivien Didelot return; 1150052f947fSAndrew Lunn 1151052f947fSAndrew Lunn mv88e6xxx_get_stats(chip, port, data); 1152fad09c73SVivien Didelot 1153fad09c73SVivien Didelot } 1154fad09c73SVivien Didelot 1155fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) 1156fad09c73SVivien Didelot { 1157fad09c73SVivien Didelot return 32 * sizeof(u16); 1158fad09c73SVivien Didelot } 1159fad09c73SVivien Didelot 1160fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, 1161fad09c73SVivien Didelot struct ethtool_regs *regs, void *_p) 1162fad09c73SVivien Didelot { 116304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 11640e7b9925SAndrew Lunn int err; 11650e7b9925SAndrew Lunn u16 reg; 1166fad09c73SVivien Didelot u16 *p = _p; 1167fad09c73SVivien Didelot int i; 1168fad09c73SVivien Didelot 1169a5f39326SVivien Didelot regs->version = chip->info->prod_num; 1170fad09c73SVivien Didelot 1171fad09c73SVivien Didelot memset(p, 0xff, 32 * sizeof(u16)); 1172fad09c73SVivien Didelot 1173fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1174fad09c73SVivien Didelot 1175fad09c73SVivien Didelot for (i = 0; i < 32; i++) { 1176fad09c73SVivien Didelot 11770e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, i, ®); 11780e7b9925SAndrew Lunn if (!err) 11790e7b9925SAndrew Lunn p[i] = reg; 1180fad09c73SVivien Didelot } 1181fad09c73SVivien Didelot 1182fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1183fad09c73SVivien Didelot } 1184fad09c73SVivien Didelot 118508f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port, 1186fad09c73SVivien Didelot struct ethtool_eee *e) 1187fad09c73SVivien Didelot { 11885480db69SVivien Didelot /* Nothing to do on the port's MAC */ 11895480db69SVivien Didelot return 0; 1190fad09c73SVivien Didelot } 1191fad09c73SVivien Didelot 119208f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port, 119346587e4aSVivien Didelot struct ethtool_eee *e) 1194fad09c73SVivien Didelot { 11955480db69SVivien Didelot /* Nothing to do on the port's MAC */ 11965480db69SVivien Didelot return 0; 1197fad09c73SVivien Didelot } 1198fad09c73SVivien Didelot 1199e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port) 1200fad09c73SVivien Didelot { 1201e5887a2aSVivien Didelot struct dsa_switch *ds = NULL; 1202e5887a2aSVivien Didelot struct net_device *br; 1203e5887a2aSVivien Didelot u16 pvlan; 1204fad09c73SVivien Didelot int i; 1205fad09c73SVivien Didelot 1206e5887a2aSVivien Didelot if (dev < DSA_MAX_SWITCHES) 1207e5887a2aSVivien Didelot ds = chip->ds->dst->ds[dev]; 1208fad09c73SVivien Didelot 1209e5887a2aSVivien Didelot /* Prevent frames from unknown switch or port */ 1210e5887a2aSVivien Didelot if (!ds || port >= ds->num_ports) 1211e5887a2aSVivien Didelot return 0; 1212e5887a2aSVivien Didelot 1213e5887a2aSVivien Didelot /* Frames from DSA links and CPU ports can egress any local port */ 1214e5887a2aSVivien Didelot if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) 1215e5887a2aSVivien Didelot return mv88e6xxx_port_mask(chip); 1216e5887a2aSVivien Didelot 1217e5887a2aSVivien Didelot br = ds->ports[port].bridge_dev; 1218e5887a2aSVivien Didelot pvlan = 0; 1219e5887a2aSVivien Didelot 1220e5887a2aSVivien Didelot /* Frames from user ports can egress any local DSA links and CPU ports, 1221e5887a2aSVivien Didelot * as well as any local member of their bridge group. 1222e5887a2aSVivien Didelot */ 1223e5887a2aSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 1224e5887a2aSVivien Didelot if (dsa_is_cpu_port(chip->ds, i) || 1225e5887a2aSVivien Didelot dsa_is_dsa_port(chip->ds, i) || 1226c8652c83SVivien Didelot (br && dsa_to_port(chip->ds, i)->bridge_dev == br)) 1227e5887a2aSVivien Didelot pvlan |= BIT(i); 1228e5887a2aSVivien Didelot 1229e5887a2aSVivien Didelot return pvlan; 1230fad09c73SVivien Didelot } 1231e5887a2aSVivien Didelot 1232240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port) 1233e5887a2aSVivien Didelot { 1234e5887a2aSVivien Didelot u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port); 1235fad09c73SVivien Didelot 1236fad09c73SVivien Didelot /* prevent frames from going back out of the port they came in on */ 1237fad09c73SVivien Didelot output_ports &= ~BIT(port); 1238fad09c73SVivien Didelot 12395a7921f4SVivien Didelot return mv88e6xxx_port_set_vlan_map(chip, port, output_ports); 1240fad09c73SVivien Didelot } 1241fad09c73SVivien Didelot 1242fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, 1243fad09c73SVivien Didelot u8 state) 1244fad09c73SVivien Didelot { 124504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1246fad09c73SVivien Didelot int err; 1247fad09c73SVivien Didelot 1248fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1249f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, port, state); 1250fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1251fad09c73SVivien Didelot 1252fad09c73SVivien Didelot if (err) 1253774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to update state\n", port); 1254fad09c73SVivien Didelot } 1255fad09c73SVivien Didelot 125693e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip) 125793e18d61SVivien Didelot { 125893e18d61SVivien Didelot int err; 125993e18d61SVivien Didelot 126093e18d61SVivien Didelot if (chip->info->ops->ieee_pri_map) { 126193e18d61SVivien Didelot err = chip->info->ops->ieee_pri_map(chip); 126293e18d61SVivien Didelot if (err) 126393e18d61SVivien Didelot return err; 126493e18d61SVivien Didelot } 126593e18d61SVivien Didelot 126693e18d61SVivien Didelot if (chip->info->ops->ip_pri_map) { 126793e18d61SVivien Didelot err = chip->info->ops->ip_pri_map(chip); 126893e18d61SVivien Didelot if (err) 126993e18d61SVivien Didelot return err; 127093e18d61SVivien Didelot } 127193e18d61SVivien Didelot 127293e18d61SVivien Didelot return 0; 127393e18d61SVivien Didelot } 127493e18d61SVivien Didelot 1275c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) 1276c7f047b6SVivien Didelot { 1277c7f047b6SVivien Didelot int target, port; 1278c7f047b6SVivien Didelot int err; 1279c7f047b6SVivien Didelot 1280c7f047b6SVivien Didelot if (!chip->info->global2_addr) 1281c7f047b6SVivien Didelot return 0; 1282c7f047b6SVivien Didelot 1283c7f047b6SVivien Didelot /* Initialize the routing port to the 32 possible target devices */ 1284c7f047b6SVivien Didelot for (target = 0; target < 32; target++) { 1285c7f047b6SVivien Didelot port = 0x1f; 1286c7f047b6SVivien Didelot if (target < DSA_MAX_SWITCHES) 1287c7f047b6SVivien Didelot if (chip->ds->rtable[target] != DSA_RTABLE_NONE) 1288c7f047b6SVivien Didelot port = chip->ds->rtable[target]; 1289c7f047b6SVivien Didelot 1290c7f047b6SVivien Didelot err = mv88e6xxx_g2_device_mapping_write(chip, target, port); 1291c7f047b6SVivien Didelot if (err) 1292c7f047b6SVivien Didelot return err; 1293c7f047b6SVivien Didelot } 1294c7f047b6SVivien Didelot 129502317e68SVivien Didelot if (chip->info->ops->set_cascade_port) { 129602317e68SVivien Didelot port = MV88E6XXX_CASCADE_PORT_MULTIPLE; 129702317e68SVivien Didelot err = chip->info->ops->set_cascade_port(chip, port); 129802317e68SVivien Didelot if (err) 129902317e68SVivien Didelot return err; 130002317e68SVivien Didelot } 130102317e68SVivien Didelot 130223c98919SVivien Didelot err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index); 130323c98919SVivien Didelot if (err) 130423c98919SVivien Didelot return err; 130523c98919SVivien Didelot 1306c7f047b6SVivien Didelot return 0; 1307c7f047b6SVivien Didelot } 1308c7f047b6SVivien Didelot 1309b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip) 1310b28f872dSVivien Didelot { 1311b28f872dSVivien Didelot /* Clear all trunk masks and mapping */ 1312b28f872dSVivien Didelot if (chip->info->global2_addr) 1313b28f872dSVivien Didelot return mv88e6xxx_g2_trunk_clear(chip); 1314b28f872dSVivien Didelot 1315b28f872dSVivien Didelot return 0; 1316b28f872dSVivien Didelot } 1317b28f872dSVivien Didelot 13189e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip) 13199e5baf9bSVivien Didelot { 13209e5baf9bSVivien Didelot if (chip->info->ops->rmu_disable) 13219e5baf9bSVivien Didelot return chip->info->ops->rmu_disable(chip); 13229e5baf9bSVivien Didelot 13239e5baf9bSVivien Didelot return 0; 13249e5baf9bSVivien Didelot } 13259e5baf9bSVivien Didelot 13269e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip) 13279e907d73SVivien Didelot { 13289e907d73SVivien Didelot if (chip->info->ops->pot_clear) 13299e907d73SVivien Didelot return chip->info->ops->pot_clear(chip); 13309e907d73SVivien Didelot 13319e907d73SVivien Didelot return 0; 13329e907d73SVivien Didelot } 13339e907d73SVivien Didelot 133451c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip) 133551c901a7SVivien Didelot { 133651c901a7SVivien Didelot if (chip->info->ops->mgmt_rsvd2cpu) 133751c901a7SVivien Didelot return chip->info->ops->mgmt_rsvd2cpu(chip); 133851c901a7SVivien Didelot 133951c901a7SVivien Didelot return 0; 134051c901a7SVivien Didelot } 134151c901a7SVivien Didelot 1342a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) 1343a2ac29d2SVivien Didelot { 1344c3a7d4adSVivien Didelot int err; 1345c3a7d4adSVivien Didelot 1346daefc943SVivien Didelot err = mv88e6xxx_g1_atu_flush(chip, 0, true); 1347daefc943SVivien Didelot if (err) 1348daefc943SVivien Didelot return err; 1349daefc943SVivien Didelot 1350c3a7d4adSVivien Didelot err = mv88e6xxx_g1_atu_set_learn2all(chip, true); 1351c3a7d4adSVivien Didelot if (err) 1352c3a7d4adSVivien Didelot return err; 1353c3a7d4adSVivien Didelot 1354a2ac29d2SVivien Didelot return mv88e6xxx_g1_atu_set_age_time(chip, 300000); 1355a2ac29d2SVivien Didelot } 1356a2ac29d2SVivien Didelot 1357cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip) 1358cd8da8bbSVivien Didelot { 1359cd8da8bbSVivien Didelot int port; 1360cd8da8bbSVivien Didelot int err; 1361cd8da8bbSVivien Didelot 1362cd8da8bbSVivien Didelot if (!chip->info->ops->irl_init_all) 1363cd8da8bbSVivien Didelot return 0; 1364cd8da8bbSVivien Didelot 1365cd8da8bbSVivien Didelot for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 1366cd8da8bbSVivien Didelot /* Disable ingress rate limiting by resetting all per port 1367cd8da8bbSVivien Didelot * ingress rate limit resources to their initial state. 1368cd8da8bbSVivien Didelot */ 1369cd8da8bbSVivien Didelot err = chip->info->ops->irl_init_all(chip, port); 1370cd8da8bbSVivien Didelot if (err) 1371cd8da8bbSVivien Didelot return err; 1372cd8da8bbSVivien Didelot } 1373cd8da8bbSVivien Didelot 1374cd8da8bbSVivien Didelot return 0; 1375cd8da8bbSVivien Didelot } 1376cd8da8bbSVivien Didelot 137704a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip) 137804a69a17SVivien Didelot { 137904a69a17SVivien Didelot if (chip->info->ops->set_switch_mac) { 138004a69a17SVivien Didelot u8 addr[ETH_ALEN]; 138104a69a17SVivien Didelot 138204a69a17SVivien Didelot eth_random_addr(addr); 138304a69a17SVivien Didelot 138404a69a17SVivien Didelot return chip->info->ops->set_switch_mac(chip, addr); 138504a69a17SVivien Didelot } 138604a69a17SVivien Didelot 138704a69a17SVivien Didelot return 0; 138804a69a17SVivien Didelot } 138904a69a17SVivien Didelot 139017a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port) 139117a1594eSVivien Didelot { 139217a1594eSVivien Didelot u16 pvlan = 0; 139317a1594eSVivien Didelot 139417a1594eSVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 139517a1594eSVivien Didelot return -EOPNOTSUPP; 139617a1594eSVivien Didelot 139717a1594eSVivien Didelot /* Skip the local source device, which uses in-chip port VLAN */ 139817a1594eSVivien Didelot if (dev != chip->ds->index) 1399aec5ac88SVivien Didelot pvlan = mv88e6xxx_port_vlan(chip, dev, port); 140017a1594eSVivien Didelot 140117a1594eSVivien Didelot return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan); 140217a1594eSVivien Didelot } 140317a1594eSVivien Didelot 140481228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip) 140581228996SVivien Didelot { 140617a1594eSVivien Didelot int dev, port; 140717a1594eSVivien Didelot int err; 140817a1594eSVivien Didelot 140981228996SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 141081228996SVivien Didelot return 0; 141181228996SVivien Didelot 141281228996SVivien Didelot /* Clear 5 Bit Port for usage with Marvell Link Street devices: 141381228996SVivien Didelot * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev. 141481228996SVivien Didelot */ 141517a1594eSVivien Didelot err = mv88e6xxx_g2_misc_4_bit_port(chip); 141617a1594eSVivien Didelot if (err) 141717a1594eSVivien Didelot return err; 141817a1594eSVivien Didelot 141917a1594eSVivien Didelot for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) { 142017a1594eSVivien Didelot for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) { 142117a1594eSVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 142217a1594eSVivien Didelot if (err) 142317a1594eSVivien Didelot return err; 142417a1594eSVivien Didelot } 142517a1594eSVivien Didelot } 142617a1594eSVivien Didelot 142717a1594eSVivien Didelot return 0; 142881228996SVivien Didelot } 142981228996SVivien Didelot 1430749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port) 1431749efcb8SVivien Didelot { 1432749efcb8SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1433749efcb8SVivien Didelot int err; 1434749efcb8SVivien Didelot 1435749efcb8SVivien Didelot mutex_lock(&chip->reg_lock); 1436e606ca36SVivien Didelot err = mv88e6xxx_g1_atu_remove(chip, 0, port, false); 1437749efcb8SVivien Didelot mutex_unlock(&chip->reg_lock); 1438749efcb8SVivien Didelot 1439749efcb8SVivien Didelot if (err) 1440774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to flush ATU\n", port); 1441749efcb8SVivien Didelot } 1442749efcb8SVivien Didelot 1443b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip) 1444b486d7c9SVivien Didelot { 1445b486d7c9SVivien Didelot if (!chip->info->max_vid) 1446b486d7c9SVivien Didelot return 0; 1447b486d7c9SVivien Didelot 1448b486d7c9SVivien Didelot return mv88e6xxx_g1_vtu_flush(chip); 1449b486d7c9SVivien Didelot } 1450b486d7c9SVivien Didelot 1451f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip, 1452f1394b78SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 1453f1394b78SVivien Didelot { 1454f1394b78SVivien Didelot if (!chip->info->ops->vtu_getnext) 1455f1394b78SVivien Didelot return -EOPNOTSUPP; 1456f1394b78SVivien Didelot 1457f1394b78SVivien Didelot return chip->info->ops->vtu_getnext(chip, entry); 1458f1394b78SVivien Didelot } 1459f1394b78SVivien Didelot 14600ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, 14610ad5daf6SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 14620ad5daf6SVivien Didelot { 14630ad5daf6SVivien Didelot if (!chip->info->ops->vtu_loadpurge) 14640ad5daf6SVivien Didelot return -EOPNOTSUPP; 14650ad5daf6SVivien Didelot 14660ad5daf6SVivien Didelot return chip->info->ops->vtu_loadpurge(chip, entry); 14670ad5daf6SVivien Didelot } 14680ad5daf6SVivien Didelot 1469d7f435f9SVivien Didelot static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) 1470fad09c73SVivien Didelot { 1471fad09c73SVivien Didelot DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); 14723afb4bdeSVivien Didelot struct mv88e6xxx_vtu_entry vlan = { 14733afb4bdeSVivien Didelot .vid = chip->info->max_vid, 14743afb4bdeSVivien Didelot }; 1475fad09c73SVivien Didelot int i, err; 1476fad09c73SVivien Didelot 1477fad09c73SVivien Didelot bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); 1478fad09c73SVivien Didelot 1479fad09c73SVivien Didelot /* Set every FID bit used by the (un)bridged ports */ 1480370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1481b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, i, fid); 1482fad09c73SVivien Didelot if (err) 1483fad09c73SVivien Didelot return err; 1484fad09c73SVivien Didelot 1485fad09c73SVivien Didelot set_bit(*fid, fid_bitmap); 1486fad09c73SVivien Didelot } 1487fad09c73SVivien Didelot 1488fad09c73SVivien Didelot /* Set every FID bit used by the VLAN entries */ 1489fad09c73SVivien Didelot do { 1490f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1491fad09c73SVivien Didelot if (err) 1492fad09c73SVivien Didelot return err; 1493fad09c73SVivien Didelot 1494fad09c73SVivien Didelot if (!vlan.valid) 1495fad09c73SVivien Didelot break; 1496fad09c73SVivien Didelot 1497fad09c73SVivien Didelot set_bit(vlan.fid, fid_bitmap); 14983cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 1499fad09c73SVivien Didelot 1500fad09c73SVivien Didelot /* The reset value 0x000 is used to indicate that multiple address 1501fad09c73SVivien Didelot * databases are not needed. Return the next positive available. 1502fad09c73SVivien Didelot */ 1503fad09c73SVivien Didelot *fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1); 1504fad09c73SVivien Didelot if (unlikely(*fid >= mv88e6xxx_num_databases(chip))) 1505fad09c73SVivien Didelot return -ENOSPC; 1506fad09c73SVivien Didelot 1507fad09c73SVivien Didelot /* Clear the database */ 1508daefc943SVivien Didelot return mv88e6xxx_g1_atu_flush(chip, *fid, true); 1509fad09c73SVivien Didelot } 1510fad09c73SVivien Didelot 1511567aa59aSVivien Didelot static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid, 1512567aa59aSVivien Didelot struct mv88e6xxx_vtu_entry *entry, bool new) 1513fad09c73SVivien Didelot { 1514fad09c73SVivien Didelot int err; 1515fad09c73SVivien Didelot 1516fad09c73SVivien Didelot if (!vid) 1517fad09c73SVivien Didelot return -EINVAL; 1518fad09c73SVivien Didelot 15193afb4bdeSVivien Didelot entry->vid = vid - 1; 15203afb4bdeSVivien Didelot entry->valid = false; 1521fad09c73SVivien Didelot 1522f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, entry); 1523fad09c73SVivien Didelot if (err) 1524fad09c73SVivien Didelot return err; 1525fad09c73SVivien Didelot 1526567aa59aSVivien Didelot if (entry->vid == vid && entry->valid) 1527567aa59aSVivien Didelot return 0; 1528fad09c73SVivien Didelot 1529567aa59aSVivien Didelot if (new) { 1530567aa59aSVivien Didelot int i; 1531567aa59aSVivien Didelot 1532567aa59aSVivien Didelot /* Initialize a fresh VLAN entry */ 1533567aa59aSVivien Didelot memset(entry, 0, sizeof(*entry)); 1534567aa59aSVivien Didelot entry->valid = true; 1535567aa59aSVivien Didelot entry->vid = vid; 1536567aa59aSVivien Didelot 1537553a768dSVivien Didelot /* Exclude all ports */ 1538567aa59aSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 1539553a768dSVivien Didelot entry->member[i] = 15407ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 1541567aa59aSVivien Didelot 1542567aa59aSVivien Didelot return mv88e6xxx_atu_new(chip, &entry->fid); 1543fad09c73SVivien Didelot } 1544fad09c73SVivien Didelot 1545567aa59aSVivien Didelot /* switchdev expects -EOPNOTSUPP to honor software VLANs */ 1546567aa59aSVivien Didelot return -EOPNOTSUPP; 1547fad09c73SVivien Didelot } 1548fad09c73SVivien Didelot 1549fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, 1550fad09c73SVivien Didelot u16 vid_begin, u16 vid_end) 1551fad09c73SVivien Didelot { 155204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 15533afb4bdeSVivien Didelot struct mv88e6xxx_vtu_entry vlan = { 15543afb4bdeSVivien Didelot .vid = vid_begin - 1, 15553afb4bdeSVivien Didelot }; 1556fad09c73SVivien Didelot int i, err; 1557fad09c73SVivien Didelot 1558db06ae41SAndrew Lunn /* DSA and CPU ports have to be members of multiple vlans */ 1559db06ae41SAndrew Lunn if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 1560db06ae41SAndrew Lunn return 0; 1561db06ae41SAndrew Lunn 1562fad09c73SVivien Didelot if (!vid_begin) 1563fad09c73SVivien Didelot return -EOPNOTSUPP; 1564fad09c73SVivien Didelot 1565fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1566fad09c73SVivien Didelot 1567fad09c73SVivien Didelot do { 1568f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1569fad09c73SVivien Didelot if (err) 1570fad09c73SVivien Didelot goto unlock; 1571fad09c73SVivien Didelot 1572fad09c73SVivien Didelot if (!vlan.valid) 1573fad09c73SVivien Didelot break; 1574fad09c73SVivien Didelot 1575fad09c73SVivien Didelot if (vlan.vid > vid_end) 1576fad09c73SVivien Didelot break; 1577fad09c73SVivien Didelot 1578370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1579fad09c73SVivien Didelot if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i)) 1580fad09c73SVivien Didelot continue; 1581fad09c73SVivien Didelot 1582cd886469SAndrew Lunn if (!ds->ports[i].slave) 158366e2809dSAndrew Lunn continue; 158466e2809dSAndrew Lunn 1585bd00e053SVivien Didelot if (vlan.member[i] == 15867ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1587fad09c73SVivien Didelot continue; 1588fad09c73SVivien Didelot 1589c8652c83SVivien Didelot if (dsa_to_port(ds, i)->bridge_dev == 1590fae8a25eSVivien Didelot ds->ports[port].bridge_dev) 1591fad09c73SVivien Didelot break; /* same bridge, check next VLAN */ 1592fad09c73SVivien Didelot 1593c8652c83SVivien Didelot if (!dsa_to_port(ds, i)->bridge_dev) 159466e2809dSAndrew Lunn continue; 159566e2809dSAndrew Lunn 1596743fcc28SAndrew Lunn dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n", 1597743fcc28SAndrew Lunn port, vlan.vid, i, 1598c8652c83SVivien Didelot netdev_name(dsa_to_port(ds, i)->bridge_dev)); 1599fad09c73SVivien Didelot err = -EOPNOTSUPP; 1600fad09c73SVivien Didelot goto unlock; 1601fad09c73SVivien Didelot } 1602fad09c73SVivien Didelot } while (vlan.vid < vid_end); 1603fad09c73SVivien Didelot 1604fad09c73SVivien Didelot unlock: 1605fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1606fad09c73SVivien Didelot 1607fad09c73SVivien Didelot return err; 1608fad09c73SVivien Didelot } 1609fad09c73SVivien Didelot 1610fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, 1611fad09c73SVivien Didelot bool vlan_filtering) 1612fad09c73SVivien Didelot { 161304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 161481c6edb2SVivien Didelot u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE : 161581c6edb2SVivien Didelot MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED; 16160e7b9925SAndrew Lunn int err; 1617fad09c73SVivien Didelot 16183cf3c846SVivien Didelot if (!chip->info->max_vid) 1619fad09c73SVivien Didelot return -EOPNOTSUPP; 1620fad09c73SVivien Didelot 1621fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1622385a0995SVivien Didelot err = mv88e6xxx_port_set_8021q_mode(chip, port, mode); 1623fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1624fad09c73SVivien Didelot 16250e7b9925SAndrew Lunn return err; 1626fad09c73SVivien Didelot } 1627fad09c73SVivien Didelot 1628fad09c73SVivien Didelot static int 1629fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, 163080e02360SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1631fad09c73SVivien Didelot { 163204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1633fad09c73SVivien Didelot int err; 1634fad09c73SVivien Didelot 16353cf3c846SVivien Didelot if (!chip->info->max_vid) 1636fad09c73SVivien Didelot return -EOPNOTSUPP; 1637fad09c73SVivien Didelot 1638fad09c73SVivien Didelot /* If the requested port doesn't belong to the same bridge as the VLAN 1639fad09c73SVivien Didelot * members, do not support it (yet) and fallback to software VLAN. 1640fad09c73SVivien Didelot */ 1641fad09c73SVivien Didelot err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin, 1642fad09c73SVivien Didelot vlan->vid_end); 1643fad09c73SVivien Didelot if (err) 1644fad09c73SVivien Didelot return err; 1645fad09c73SVivien Didelot 1646fad09c73SVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 1647fad09c73SVivien Didelot * so skip the prepare phase. 1648fad09c73SVivien Didelot */ 1649fad09c73SVivien Didelot return 0; 1650fad09c73SVivien Didelot } 1651fad09c73SVivien Didelot 1652a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, 1653a4c93ae1SAndrew Lunn const unsigned char *addr, u16 vid, 1654a4c93ae1SAndrew Lunn u8 state) 1655a4c93ae1SAndrew Lunn { 1656a4c93ae1SAndrew Lunn struct mv88e6xxx_vtu_entry vlan; 1657a4c93ae1SAndrew Lunn struct mv88e6xxx_atu_entry entry; 1658a4c93ae1SAndrew Lunn int err; 1659a4c93ae1SAndrew Lunn 1660a4c93ae1SAndrew Lunn /* Null VLAN ID corresponds to the port private database */ 1661a4c93ae1SAndrew Lunn if (vid == 0) 1662a4c93ae1SAndrew Lunn err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid); 1663a4c93ae1SAndrew Lunn else 1664a4c93ae1SAndrew Lunn err = mv88e6xxx_vtu_get(chip, vid, &vlan, false); 1665a4c93ae1SAndrew Lunn if (err) 1666a4c93ae1SAndrew Lunn return err; 1667a4c93ae1SAndrew Lunn 1668a4c93ae1SAndrew Lunn entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED; 1669a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 1670a4c93ae1SAndrew Lunn eth_addr_dec(entry.mac); 1671a4c93ae1SAndrew Lunn 1672a4c93ae1SAndrew Lunn err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry); 1673a4c93ae1SAndrew Lunn if (err) 1674a4c93ae1SAndrew Lunn return err; 1675a4c93ae1SAndrew Lunn 1676a4c93ae1SAndrew Lunn /* Initialize a fresh ATU entry if it isn't found */ 1677a4c93ae1SAndrew Lunn if (entry.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED || 1678a4c93ae1SAndrew Lunn !ether_addr_equal(entry.mac, addr)) { 1679a4c93ae1SAndrew Lunn memset(&entry, 0, sizeof(entry)); 1680a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 1681a4c93ae1SAndrew Lunn } 1682a4c93ae1SAndrew Lunn 1683a4c93ae1SAndrew Lunn /* Purge the ATU entry only if no port is using it anymore */ 1684a4c93ae1SAndrew Lunn if (state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) { 1685a4c93ae1SAndrew Lunn entry.portvec &= ~BIT(port); 1686a4c93ae1SAndrew Lunn if (!entry.portvec) 1687a4c93ae1SAndrew Lunn entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED; 1688a4c93ae1SAndrew Lunn } else { 1689a4c93ae1SAndrew Lunn entry.portvec |= BIT(port); 1690a4c93ae1SAndrew Lunn entry.state = state; 1691a4c93ae1SAndrew Lunn } 1692a4c93ae1SAndrew Lunn 1693a4c93ae1SAndrew Lunn return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry); 1694a4c93ae1SAndrew Lunn } 1695a4c93ae1SAndrew Lunn 169687fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port, 169787fa886eSAndrew Lunn u16 vid) 169887fa886eSAndrew Lunn { 169987fa886eSAndrew Lunn const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 170087fa886eSAndrew Lunn u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC; 170187fa886eSAndrew Lunn 170287fa886eSAndrew Lunn return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state); 170387fa886eSAndrew Lunn } 170487fa886eSAndrew Lunn 170587fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid) 170687fa886eSAndrew Lunn { 170787fa886eSAndrew Lunn int port; 170887fa886eSAndrew Lunn int err; 170987fa886eSAndrew Lunn 171087fa886eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 171187fa886eSAndrew Lunn err = mv88e6xxx_port_add_broadcast(chip, port, vid); 171287fa886eSAndrew Lunn if (err) 171387fa886eSAndrew Lunn return err; 171487fa886eSAndrew Lunn } 171587fa886eSAndrew Lunn 171687fa886eSAndrew Lunn return 0; 171787fa886eSAndrew Lunn } 171887fa886eSAndrew Lunn 1719fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port, 1720c91498e1SVivien Didelot u16 vid, u8 member) 1721fad09c73SVivien Didelot { 1722b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1723fad09c73SVivien Didelot int err; 1724fad09c73SVivien Didelot 1725567aa59aSVivien Didelot err = mv88e6xxx_vtu_get(chip, vid, &vlan, true); 1726fad09c73SVivien Didelot if (err) 1727fad09c73SVivien Didelot return err; 1728fad09c73SVivien Didelot 1729c91498e1SVivien Didelot vlan.member[port] = member; 1730fad09c73SVivien Didelot 173187fa886eSAndrew Lunn err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 173287fa886eSAndrew Lunn if (err) 173387fa886eSAndrew Lunn return err; 173487fa886eSAndrew Lunn 173587fa886eSAndrew Lunn return mv88e6xxx_broadcast_setup(chip, vid); 1736fad09c73SVivien Didelot } 1737fad09c73SVivien Didelot 1738fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, 173980e02360SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1740fad09c73SVivien Didelot { 174104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1742fad09c73SVivien Didelot bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; 1743fad09c73SVivien Didelot bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 1744c91498e1SVivien Didelot u8 member; 1745fad09c73SVivien Didelot u16 vid; 1746fad09c73SVivien Didelot 17473cf3c846SVivien Didelot if (!chip->info->max_vid) 1748fad09c73SVivien Didelot return; 1749fad09c73SVivien Didelot 1750c91498e1SVivien Didelot if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 17517ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED; 1752c91498e1SVivien Didelot else if (untagged) 17537ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED; 1754c91498e1SVivien Didelot else 17557ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED; 1756c91498e1SVivien Didelot 1757fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1758fad09c73SVivien Didelot 1759fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) 1760c91498e1SVivien Didelot if (_mv88e6xxx_port_vlan_add(chip, port, vid, member)) 1761774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port, 1762fad09c73SVivien Didelot vid, untagged ? 'u' : 't'); 1763fad09c73SVivien Didelot 176477064f37SVivien Didelot if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end)) 1765774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to set PVID %d\n", port, 1766fad09c73SVivien Didelot vlan->vid_end); 1767fad09c73SVivien Didelot 1768fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1769fad09c73SVivien Didelot } 1770fad09c73SVivien Didelot 1771fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip, 1772fad09c73SVivien Didelot int port, u16 vid) 1773fad09c73SVivien Didelot { 1774b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1775fad09c73SVivien Didelot int i, err; 1776fad09c73SVivien Didelot 1777567aa59aSVivien Didelot err = mv88e6xxx_vtu_get(chip, vid, &vlan, false); 1778fad09c73SVivien Didelot if (err) 1779fad09c73SVivien Didelot return err; 1780fad09c73SVivien Didelot 1781fad09c73SVivien Didelot /* Tell switchdev if this VLAN is handled in software */ 17827ec60d6eSVivien Didelot if (vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1783fad09c73SVivien Didelot return -EOPNOTSUPP; 1784fad09c73SVivien Didelot 17857ec60d6eSVivien Didelot vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 1786fad09c73SVivien Didelot 1787fad09c73SVivien Didelot /* keep the VLAN unless all ports are excluded */ 1788fad09c73SVivien Didelot vlan.valid = false; 1789370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 17907ec60d6eSVivien Didelot if (vlan.member[i] != 17917ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) { 1792fad09c73SVivien Didelot vlan.valid = true; 1793fad09c73SVivien Didelot break; 1794fad09c73SVivien Didelot } 1795fad09c73SVivien Didelot } 1796fad09c73SVivien Didelot 17970ad5daf6SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 1798fad09c73SVivien Didelot if (err) 1799fad09c73SVivien Didelot return err; 1800fad09c73SVivien Didelot 1801e606ca36SVivien Didelot return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); 1802fad09c73SVivien Didelot } 1803fad09c73SVivien Didelot 1804fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, 1805fad09c73SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1806fad09c73SVivien Didelot { 180704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1808fad09c73SVivien Didelot u16 pvid, vid; 1809fad09c73SVivien Didelot int err = 0; 1810fad09c73SVivien Didelot 18113cf3c846SVivien Didelot if (!chip->info->max_vid) 1812fad09c73SVivien Didelot return -EOPNOTSUPP; 1813fad09c73SVivien Didelot 1814fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1815fad09c73SVivien Didelot 181677064f37SVivien Didelot err = mv88e6xxx_port_get_pvid(chip, port, &pvid); 1817fad09c73SVivien Didelot if (err) 1818fad09c73SVivien Didelot goto unlock; 1819fad09c73SVivien Didelot 1820fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { 1821fad09c73SVivien Didelot err = _mv88e6xxx_port_vlan_del(chip, port, vid); 1822fad09c73SVivien Didelot if (err) 1823fad09c73SVivien Didelot goto unlock; 1824fad09c73SVivien Didelot 1825fad09c73SVivien Didelot if (vid == pvid) { 182677064f37SVivien Didelot err = mv88e6xxx_port_set_pvid(chip, port, 0); 1827fad09c73SVivien Didelot if (err) 1828fad09c73SVivien Didelot goto unlock; 1829fad09c73SVivien Didelot } 1830fad09c73SVivien Didelot } 1831fad09c73SVivien Didelot 1832fad09c73SVivien Didelot unlock: 1833fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1834fad09c73SVivien Didelot 1835fad09c73SVivien Didelot return err; 1836fad09c73SVivien Didelot } 1837fad09c73SVivien Didelot 18381b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, 18396c2c1dcbSArkadi Sharshevsky const unsigned char *addr, u16 vid) 1840fad09c73SVivien Didelot { 184104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 18421b6dd556SArkadi Sharshevsky int err; 1843fad09c73SVivien Didelot 1844fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 18451b6dd556SArkadi Sharshevsky err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 18461b6dd556SArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 1847fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 18481b6dd556SArkadi Sharshevsky 18491b6dd556SArkadi Sharshevsky return err; 1850fad09c73SVivien Didelot } 1851fad09c73SVivien Didelot 1852fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, 18536c2c1dcbSArkadi Sharshevsky const unsigned char *addr, u16 vid) 1854fad09c73SVivien Didelot { 185504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 185683dabd1fSVivien Didelot int err; 1857fad09c73SVivien Didelot 1858fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 18596c2c1dcbSArkadi Sharshevsky err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 186027c0e600SVivien Didelot MV88E6XXX_G1_ATU_DATA_STATE_UNUSED); 1861fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1862fad09c73SVivien Didelot 186383dabd1fSVivien Didelot return err; 1864fad09c73SVivien Didelot } 1865fad09c73SVivien Didelot 186683dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, 1867fad09c73SVivien Didelot u16 fid, u16 vid, int port, 18682bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 1869fad09c73SVivien Didelot { 1870dabc1a96SVivien Didelot struct mv88e6xxx_atu_entry addr; 18712bedde1aSArkadi Sharshevsky bool is_static; 1872fad09c73SVivien Didelot int err; 1873fad09c73SVivien Didelot 187427c0e600SVivien Didelot addr.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED; 1875dabc1a96SVivien Didelot eth_broadcast_addr(addr.mac); 1876fad09c73SVivien Didelot 1877fad09c73SVivien Didelot do { 1878a61e5406SAndrew Lunn mutex_lock(&chip->reg_lock); 1879dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); 1880a61e5406SAndrew Lunn mutex_unlock(&chip->reg_lock); 1881fad09c73SVivien Didelot if (err) 188283dabd1fSVivien Didelot return err; 1883fad09c73SVivien Didelot 188427c0e600SVivien Didelot if (addr.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) 1885fad09c73SVivien Didelot break; 1886fad09c73SVivien Didelot 188701bd96c8SVivien Didelot if (addr.trunk || (addr.portvec & BIT(port)) == 0) 188883dabd1fSVivien Didelot continue; 1889fad09c73SVivien Didelot 189083dabd1fSVivien Didelot if (!is_unicast_ether_addr(addr.mac)) 189183dabd1fSVivien Didelot continue; 189283dabd1fSVivien Didelot 18932bedde1aSArkadi Sharshevsky is_static = (addr.state == 18942bedde1aSArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 18952bedde1aSArkadi Sharshevsky err = cb(addr.mac, vid, is_static, data); 189683dabd1fSVivien Didelot if (err) 189783dabd1fSVivien Didelot return err; 1898fad09c73SVivien Didelot } while (!is_broadcast_ether_addr(addr.mac)); 1899fad09c73SVivien Didelot 1900fad09c73SVivien Didelot return err; 1901fad09c73SVivien Didelot } 1902fad09c73SVivien Didelot 190383dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, 19042bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 190583dabd1fSVivien Didelot { 1906b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan = { 19073cf3c846SVivien Didelot .vid = chip->info->max_vid, 190883dabd1fSVivien Didelot }; 190983dabd1fSVivien Didelot u16 fid; 191083dabd1fSVivien Didelot int err; 191183dabd1fSVivien Didelot 191283dabd1fSVivien Didelot /* Dump port's default Filtering Information Database (VLAN ID 0) */ 1913a61e5406SAndrew Lunn mutex_lock(&chip->reg_lock); 1914b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &fid); 1915a61e5406SAndrew Lunn mutex_unlock(&chip->reg_lock); 1916a61e5406SAndrew Lunn 191783dabd1fSVivien Didelot if (err) 191883dabd1fSVivien Didelot return err; 191983dabd1fSVivien Didelot 19202bedde1aSArkadi Sharshevsky err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data); 192183dabd1fSVivien Didelot if (err) 192283dabd1fSVivien Didelot return err; 192383dabd1fSVivien Didelot 192483dabd1fSVivien Didelot /* Dump VLANs' Filtering Information Databases */ 192583dabd1fSVivien Didelot do { 1926a61e5406SAndrew Lunn mutex_lock(&chip->reg_lock); 1927f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1928a61e5406SAndrew Lunn mutex_unlock(&chip->reg_lock); 192983dabd1fSVivien Didelot if (err) 193083dabd1fSVivien Didelot return err; 193183dabd1fSVivien Didelot 193283dabd1fSVivien Didelot if (!vlan.valid) 193383dabd1fSVivien Didelot break; 193483dabd1fSVivien Didelot 193583dabd1fSVivien Didelot err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port, 19362bedde1aSArkadi Sharshevsky cb, data); 193783dabd1fSVivien Didelot if (err) 193883dabd1fSVivien Didelot return err; 19393cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 194083dabd1fSVivien Didelot 194183dabd1fSVivien Didelot return err; 194283dabd1fSVivien Didelot } 194383dabd1fSVivien Didelot 1944fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, 19452bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 1946fad09c73SVivien Didelot { 194704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1948fad09c73SVivien Didelot 1949a61e5406SAndrew Lunn return mv88e6xxx_port_db_dump(chip, port, cb, data); 1950fad09c73SVivien Didelot } 1951fad09c73SVivien Didelot 1952240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, 1953240ea3efSVivien Didelot struct net_device *br) 1954240ea3efSVivien Didelot { 1955e96a6e02SVivien Didelot struct dsa_switch *ds; 1956240ea3efSVivien Didelot int port; 1957e96a6e02SVivien Didelot int dev; 1958240ea3efSVivien Didelot int err; 1959240ea3efSVivien Didelot 1960240ea3efSVivien Didelot /* Remap the Port VLAN of each local bridge group member */ 1961240ea3efSVivien Didelot for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) { 1962240ea3efSVivien Didelot if (chip->ds->ports[port].bridge_dev == br) { 1963240ea3efSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, port); 1964240ea3efSVivien Didelot if (err) 1965240ea3efSVivien Didelot return err; 1966240ea3efSVivien Didelot } 1967240ea3efSVivien Didelot } 1968240ea3efSVivien Didelot 1969e96a6e02SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1970e96a6e02SVivien Didelot return 0; 1971e96a6e02SVivien Didelot 1972e96a6e02SVivien Didelot /* Remap the Port VLAN of each cross-chip bridge group member */ 1973e96a6e02SVivien Didelot for (dev = 0; dev < DSA_MAX_SWITCHES; ++dev) { 1974e96a6e02SVivien Didelot ds = chip->ds->dst->ds[dev]; 1975e96a6e02SVivien Didelot if (!ds) 1976e96a6e02SVivien Didelot break; 1977e96a6e02SVivien Didelot 1978e96a6e02SVivien Didelot for (port = 0; port < ds->num_ports; ++port) { 1979e96a6e02SVivien Didelot if (ds->ports[port].bridge_dev == br) { 1980e96a6e02SVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 1981e96a6e02SVivien Didelot if (err) 1982e96a6e02SVivien Didelot return err; 1983e96a6e02SVivien Didelot } 1984e96a6e02SVivien Didelot } 1985e96a6e02SVivien Didelot } 1986e96a6e02SVivien Didelot 1987240ea3efSVivien Didelot return 0; 1988240ea3efSVivien Didelot } 1989240ea3efSVivien Didelot 1990fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, 1991fae8a25eSVivien Didelot struct net_device *br) 1992fad09c73SVivien Didelot { 199304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1994240ea3efSVivien Didelot int err; 1995fad09c73SVivien Didelot 1996fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1997240ea3efSVivien Didelot err = mv88e6xxx_bridge_map(chip, br); 1998fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1999fad09c73SVivien Didelot 2000fad09c73SVivien Didelot return err; 2001fad09c73SVivien Didelot } 2002fad09c73SVivien Didelot 2003f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, 2004f123f2fbSVivien Didelot struct net_device *br) 2005fad09c73SVivien Didelot { 200604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2007fad09c73SVivien Didelot 2008fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 2009240ea3efSVivien Didelot if (mv88e6xxx_bridge_map(chip, br) || 2010240ea3efSVivien Didelot mv88e6xxx_port_vlan_map(chip, port)) 2011240ea3efSVivien Didelot dev_err(ds->dev, "failed to remap in-chip Port VLAN\n"); 2012fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 2013fad09c73SVivien Didelot } 2014fad09c73SVivien Didelot 2015aec5ac88SVivien Didelot static int mv88e6xxx_crosschip_bridge_join(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 int err; 2020aec5ac88SVivien Didelot 2021aec5ac88SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 2022aec5ac88SVivien Didelot return 0; 2023aec5ac88SVivien Didelot 2024aec5ac88SVivien Didelot mutex_lock(&chip->reg_lock); 2025aec5ac88SVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 2026aec5ac88SVivien Didelot mutex_unlock(&chip->reg_lock); 2027aec5ac88SVivien Didelot 2028aec5ac88SVivien Didelot return err; 2029aec5ac88SVivien Didelot } 2030aec5ac88SVivien Didelot 2031aec5ac88SVivien Didelot static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev, 2032aec5ac88SVivien Didelot int port, struct net_device *br) 2033aec5ac88SVivien Didelot { 2034aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2035aec5ac88SVivien Didelot 2036aec5ac88SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 2037aec5ac88SVivien Didelot return; 2038aec5ac88SVivien Didelot 2039aec5ac88SVivien Didelot mutex_lock(&chip->reg_lock); 2040aec5ac88SVivien Didelot if (mv88e6xxx_pvt_map(chip, dev, port)) 2041aec5ac88SVivien Didelot dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); 2042aec5ac88SVivien Didelot mutex_unlock(&chip->reg_lock); 2043aec5ac88SVivien Didelot } 2044aec5ac88SVivien Didelot 204517e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip) 204617e708baSVivien Didelot { 204717e708baSVivien Didelot if (chip->info->ops->reset) 204817e708baSVivien Didelot return chip->info->ops->reset(chip); 204917e708baSVivien Didelot 205017e708baSVivien Didelot return 0; 205117e708baSVivien Didelot } 205217e708baSVivien Didelot 2053309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) 2054309eca6dSVivien Didelot { 2055309eca6dSVivien Didelot struct gpio_desc *gpiod = chip->reset; 2056309eca6dSVivien Didelot 2057309eca6dSVivien Didelot /* If there is a GPIO connected to the reset pin, toggle it */ 2058309eca6dSVivien Didelot if (gpiod) { 2059309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 1); 2060309eca6dSVivien Didelot usleep_range(10000, 20000); 2061309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 0); 2062309eca6dSVivien Didelot usleep_range(10000, 20000); 2063309eca6dSVivien Didelot } 2064309eca6dSVivien Didelot } 2065309eca6dSVivien Didelot 20664ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip) 20674ac4b5a6SVivien Didelot { 20684ac4b5a6SVivien Didelot int i, err; 20694ac4b5a6SVivien Didelot 20704ac4b5a6SVivien Didelot /* Set all ports to the Disabled state */ 20714ac4b5a6SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 2072f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED); 20734ac4b5a6SVivien Didelot if (err) 20744ac4b5a6SVivien Didelot return err; 20754ac4b5a6SVivien Didelot } 20764ac4b5a6SVivien Didelot 20774ac4b5a6SVivien Didelot /* Wait for transmit queues to drain, 20784ac4b5a6SVivien Didelot * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps. 20794ac4b5a6SVivien Didelot */ 20804ac4b5a6SVivien Didelot usleep_range(2000, 4000); 20814ac4b5a6SVivien Didelot 20824ac4b5a6SVivien Didelot return 0; 20834ac4b5a6SVivien Didelot } 20844ac4b5a6SVivien Didelot 2085fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip) 2086fad09c73SVivien Didelot { 2087a935c052SVivien Didelot int err; 2088fad09c73SVivien Didelot 20894ac4b5a6SVivien Didelot err = mv88e6xxx_disable_ports(chip); 20900e7b9925SAndrew Lunn if (err) 20910e7b9925SAndrew Lunn return err; 2092fad09c73SVivien Didelot 2093309eca6dSVivien Didelot mv88e6xxx_hardware_reset(chip); 2094fad09c73SVivien Didelot 209517e708baSVivien Didelot return mv88e6xxx_software_reset(chip); 2096fad09c73SVivien Didelot } 2097fad09c73SVivien Didelot 20984314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, 209931bef4e9SVivien Didelot enum mv88e6xxx_frame_mode frame, 210031bef4e9SVivien Didelot enum mv88e6xxx_egress_mode egress, u16 etype) 210156995cbcSAndrew Lunn { 210256995cbcSAndrew Lunn int err; 210356995cbcSAndrew Lunn 21044314557cSVivien Didelot if (!chip->info->ops->port_set_frame_mode) 21054314557cSVivien Didelot return -EOPNOTSUPP; 21064314557cSVivien Didelot 21074314557cSVivien Didelot err = mv88e6xxx_port_set_egress_mode(chip, port, egress); 210856995cbcSAndrew Lunn if (err) 210956995cbcSAndrew Lunn return err; 211056995cbcSAndrew Lunn 21114314557cSVivien Didelot err = chip->info->ops->port_set_frame_mode(chip, port, frame); 21124314557cSVivien Didelot if (err) 21134314557cSVivien Didelot return err; 21144314557cSVivien Didelot 21154314557cSVivien Didelot if (chip->info->ops->port_set_ether_type) 21164314557cSVivien Didelot return chip->info->ops->port_set_ether_type(chip, port, etype); 21174314557cSVivien Didelot 21184314557cSVivien Didelot return 0; 21194314557cSVivien Didelot } 21204314557cSVivien Didelot 21214314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port) 21224314557cSVivien Didelot { 21234314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL, 212431bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 2125b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 21264314557cSVivien Didelot } 21274314557cSVivien Didelot 21284314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port) 21294314557cSVivien Didelot { 21304314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA, 213131bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 2132b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 21334314557cSVivien Didelot } 21344314557cSVivien Didelot 21354314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port) 21364314557cSVivien Didelot { 21374314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, 21384314557cSVivien Didelot MV88E6XXX_FRAME_MODE_ETHERTYPE, 213931bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_ETHERTYPE, 214031bef4e9SVivien Didelot ETH_P_EDSA); 21414314557cSVivien Didelot } 21424314557cSVivien Didelot 21434314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port) 21444314557cSVivien Didelot { 21454314557cSVivien Didelot if (dsa_is_dsa_port(chip->ds, port)) 21464314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 21474314557cSVivien Didelot 21482b3e9891SVivien Didelot if (dsa_is_user_port(chip->ds, port)) 21494314557cSVivien Didelot return mv88e6xxx_set_port_mode_normal(chip, port); 21504314557cSVivien Didelot 21514314557cSVivien Didelot /* Setup CPU port mode depending on its supported tag format */ 21524314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA) 21534314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 21544314557cSVivien Didelot 21554314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA) 21564314557cSVivien Didelot return mv88e6xxx_set_port_mode_edsa(chip, port); 21574314557cSVivien Didelot 21584314557cSVivien Didelot return -EINVAL; 21594314557cSVivien Didelot } 21604314557cSVivien Didelot 2161ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port) 2162ea698f4fSVivien Didelot { 2163ea698f4fSVivien Didelot bool message = dsa_is_dsa_port(chip->ds, port); 2164ea698f4fSVivien Didelot 2165ea698f4fSVivien Didelot return mv88e6xxx_port_set_message_port(chip, port, message); 2166ea698f4fSVivien Didelot } 2167ea698f4fSVivien Didelot 2168601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) 2169601aeed3SVivien Didelot { 21703ee50cbfSVivien Didelot struct dsa_switch *ds = chip->ds; 21713ee50cbfSVivien Didelot bool flood; 2172601aeed3SVivien Didelot 2173601aeed3SVivien Didelot /* Upstream ports flood frames with unknown unicast or multicast DA */ 21743ee50cbfSVivien Didelot flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port); 2175601aeed3SVivien Didelot if (chip->info->ops->port_set_egress_floods) 2176601aeed3SVivien Didelot return chip->info->ops->port_set_egress_floods(chip, port, 2177601aeed3SVivien Didelot flood, flood); 2178601aeed3SVivien Didelot 2179601aeed3SVivien Didelot return 0; 2180601aeed3SVivien Didelot } 2181601aeed3SVivien Didelot 21826d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, 21836d91782fSAndrew Lunn bool on) 21846d91782fSAndrew Lunn { 2185523a8904SVivien Didelot if (chip->info->ops->serdes_power) 2186523a8904SVivien Didelot return chip->info->ops->serdes_power(chip, port, on); 21876d91782fSAndrew Lunn 2188523a8904SVivien Didelot return 0; 21896d91782fSAndrew Lunn } 21906d91782fSAndrew Lunn 2191fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) 2192fa371c80SVivien Didelot { 2193fa371c80SVivien Didelot struct dsa_switch *ds = chip->ds; 2194fa371c80SVivien Didelot int upstream_port; 2195fa371c80SVivien Didelot int err; 2196fa371c80SVivien Didelot 219707073c79SVivien Didelot upstream_port = dsa_upstream_port(ds, port); 2198fa371c80SVivien Didelot if (chip->info->ops->port_set_upstream_port) { 2199fa371c80SVivien Didelot err = chip->info->ops->port_set_upstream_port(chip, port, 2200fa371c80SVivien Didelot upstream_port); 2201fa371c80SVivien Didelot if (err) 2202fa371c80SVivien Didelot return err; 2203fa371c80SVivien Didelot } 2204fa371c80SVivien Didelot 22050ea54ddaSVivien Didelot if (port == upstream_port) { 22060ea54ddaSVivien Didelot if (chip->info->ops->set_cpu_port) { 22070ea54ddaSVivien Didelot err = chip->info->ops->set_cpu_port(chip, 22080ea54ddaSVivien Didelot upstream_port); 22090ea54ddaSVivien Didelot if (err) 22100ea54ddaSVivien Didelot return err; 22110ea54ddaSVivien Didelot } 22120ea54ddaSVivien Didelot 22130ea54ddaSVivien Didelot if (chip->info->ops->set_egress_port) { 22140ea54ddaSVivien Didelot err = chip->info->ops->set_egress_port(chip, 22150ea54ddaSVivien Didelot upstream_port); 22160ea54ddaSVivien Didelot if (err) 22170ea54ddaSVivien Didelot return err; 22180ea54ddaSVivien Didelot } 22190ea54ddaSVivien Didelot } 22200ea54ddaSVivien Didelot 2221fa371c80SVivien Didelot return 0; 2222fa371c80SVivien Didelot } 2223fa371c80SVivien Didelot 2224fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) 2225fad09c73SVivien Didelot { 2226fad09c73SVivien Didelot struct dsa_switch *ds = chip->ds; 22270e7b9925SAndrew Lunn int err; 2228fad09c73SVivien Didelot u16 reg; 2229fad09c73SVivien Didelot 22307b898469SAndrew Lunn chip->ports[port].chip = chip; 22317b898469SAndrew Lunn chip->ports[port].port = port; 22327b898469SAndrew Lunn 2233d78343d2SVivien Didelot /* MAC Forcing register: don't force link, speed, duplex or flow control 2234d78343d2SVivien Didelot * state to any particular values on physical ports, but force the CPU 2235d78343d2SVivien Didelot * port and all DSA ports to their maximum bandwidth and full duplex. 2236fad09c73SVivien Didelot */ 2237d78343d2SVivien Didelot if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) 2238d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP, 2239d78343d2SVivien Didelot SPEED_MAX, DUPLEX_FULL, 224054186b91SAndrew Lunn PAUSE_OFF, 2241d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 2242fad09c73SVivien Didelot else 2243d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, 2244d78343d2SVivien Didelot SPEED_UNFORCED, DUPLEX_UNFORCED, 224554186b91SAndrew Lunn PAUSE_ON, 2246d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 22470e7b9925SAndrew Lunn if (err) 22480e7b9925SAndrew Lunn return err; 2249fad09c73SVivien Didelot 2250fad09c73SVivien Didelot /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, 2251fad09c73SVivien Didelot * disable Header mode, enable IGMP/MLD snooping, disable VLAN 2252fad09c73SVivien Didelot * tunneling, determine priority by looking at 802.1p and IP 2253fad09c73SVivien Didelot * priority fields (IP prio has precedence), and set STP state 2254fad09c73SVivien Didelot * to Forwarding. 2255fad09c73SVivien Didelot * 2256fad09c73SVivien Didelot * If this is the CPU link, use DSA or EDSA tagging depending 2257fad09c73SVivien Didelot * on which tagging mode was configured. 2258fad09c73SVivien Didelot * 2259fad09c73SVivien Didelot * If this is a link to another switch, use DSA tagging mode. 2260fad09c73SVivien Didelot * 2261fad09c73SVivien Didelot * If this is the upstream port for this switch, enable 2262fad09c73SVivien Didelot * forwarding of unknown unicasts and multicasts. 2263fad09c73SVivien Didelot */ 2264a89b433bSVivien Didelot reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP | 2265a89b433bSVivien Didelot MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | 2266a89b433bSVivien Didelot MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 2267a89b433bSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 22680e7b9925SAndrew Lunn if (err) 22690e7b9925SAndrew Lunn return err; 227056995cbcSAndrew Lunn 2271601aeed3SVivien Didelot err = mv88e6xxx_setup_port_mode(chip, port); 227256995cbcSAndrew Lunn if (err) 227356995cbcSAndrew Lunn return err; 2274fad09c73SVivien Didelot 2275601aeed3SVivien Didelot err = mv88e6xxx_setup_egress_floods(chip, port); 22764314557cSVivien Didelot if (err) 22774314557cSVivien Didelot return err; 22784314557cSVivien Didelot 227904aca993SAndrew Lunn /* Enable the SERDES interface for DSA and CPU ports. Normal 228004aca993SAndrew Lunn * ports SERDES are enabled when the port is enabled, thus 228104aca993SAndrew Lunn * saving a bit of power. 2282fad09c73SVivien Didelot */ 228304aca993SAndrew Lunn if ((dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) { 22846d91782fSAndrew Lunn err = mv88e6xxx_serdes_power(chip, port, true); 22850e7b9925SAndrew Lunn if (err) 22860e7b9925SAndrew Lunn return err; 228704aca993SAndrew Lunn } 2288fad09c73SVivien Didelot 2289fad09c73SVivien Didelot /* Port Control 2: don't force a good FCS, set the maximum frame size to 2290fad09c73SVivien Didelot * 10240 bytes, disable 802.1q tags checking, don't discard tagged or 2291fad09c73SVivien Didelot * untagged frames on this port, do a destination address lookup on all 2292fad09c73SVivien Didelot * received packets as usual, disable ARP mirroring and don't send a 2293fad09c73SVivien Didelot * copy of all transmitted/received frames on this port to the CPU. 2294fad09c73SVivien Didelot */ 2295a23b2961SAndrew Lunn err = mv88e6xxx_port_set_map_da(chip, port); 2296a23b2961SAndrew Lunn if (err) 2297a23b2961SAndrew Lunn return err; 2298a23b2961SAndrew Lunn 2299fa371c80SVivien Didelot err = mv88e6xxx_setup_upstream_port(chip, port); 23000e7b9925SAndrew Lunn if (err) 23010e7b9925SAndrew Lunn return err; 2302fad09c73SVivien Didelot 2303a23b2961SAndrew Lunn err = mv88e6xxx_port_set_8021q_mode(chip, port, 230481c6edb2SVivien Didelot MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED); 2305a23b2961SAndrew Lunn if (err) 2306a23b2961SAndrew Lunn return err; 2307a23b2961SAndrew Lunn 2308cd782656SVivien Didelot if (chip->info->ops->port_set_jumbo_size) { 2309cd782656SVivien Didelot err = chip->info->ops->port_set_jumbo_size(chip, port, 10240); 23105f436666SAndrew Lunn if (err) 23115f436666SAndrew Lunn return err; 23125f436666SAndrew Lunn } 23135f436666SAndrew Lunn 2314fad09c73SVivien Didelot /* Port Association Vector: when learning source addresses 2315fad09c73SVivien Didelot * of packets, add the address to the address database using 2316fad09c73SVivien Didelot * a port bitmap that has only the bit for this port set and 2317fad09c73SVivien Didelot * the other bits clear. 2318fad09c73SVivien Didelot */ 2319fad09c73SVivien Didelot reg = 1 << port; 2320fad09c73SVivien Didelot /* Disable learning for CPU port */ 2321fad09c73SVivien Didelot if (dsa_is_cpu_port(ds, port)) 2322fad09c73SVivien Didelot reg = 0; 2323fad09c73SVivien Didelot 23242a4614e4SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, 23252a4614e4SVivien Didelot reg); 23260e7b9925SAndrew Lunn if (err) 23270e7b9925SAndrew Lunn return err; 2328fad09c73SVivien Didelot 2329fad09c73SVivien Didelot /* Egress rate control 2: disable egress rate control. */ 23302cb8cb14SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2, 23312cb8cb14SVivien Didelot 0x0000); 23320e7b9925SAndrew Lunn if (err) 23330e7b9925SAndrew Lunn return err; 2334fad09c73SVivien Didelot 23350898432cSVivien Didelot if (chip->info->ops->port_pause_limit) { 23360898432cSVivien Didelot err = chip->info->ops->port_pause_limit(chip, port, 0, 0); 2337b35d322aSAndrew Lunn if (err) 2338b35d322aSAndrew Lunn return err; 2339b35d322aSAndrew Lunn } 2340b35d322aSAndrew Lunn 2341c8c94891SVivien Didelot if (chip->info->ops->port_disable_learn_limit) { 2342c8c94891SVivien Didelot err = chip->info->ops->port_disable_learn_limit(chip, port); 2343c8c94891SVivien Didelot if (err) 2344c8c94891SVivien Didelot return err; 2345c8c94891SVivien Didelot } 2346c8c94891SVivien Didelot 23479dbfb4e1SVivien Didelot if (chip->info->ops->port_disable_pri_override) { 23489dbfb4e1SVivien Didelot err = chip->info->ops->port_disable_pri_override(chip, port); 23490e7b9925SAndrew Lunn if (err) 23500e7b9925SAndrew Lunn return err; 2351ef0a7318SAndrew Lunn } 23522bbb33beSAndrew Lunn 2353ef0a7318SAndrew Lunn if (chip->info->ops->port_tag_remap) { 2354ef0a7318SAndrew Lunn err = chip->info->ops->port_tag_remap(chip, port); 23550e7b9925SAndrew Lunn if (err) 23560e7b9925SAndrew Lunn return err; 2357fad09c73SVivien Didelot } 2358fad09c73SVivien Didelot 2359ef70b111SAndrew Lunn if (chip->info->ops->port_egress_rate_limiting) { 2360ef70b111SAndrew Lunn err = chip->info->ops->port_egress_rate_limiting(chip, port); 23610e7b9925SAndrew Lunn if (err) 23620e7b9925SAndrew Lunn return err; 2363fad09c73SVivien Didelot } 2364fad09c73SVivien Didelot 2365ea698f4fSVivien Didelot err = mv88e6xxx_setup_message_port(chip, port); 23660e7b9925SAndrew Lunn if (err) 23670e7b9925SAndrew Lunn return err; 2368fad09c73SVivien Didelot 2369fad09c73SVivien Didelot /* Port based VLAN map: give each port the same default address 2370fad09c73SVivien Didelot * database, and allow bidirectional communication between the 2371fad09c73SVivien Didelot * CPU and DSA port(s), and the other ports. 2372fad09c73SVivien Didelot */ 2373b4e48c50SVivien Didelot err = mv88e6xxx_port_set_fid(chip, port, 0); 23740e7b9925SAndrew Lunn if (err) 23750e7b9925SAndrew Lunn return err; 2376fad09c73SVivien Didelot 2377240ea3efSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, port); 23780e7b9925SAndrew Lunn if (err) 23790e7b9925SAndrew Lunn return err; 2380fad09c73SVivien Didelot 2381fad09c73SVivien Didelot /* Default VLAN ID and priority: don't set a default VLAN 2382fad09c73SVivien Didelot * ID, and set the default packet priority to zero. 2383fad09c73SVivien Didelot */ 2384b7929fb3SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0); 2385fad09c73SVivien Didelot } 2386fad09c73SVivien Didelot 238704aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port, 238804aca993SAndrew Lunn struct phy_device *phydev) 238904aca993SAndrew Lunn { 239004aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 2391523a8904SVivien Didelot int err; 239204aca993SAndrew Lunn 239304aca993SAndrew Lunn mutex_lock(&chip->reg_lock); 2394efd1ba6aSAndrew Lunn 2395523a8904SVivien Didelot err = mv88e6xxx_serdes_power(chip, port, true); 2396efd1ba6aSAndrew Lunn 2397efd1ba6aSAndrew Lunn if (!err && chip->info->ops->serdes_irq_setup) 2398efd1ba6aSAndrew Lunn err = chip->info->ops->serdes_irq_setup(chip, port); 2399efd1ba6aSAndrew Lunn 240004aca993SAndrew Lunn mutex_unlock(&chip->reg_lock); 240104aca993SAndrew Lunn 240204aca993SAndrew Lunn return err; 240304aca993SAndrew Lunn } 240404aca993SAndrew Lunn 240575104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port) 240604aca993SAndrew Lunn { 240704aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 240804aca993SAndrew Lunn 240904aca993SAndrew Lunn mutex_lock(&chip->reg_lock); 2410efd1ba6aSAndrew Lunn 2411efd1ba6aSAndrew Lunn if (chip->info->ops->serdes_irq_free) 2412efd1ba6aSAndrew Lunn chip->info->ops->serdes_irq_free(chip, port); 2413efd1ba6aSAndrew Lunn 2414523a8904SVivien Didelot if (mv88e6xxx_serdes_power(chip, port, false)) 2415523a8904SVivien Didelot dev_err(chip->dev, "failed to power off SERDES\n"); 2416efd1ba6aSAndrew Lunn 241704aca993SAndrew Lunn mutex_unlock(&chip->reg_lock); 241804aca993SAndrew Lunn } 241904aca993SAndrew Lunn 24202cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, 24212cfcd964SVivien Didelot unsigned int ageing_time) 24222cfcd964SVivien Didelot { 242304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 24242cfcd964SVivien Didelot int err; 24252cfcd964SVivien Didelot 24262cfcd964SVivien Didelot mutex_lock(&chip->reg_lock); 2427720c6343SVivien Didelot err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time); 24282cfcd964SVivien Didelot mutex_unlock(&chip->reg_lock); 24292cfcd964SVivien Didelot 24302cfcd964SVivien Didelot return err; 24312cfcd964SVivien Didelot } 24322cfcd964SVivien Didelot 2433447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip) 2434fad09c73SVivien Didelot { 2435fad09c73SVivien Didelot int err; 2436fad09c73SVivien Didelot 2437de227387SAndrew Lunn /* Initialize the statistics unit */ 2438447b1bb8SVivien Didelot if (chip->info->ops->stats_set_histogram) { 2439447b1bb8SVivien Didelot err = chip->info->ops->stats_set_histogram(chip); 2440de227387SAndrew Lunn if (err) 2441de227387SAndrew Lunn return err; 2442447b1bb8SVivien Didelot } 2443de227387SAndrew Lunn 244440cff8fcSAndrew Lunn return mv88e6xxx_g1_stats_clear(chip); 24459729934cSVivien Didelot } 24469729934cSVivien Didelot 2447ea89098eSAndrew Lunn /* The mv88e6390 has some hidden registers used for debug and 2448ea89098eSAndrew Lunn * development. The errata also makes use of them. 2449ea89098eSAndrew Lunn */ 2450ea89098eSAndrew Lunn static int mv88e6390_hidden_write(struct mv88e6xxx_chip *chip, int port, 2451ea89098eSAndrew Lunn int reg, u16 val) 2452ea89098eSAndrew Lunn { 2453ea89098eSAndrew Lunn u16 ctrl; 2454ea89098eSAndrew Lunn int err; 2455ea89098eSAndrew Lunn 2456ea89098eSAndrew Lunn err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_DATA_PORT, 2457ea89098eSAndrew Lunn PORT_RESERVED_1A, val); 2458ea89098eSAndrew Lunn if (err) 2459ea89098eSAndrew Lunn return err; 2460ea89098eSAndrew Lunn 2461ea89098eSAndrew Lunn ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_WRITE | 2462ea89098eSAndrew Lunn PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT | 2463ea89098eSAndrew Lunn reg; 2464ea89098eSAndrew Lunn 2465ea89098eSAndrew Lunn return mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT, 2466ea89098eSAndrew Lunn PORT_RESERVED_1A, ctrl); 2467ea89098eSAndrew Lunn } 2468ea89098eSAndrew Lunn 2469ea89098eSAndrew Lunn static int mv88e6390_hidden_wait(struct mv88e6xxx_chip *chip) 2470ea89098eSAndrew Lunn { 2471ea89098eSAndrew Lunn return mv88e6xxx_wait(chip, PORT_RESERVED_1A_CTRL_PORT, 2472ea89098eSAndrew Lunn PORT_RESERVED_1A, PORT_RESERVED_1A_BUSY); 2473ea89098eSAndrew Lunn } 2474ea89098eSAndrew Lunn 2475ea89098eSAndrew Lunn 2476ea89098eSAndrew Lunn static int mv88e6390_hidden_read(struct mv88e6xxx_chip *chip, int port, 2477ea89098eSAndrew Lunn int reg, u16 *val) 2478ea89098eSAndrew Lunn { 2479ea89098eSAndrew Lunn u16 ctrl; 2480ea89098eSAndrew Lunn int err; 2481ea89098eSAndrew Lunn 2482ea89098eSAndrew Lunn ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_READ | 2483ea89098eSAndrew Lunn PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT | 2484ea89098eSAndrew Lunn reg; 2485ea89098eSAndrew Lunn 2486ea89098eSAndrew Lunn err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT, 2487ea89098eSAndrew Lunn PORT_RESERVED_1A, ctrl); 2488ea89098eSAndrew Lunn if (err) 2489ea89098eSAndrew Lunn return err; 2490ea89098eSAndrew Lunn 2491ea89098eSAndrew Lunn err = mv88e6390_hidden_wait(chip); 2492ea89098eSAndrew Lunn if (err) 2493ea89098eSAndrew Lunn return err; 2494ea89098eSAndrew Lunn 2495ea89098eSAndrew Lunn return mv88e6xxx_port_read(chip, PORT_RESERVED_1A_DATA_PORT, 2496ea89098eSAndrew Lunn PORT_RESERVED_1A, val); 2497ea89098eSAndrew Lunn } 2498ea89098eSAndrew Lunn 2499ea89098eSAndrew Lunn /* Check if the errata has already been applied. */ 2500ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip) 2501ea89098eSAndrew Lunn { 2502ea89098eSAndrew Lunn int port; 2503ea89098eSAndrew Lunn int err; 2504ea89098eSAndrew Lunn u16 val; 2505ea89098eSAndrew Lunn 2506ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 2507ea89098eSAndrew Lunn err = mv88e6390_hidden_read(chip, port, 0, &val); 2508ea89098eSAndrew Lunn if (err) { 2509ea89098eSAndrew Lunn dev_err(chip->dev, 2510ea89098eSAndrew Lunn "Error reading hidden register: %d\n", err); 2511ea89098eSAndrew Lunn return false; 2512ea89098eSAndrew Lunn } 2513ea89098eSAndrew Lunn if (val != 0x01c0) 2514ea89098eSAndrew Lunn return false; 2515ea89098eSAndrew Lunn } 2516ea89098eSAndrew Lunn 2517ea89098eSAndrew Lunn return true; 2518ea89098eSAndrew Lunn } 2519ea89098eSAndrew Lunn 2520ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic 2521ea89098eSAndrew Lunn * values into undocumented hidden registers and then performing a 2522ea89098eSAndrew Lunn * software reset. 2523ea89098eSAndrew Lunn */ 2524ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) 2525ea89098eSAndrew Lunn { 2526ea89098eSAndrew Lunn int port; 2527ea89098eSAndrew Lunn int err; 2528ea89098eSAndrew Lunn 2529ea89098eSAndrew Lunn if (mv88e6390_setup_errata_applied(chip)) 2530ea89098eSAndrew Lunn return 0; 2531ea89098eSAndrew Lunn 2532ea89098eSAndrew Lunn /* Set the ports into blocking mode */ 2533ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 2534ea89098eSAndrew Lunn err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED); 2535ea89098eSAndrew Lunn if (err) 2536ea89098eSAndrew Lunn return err; 2537ea89098eSAndrew Lunn } 2538ea89098eSAndrew Lunn 2539ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 2540ea89098eSAndrew Lunn err = mv88e6390_hidden_write(chip, port, 0, 0x01c0); 2541ea89098eSAndrew Lunn if (err) 2542ea89098eSAndrew Lunn return err; 2543ea89098eSAndrew Lunn } 2544ea89098eSAndrew Lunn 2545ea89098eSAndrew Lunn return mv88e6xxx_software_reset(chip); 2546ea89098eSAndrew Lunn } 2547ea89098eSAndrew Lunn 2548fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds) 2549fad09c73SVivien Didelot { 255004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 25512d2e1dd2SAndrew Lunn u8 cmode; 2552fad09c73SVivien Didelot int err; 2553fad09c73SVivien Didelot int i; 2554fad09c73SVivien Didelot 2555fad09c73SVivien Didelot chip->ds = ds; 2556a3c53be5SAndrew Lunn ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); 2557fad09c73SVivien Didelot 2558fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 2559fad09c73SVivien Didelot 2560ea89098eSAndrew Lunn if (chip->info->ops->setup_errata) { 2561ea89098eSAndrew Lunn err = chip->info->ops->setup_errata(chip); 2562ea89098eSAndrew Lunn if (err) 2563ea89098eSAndrew Lunn goto unlock; 2564ea89098eSAndrew Lunn } 2565ea89098eSAndrew Lunn 25662d2e1dd2SAndrew Lunn /* Cache the cmode of each port. */ 25672d2e1dd2SAndrew Lunn for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 25682d2e1dd2SAndrew Lunn if (chip->info->ops->port_get_cmode) { 25692d2e1dd2SAndrew Lunn err = chip->info->ops->port_get_cmode(chip, i, &cmode); 25702d2e1dd2SAndrew Lunn if (err) 2571e29129fcSDan Carpenter goto unlock; 25722d2e1dd2SAndrew Lunn 25732d2e1dd2SAndrew Lunn chip->ports[i].cmode = cmode; 25742d2e1dd2SAndrew Lunn } 25752d2e1dd2SAndrew Lunn } 25762d2e1dd2SAndrew Lunn 25779729934cSVivien Didelot /* Setup Switch Port Registers */ 2578370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 257991dee144SVivien Didelot if (dsa_is_unused_port(ds, i)) 258091dee144SVivien Didelot continue; 258191dee144SVivien Didelot 25829729934cSVivien Didelot err = mv88e6xxx_setup_port(chip, i); 25839729934cSVivien Didelot if (err) 25849729934cSVivien Didelot goto unlock; 25859729934cSVivien Didelot } 25869729934cSVivien Didelot 2587cd8da8bbSVivien Didelot err = mv88e6xxx_irl_setup(chip); 2588cd8da8bbSVivien Didelot if (err) 2589cd8da8bbSVivien Didelot goto unlock; 2590cd8da8bbSVivien Didelot 259104a69a17SVivien Didelot err = mv88e6xxx_mac_setup(chip); 259204a69a17SVivien Didelot if (err) 259304a69a17SVivien Didelot goto unlock; 259404a69a17SVivien Didelot 25951b17aedfSVivien Didelot err = mv88e6xxx_phy_setup(chip); 25961b17aedfSVivien Didelot if (err) 25971b17aedfSVivien Didelot goto unlock; 25981b17aedfSVivien Didelot 2599b486d7c9SVivien Didelot err = mv88e6xxx_vtu_setup(chip); 2600b486d7c9SVivien Didelot if (err) 2601b486d7c9SVivien Didelot goto unlock; 2602b486d7c9SVivien Didelot 260381228996SVivien Didelot err = mv88e6xxx_pvt_setup(chip); 260481228996SVivien Didelot if (err) 260581228996SVivien Didelot goto unlock; 260681228996SVivien Didelot 2607a2ac29d2SVivien Didelot err = mv88e6xxx_atu_setup(chip); 2608a2ac29d2SVivien Didelot if (err) 2609a2ac29d2SVivien Didelot goto unlock; 2610a2ac29d2SVivien Didelot 261187fa886eSAndrew Lunn err = mv88e6xxx_broadcast_setup(chip, 0); 261287fa886eSAndrew Lunn if (err) 261387fa886eSAndrew Lunn goto unlock; 261487fa886eSAndrew Lunn 26159e907d73SVivien Didelot err = mv88e6xxx_pot_setup(chip); 26169e907d73SVivien Didelot if (err) 26179e907d73SVivien Didelot goto unlock; 26189e907d73SVivien Didelot 26199e5baf9bSVivien Didelot err = mv88e6xxx_rmu_setup(chip); 26209e5baf9bSVivien Didelot if (err) 26219e5baf9bSVivien Didelot goto unlock; 26229e5baf9bSVivien Didelot 262351c901a7SVivien Didelot err = mv88e6xxx_rsvd2cpu_setup(chip); 26246e55f698SAndrew Lunn if (err) 26256e55f698SAndrew Lunn goto unlock; 26266e55f698SAndrew Lunn 2627b28f872dSVivien Didelot err = mv88e6xxx_trunk_setup(chip); 2628b28f872dSVivien Didelot if (err) 2629b28f872dSVivien Didelot goto unlock; 2630b28f872dSVivien Didelot 2631c7f047b6SVivien Didelot err = mv88e6xxx_devmap_setup(chip); 2632c7f047b6SVivien Didelot if (err) 2633c7f047b6SVivien Didelot goto unlock; 2634c7f047b6SVivien Didelot 263593e18d61SVivien Didelot err = mv88e6xxx_pri_setup(chip); 263693e18d61SVivien Didelot if (err) 263793e18d61SVivien Didelot goto unlock; 263893e18d61SVivien Didelot 2639c6fe0ad2SBrandon Streiff /* Setup PTP Hardware Clock and timestamping */ 26402fa8d3afSBrandon Streiff if (chip->info->ptp_support) { 26412fa8d3afSBrandon Streiff err = mv88e6xxx_ptp_setup(chip); 26422fa8d3afSBrandon Streiff if (err) 26432fa8d3afSBrandon Streiff goto unlock; 2644c6fe0ad2SBrandon Streiff 2645c6fe0ad2SBrandon Streiff err = mv88e6xxx_hwtstamp_setup(chip); 2646c6fe0ad2SBrandon Streiff if (err) 2647c6fe0ad2SBrandon Streiff goto unlock; 26482fa8d3afSBrandon Streiff } 26492fa8d3afSBrandon Streiff 2650447b1bb8SVivien Didelot err = mv88e6xxx_stats_setup(chip); 2651447b1bb8SVivien Didelot if (err) 2652447b1bb8SVivien Didelot goto unlock; 2653447b1bb8SVivien Didelot 2654fad09c73SVivien Didelot unlock: 2655fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 2656fad09c73SVivien Didelot 2657fad09c73SVivien Didelot return err; 2658fad09c73SVivien Didelot } 2659fad09c73SVivien Didelot 2660e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) 2661fad09c73SVivien Didelot { 26620dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 26630dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 2664e57e5e77SVivien Didelot u16 val; 2665e57e5e77SVivien Didelot int err; 2666fad09c73SVivien Didelot 2667ee26a228SAndrew Lunn if (!chip->info->ops->phy_read) 2668ee26a228SAndrew Lunn return -EOPNOTSUPP; 2669ee26a228SAndrew Lunn 2670fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 2671ee26a228SAndrew Lunn err = chip->info->ops->phy_read(chip, bus, phy, reg, &val); 2672fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 2673e57e5e77SVivien Didelot 2674da9f3301SAndrew Lunn if (reg == MII_PHYSID2) { 2675ddc49acbSAndrew Lunn /* Some internal PHYs don't have a model number. */ 2676ddc49acbSAndrew Lunn if (chip->info->family != MV88E6XXX_FAMILY_6165) 2677ddc49acbSAndrew Lunn /* Then there is the 6165 family. It gets is 2678ddc49acbSAndrew Lunn * PHYs correct. But it can also have two 2679ddc49acbSAndrew Lunn * SERDES interfaces in the PHY address 2680ddc49acbSAndrew Lunn * space. And these don't have a model 2681ddc49acbSAndrew Lunn * number. But they are not PHYs, so we don't 2682ddc49acbSAndrew Lunn * want to give them something a PHY driver 2683ddc49acbSAndrew Lunn * will recognise. 2684ddc49acbSAndrew Lunn * 2685ddc49acbSAndrew Lunn * Use the mv88e6390 family model number 2686ddc49acbSAndrew Lunn * instead, for anything which really could be 2687ddc49acbSAndrew Lunn * a PHY, 2688da9f3301SAndrew Lunn */ 2689da9f3301SAndrew Lunn if (!(val & 0x3f0)) 2690107fcc10SVivien Didelot val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4; 2691da9f3301SAndrew Lunn } 2692da9f3301SAndrew Lunn 2693e57e5e77SVivien Didelot return err ? err : val; 2694fad09c73SVivien Didelot } 2695fad09c73SVivien Didelot 2696e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 2697fad09c73SVivien Didelot { 26980dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 26990dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 2700e57e5e77SVivien Didelot int err; 2701fad09c73SVivien Didelot 2702ee26a228SAndrew Lunn if (!chip->info->ops->phy_write) 2703ee26a228SAndrew Lunn return -EOPNOTSUPP; 2704ee26a228SAndrew Lunn 2705fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 2706ee26a228SAndrew Lunn err = chip->info->ops->phy_write(chip, bus, phy, reg, val); 2707fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 2708e57e5e77SVivien Didelot 2709e57e5e77SVivien Didelot return err; 2710fad09c73SVivien Didelot } 2711fad09c73SVivien Didelot 2712fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, 2713a3c53be5SAndrew Lunn struct device_node *np, 2714a3c53be5SAndrew Lunn bool external) 2715fad09c73SVivien Didelot { 2716fad09c73SVivien Didelot static int index; 27170dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 2718fad09c73SVivien Didelot struct mii_bus *bus; 2719fad09c73SVivien Didelot int err; 2720fad09c73SVivien Didelot 27212510babcSAndrew Lunn if (external) { 27222510babcSAndrew Lunn mutex_lock(&chip->reg_lock); 27232510babcSAndrew Lunn err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true); 27242510babcSAndrew Lunn mutex_unlock(&chip->reg_lock); 27252510babcSAndrew Lunn 27262510babcSAndrew Lunn if (err) 27272510babcSAndrew Lunn return err; 27282510babcSAndrew Lunn } 27292510babcSAndrew Lunn 27300dd12d54SAndrew Lunn bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus)); 2731fad09c73SVivien Didelot if (!bus) 2732fad09c73SVivien Didelot return -ENOMEM; 2733fad09c73SVivien Didelot 27340dd12d54SAndrew Lunn mdio_bus = bus->priv; 2735a3c53be5SAndrew Lunn mdio_bus->bus = bus; 27360dd12d54SAndrew Lunn mdio_bus->chip = chip; 2737a3c53be5SAndrew Lunn INIT_LIST_HEAD(&mdio_bus->list); 2738a3c53be5SAndrew Lunn mdio_bus->external = external; 27390dd12d54SAndrew Lunn 2740fad09c73SVivien Didelot if (np) { 2741fad09c73SVivien Didelot bus->name = np->full_name; 2742f7ce9103SRob Herring snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np); 2743fad09c73SVivien Didelot } else { 2744fad09c73SVivien Didelot bus->name = "mv88e6xxx SMI"; 2745fad09c73SVivien Didelot snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++); 2746fad09c73SVivien Didelot } 2747fad09c73SVivien Didelot 2748fad09c73SVivien Didelot bus->read = mv88e6xxx_mdio_read; 2749fad09c73SVivien Didelot bus->write = mv88e6xxx_mdio_write; 2750fad09c73SVivien Didelot bus->parent = chip->dev; 2751fad09c73SVivien Didelot 27526f88284fSAndrew Lunn if (!external) { 27536f88284fSAndrew Lunn err = mv88e6xxx_g2_irq_mdio_setup(chip, bus); 27546f88284fSAndrew Lunn if (err) 27556f88284fSAndrew Lunn return err; 27566f88284fSAndrew Lunn } 27576f88284fSAndrew Lunn 2758a3c53be5SAndrew Lunn err = of_mdiobus_register(bus, np); 2759fad09c73SVivien Didelot if (err) { 2760fad09c73SVivien Didelot dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err); 27616f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 2762fad09c73SVivien Didelot return err; 2763fad09c73SVivien Didelot } 2764fad09c73SVivien Didelot 2765a3c53be5SAndrew Lunn if (external) 2766a3c53be5SAndrew Lunn list_add_tail(&mdio_bus->list, &chip->mdios); 2767a3c53be5SAndrew Lunn else 2768a3c53be5SAndrew Lunn list_add(&mdio_bus->list, &chip->mdios); 2769a3c53be5SAndrew Lunn 2770a3c53be5SAndrew Lunn return 0; 2771a3c53be5SAndrew Lunn } 2772a3c53be5SAndrew Lunn 2773a3c53be5SAndrew Lunn static const struct of_device_id mv88e6xxx_mdio_external_match[] = { 2774a3c53be5SAndrew Lunn { .compatible = "marvell,mv88e6xxx-mdio-external", 2775a3c53be5SAndrew Lunn .data = (void *)true }, 2776a3c53be5SAndrew Lunn { }, 2777a3c53be5SAndrew Lunn }; 2778a3c53be5SAndrew Lunn 27793126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) 27803126aeecSAndrew Lunn 27813126aeecSAndrew Lunn { 27823126aeecSAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 27833126aeecSAndrew Lunn struct mii_bus *bus; 27843126aeecSAndrew Lunn 27853126aeecSAndrew Lunn list_for_each_entry(mdio_bus, &chip->mdios, list) { 27863126aeecSAndrew Lunn bus = mdio_bus->bus; 27873126aeecSAndrew Lunn 27886f88284fSAndrew Lunn if (!mdio_bus->external) 27896f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 27906f88284fSAndrew Lunn 27913126aeecSAndrew Lunn mdiobus_unregister(bus); 27923126aeecSAndrew Lunn } 27933126aeecSAndrew Lunn } 27943126aeecSAndrew Lunn 2795a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, 2796a3c53be5SAndrew Lunn struct device_node *np) 2797a3c53be5SAndrew Lunn { 2798a3c53be5SAndrew Lunn const struct of_device_id *match; 2799a3c53be5SAndrew Lunn struct device_node *child; 2800a3c53be5SAndrew Lunn int err; 2801a3c53be5SAndrew Lunn 2802a3c53be5SAndrew Lunn /* Always register one mdio bus for the internal/default mdio 2803a3c53be5SAndrew Lunn * bus. This maybe represented in the device tree, but is 2804a3c53be5SAndrew Lunn * optional. 2805a3c53be5SAndrew Lunn */ 2806a3c53be5SAndrew Lunn child = of_get_child_by_name(np, "mdio"); 2807a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, false); 2808a3c53be5SAndrew Lunn if (err) 2809a3c53be5SAndrew Lunn return err; 2810a3c53be5SAndrew Lunn 2811a3c53be5SAndrew Lunn /* Walk the device tree, and see if there are any other nodes 2812a3c53be5SAndrew Lunn * which say they are compatible with the external mdio 2813a3c53be5SAndrew Lunn * bus. 2814a3c53be5SAndrew Lunn */ 2815a3c53be5SAndrew Lunn for_each_available_child_of_node(np, child) { 2816a3c53be5SAndrew Lunn match = of_match_node(mv88e6xxx_mdio_external_match, child); 2817a3c53be5SAndrew Lunn if (match) { 2818a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, true); 28193126aeecSAndrew Lunn if (err) { 28203126aeecSAndrew Lunn mv88e6xxx_mdios_unregister(chip); 2821a3c53be5SAndrew Lunn return err; 2822a3c53be5SAndrew Lunn } 2823a3c53be5SAndrew Lunn } 28243126aeecSAndrew Lunn } 2825a3c53be5SAndrew Lunn 2826a3c53be5SAndrew Lunn return 0; 2827a3c53be5SAndrew Lunn } 2828a3c53be5SAndrew Lunn 2829855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) 2830855b1932SVivien Didelot { 283104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2832855b1932SVivien Didelot 2833855b1932SVivien Didelot return chip->eeprom_len; 2834855b1932SVivien Didelot } 2835855b1932SVivien Didelot 2836855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds, 2837855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 2838855b1932SVivien Didelot { 283904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2840855b1932SVivien Didelot int err; 2841855b1932SVivien Didelot 2842ee4dc2e7SVivien Didelot if (!chip->info->ops->get_eeprom) 2843ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 2844ee4dc2e7SVivien Didelot 2845855b1932SVivien Didelot mutex_lock(&chip->reg_lock); 2846ee4dc2e7SVivien Didelot err = chip->info->ops->get_eeprom(chip, eeprom, data); 2847855b1932SVivien Didelot mutex_unlock(&chip->reg_lock); 2848855b1932SVivien Didelot 2849855b1932SVivien Didelot if (err) 2850855b1932SVivien Didelot return err; 2851855b1932SVivien Didelot 2852855b1932SVivien Didelot eeprom->magic = 0xc3ec4951; 2853855b1932SVivien Didelot 2854855b1932SVivien Didelot return 0; 2855855b1932SVivien Didelot } 2856855b1932SVivien Didelot 2857855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, 2858855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 2859855b1932SVivien Didelot { 286004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2861855b1932SVivien Didelot int err; 2862855b1932SVivien Didelot 2863ee4dc2e7SVivien Didelot if (!chip->info->ops->set_eeprom) 2864ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 2865ee4dc2e7SVivien Didelot 2866855b1932SVivien Didelot if (eeprom->magic != 0xc3ec4951) 2867855b1932SVivien Didelot return -EINVAL; 2868855b1932SVivien Didelot 2869855b1932SVivien Didelot mutex_lock(&chip->reg_lock); 2870ee4dc2e7SVivien Didelot err = chip->info->ops->set_eeprom(chip, eeprom, data); 2871855b1932SVivien Didelot mutex_unlock(&chip->reg_lock); 2872855b1932SVivien Didelot 2873855b1932SVivien Didelot return err; 2874855b1932SVivien Didelot } 2875855b1932SVivien Didelot 2876b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = { 28774b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6097 */ 287893e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 287993e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 2880cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 2881b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 28827e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 28837e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 288408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 28857f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 288696a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2887ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 288856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2889601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 289056995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2891ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 28920898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2893c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 28949dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 28956c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 28962d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 2897a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 289840cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 2899dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2900dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2901052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2902fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2903fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2904fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 290551c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 29069e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 2907a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 2908a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 290917e708baSVivien Didelot .reset = mv88e6185_g1_reset, 29109e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 2911f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 29120ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 29136c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 2914b3469dd8SVivien Didelot }; 2915b3469dd8SVivien Didelot 2916b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = { 29174b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6095 */ 291893e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 291993e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 2920b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 29217e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 29227e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 292308ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 29247f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 292596a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 292656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 2927601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 2928a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 29296c422e34SRussell King .port_link_state = mv88e6185_port_link_state, 29302d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 2931a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 293240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 2933dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2934dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2935052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 293651c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 2937a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 2938a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 293917e708baSVivien Didelot .reset = mv88e6185_g1_reset, 2940f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 29410ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 29426c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 2943b3469dd8SVivien Didelot }; 2944b3469dd8SVivien Didelot 29457d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = { 294615da3cc8SStefan Eichenberger /* MV88E6XXX_FAMILY_6097 */ 294793e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 294893e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 2949cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 29507d381a02SStefan Eichenberger .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 29517d381a02SStefan Eichenberger .phy_read = mv88e6xxx_g2_smi_phy_read, 29527d381a02SStefan Eichenberger .phy_write = mv88e6xxx_g2_smi_phy_write, 29537d381a02SStefan Eichenberger .port_set_link = mv88e6xxx_port_set_link, 29547d381a02SStefan Eichenberger .port_set_duplex = mv88e6xxx_port_set_duplex, 29557d381a02SStefan Eichenberger .port_set_speed = mv88e6185_port_set_speed, 2956ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 295756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2958601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 295956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2960cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2961ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 29620898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2963c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 29649dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 29656c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 29662d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 29677d381a02SStefan Eichenberger .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 296840cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 29697d381a02SStefan Eichenberger .stats_get_sset_count = mv88e6095_stats_get_sset_count, 29707d381a02SStefan Eichenberger .stats_get_strings = mv88e6095_stats_get_strings, 29717d381a02SStefan Eichenberger .stats_get_stats = mv88e6095_stats_get_stats, 2972fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2973fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 297491eaa475SVolodymyr Bendiuga .watchdog_ops = &mv88e6097_watchdog_ops, 297551c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 29769e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 297717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 29789e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 2979f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 29800ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 29816c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 29827d381a02SStefan Eichenberger }; 29837d381a02SStefan Eichenberger 2984b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = { 29854b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 298693e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 298793e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 2988cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 2989b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2990ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 2991ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 299208ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 29937f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 299496a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 299556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 2996601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 2997c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 29989dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 29996c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 30002d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 30010ac64c39SAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 300240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3003dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3004dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3005052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3006fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3007fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3008fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 300951c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 30109e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 301117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3012f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 30130ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 30146c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3015b3469dd8SVivien Didelot }; 3016b3469dd8SVivien Didelot 3017b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = { 30184b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 301993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 302093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3021b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 30227e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 30237e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 302408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 30257f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 302696a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3027ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 302856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3029601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 303056995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3031a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 3032cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3033ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 30340898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 303554186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 30366c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 30372d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3038a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 303940cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3040dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3041dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3042052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3043fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3044fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3045fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 304651c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 3047a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 304802317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 3049a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 305017e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3051f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 30520ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 30536c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3054b3469dd8SVivien Didelot }; 3055b3469dd8SVivien Didelot 3056990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = { 3057990e27b0SVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 305893e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 305993e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3060cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3061990e27b0SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 3062990e27b0SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 3063990e27b0SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3064990e27b0SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3065990e27b0SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 3066990e27b0SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3067990e27b0SVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3068990e27b0SVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 306926422340SMarek Behún .port_set_speed = mv88e6341_port_set_speed, 3070990e27b0SVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 3071990e27b0SVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3072990e27b0SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 3073990e27b0SVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 3074cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3075990e27b0SVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 30760898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3077990e27b0SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 3078990e27b0SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 30796c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 30802d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3081990e27b0SVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 308240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3083990e27b0SVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3084990e27b0SVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 3085990e27b0SVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 3086fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3087fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 3088990e27b0SVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 3089990e27b0SVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 30909e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 3091990e27b0SVivien Didelot .reset = mv88e6352_g1_reset, 3092f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 30930ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 30946751e7c6SAndrew Lunn .serdes_power = mv88e6341_serdes_power, 3095a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 3096e3af71a3SMarek Behún .phylink_validate = mv88e6341_phylink_validate, 3097990e27b0SVivien Didelot }; 3098990e27b0SVivien Didelot 3099b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = { 31004b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 310193e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 310293e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3103cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3104b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3105ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 3106ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 310708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 31087f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 310996a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3110ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 311156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3112601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 311356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3114cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3115ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 31160898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3117c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 31189dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 31196c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 31202d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3121a6da21bbSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 312240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3123dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3124dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3125052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3126fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3127fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3128fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 312951c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 31309e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 313117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3132f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 31330ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3134a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 3135dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 31366c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3137b3469dd8SVivien Didelot }; 3138b3469dd8SVivien Didelot 3139b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = { 31404b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 314193e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 314293e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3143cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3144b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3145efb3e74dSAndrew Lunn .phy_read = mv88e6165_phy_read, 3146efb3e74dSAndrew Lunn .phy_write = mv88e6165_phy_write, 314708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 31487f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 314996a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3150c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 31519dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 31526c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 31532d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3154a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 315540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3156dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3157dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3158052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3159fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3160fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3161fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 316251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 31639e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 316417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3165f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 31660ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3167a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 3168dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 31696c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3170b3469dd8SVivien Didelot }; 3171b3469dd8SVivien Didelot 3172b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = { 31734b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 317493e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 317593e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3176cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3177b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3178b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3179b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 318008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 31817f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 318294d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 318396a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3184ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 318556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3186601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 318756995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3188cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3189ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 31900898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3191c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 31929dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 31936c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 31942d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3195a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 319640cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3197dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3198dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3199052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3200fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3201fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3202fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 320351c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 32049e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 320517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3206f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 32070ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 32086c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3209b3469dd8SVivien Didelot }; 3210b3469dd8SVivien Didelot 3211b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = { 32124b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 321393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 321493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3215cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3216ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3217ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3218b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3219b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3220b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 322108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 32227f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3223a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 322496a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 3225ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 322656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3227601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 322856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3229cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3230ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 32310898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3232c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 32339dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 32346c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 32352d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3236a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 323740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3238dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3239dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3240052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3241fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3242fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3243fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 324451c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 32459e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 324617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 32479e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 3248f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 32490ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 32506d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 3251a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 32526c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3253b3469dd8SVivien Didelot }; 3254b3469dd8SVivien Didelot 3255b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = { 32564b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 325793e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 325893e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3259cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3260b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3261b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3262b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 326308ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 32647f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 326594d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 326696a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3267ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 326856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3269601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 327056995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3271cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3272ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 32730898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3274c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 32759dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 32766c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 32772d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3278a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 327940cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3280dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3281dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3282052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3283fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3284fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3285fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 328651c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 32879e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 328817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3289f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 32900ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 32916c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3292b3469dd8SVivien Didelot }; 3293b3469dd8SVivien Didelot 3294b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = { 32954b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 329693e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 329793e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3298cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3299ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3300ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3301b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3302b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3303b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 330408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 33057f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3306a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 330796a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 3308ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 330956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3310601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 331156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3312cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3313ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 33140898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3315c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 33169dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 33176c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 33182d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3319a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 332040cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3321dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3322dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3323052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3324fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3325fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3326fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 332751c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 33289e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 332917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 33309e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 3331f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 33320ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 33336d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 33344382172fSAndrew Lunn .serdes_irq_setup = mv88e6352_serdes_irq_setup, 33354382172fSAndrew Lunn .serdes_irq_free = mv88e6352_serdes_irq_free, 3336a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 33376c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3338b3469dd8SVivien Didelot }; 3339b3469dd8SVivien Didelot 3340b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = { 33414b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 334293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 334393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3344b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 33457e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 33467e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 334708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 33487f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 334996a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 335056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 3351601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 3352ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 3353a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 335454186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 33556c422e34SRussell King .port_link_state = mv88e6185_port_link_state, 33562d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3357a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 335840cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3359dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3360dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3361052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3362fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3363fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3364fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 336551c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 336602317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 3367a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 3368a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 336917e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3370f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 33710ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 33726c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3373b3469dd8SVivien Didelot }; 3374b3469dd8SVivien Didelot 33751a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = { 33764b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3377ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3378cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 337998fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 338098fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 33811a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 33821a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 33831a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 33841a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 33851a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 33861a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 33871a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 3388ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 338956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3390601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 339156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 33920898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3393c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 33949dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 33956c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 33962d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3397fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 339879523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3399de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3400dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3401dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3402e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3403fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3404fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 340561303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 34066e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 34079e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 340817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 34099e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 3410931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3411931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 34126335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 3413efd1ba6aSAndrew Lunn .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3414efd1ba6aSAndrew Lunn .serdes_irq_free = mv88e6390_serdes_irq_free, 3415a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 34166c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 34171a3b39ecSAndrew Lunn }; 34181a3b39ecSAndrew Lunn 34191a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = { 34204b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3421ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3422cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 342398fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 342498fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 34251a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 34261a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 34271a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 34281a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 34291a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 34301a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 34311a3b39ecSAndrew Lunn .port_set_speed = mv88e6390x_port_set_speed, 3432ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 343356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3434601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 343556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 34360898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3437c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 34389dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 34396c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 34402d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3441fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 344279523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3443de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3444dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3445dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3446e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3447fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3448fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 344961303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 34506e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 34519e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 345217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 34539e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 3454931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3455931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 345607ffbd74SAndrew Lunn .serdes_power = mv88e6390x_serdes_power, 34572defda1fSAndrew Lunn .serdes_irq_setup = mv88e6390x_serdes_irq_setup, 34582defda1fSAndrew Lunn .serdes_irq_free = mv88e6390x_serdes_irq_free, 3459a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 34606c422e34SRussell King .phylink_validate = mv88e6390x_phylink_validate, 34611a3b39ecSAndrew Lunn }; 34621a3b39ecSAndrew Lunn 34631a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = { 34644b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3465ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3466cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 346798fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 346898fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 34691a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 34701a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 34711a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 34721a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 34731a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 34741a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 34751a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 3476ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 347756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3478601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 347956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 34800898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3481c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 34829dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 34836c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 34842d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3485fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 348679523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3487de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3488dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3489dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3490e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3491fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3492fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 349361303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 34946e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 34959e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 349617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 34979e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 3498931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3499931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 35006335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 3501efd1ba6aSAndrew Lunn .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3502efd1ba6aSAndrew Lunn .serdes_irq_free = mv88e6390_serdes_irq_free, 35036d2ac8eeSAndrew Lunn .avb_ops = &mv88e6390_avb_ops, 35046d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 35056c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 35061a3b39ecSAndrew Lunn }; 35071a3b39ecSAndrew Lunn 3508b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = { 35094b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 351093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 351193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3512cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3513ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3514ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3515b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3516b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3517b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 351808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 35197f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3520a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 352196a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 3522ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 352356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3524601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 352556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3526cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3527ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 35280898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3529c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 35309dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 35316c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 35322d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3533a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 353440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3535dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3536dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3537052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3538fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3539fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3540fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 354151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 35429e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 354317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 35449e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 3545f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 35460ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 35476d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 35484382172fSAndrew Lunn .serdes_irq_setup = mv88e6352_serdes_irq_setup, 35494382172fSAndrew Lunn .serdes_irq_free = mv88e6352_serdes_irq_free, 3550a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 35510d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 35526d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 35536c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3554b3469dd8SVivien Didelot }; 3555b3469dd8SVivien Didelot 35561a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = { 35574b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3558ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3559cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 356098fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 356198fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 35621a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 35631a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 35641a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 35651a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 35661a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 35671a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 35681a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 3569ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 357056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3571601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 357256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 35730898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3574c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 35759dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 35766c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 35772d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3578fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 357979523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3580de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3581dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3582dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3583e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3584fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3585fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 358661303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 35876e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 35889e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 358917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 35909e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 3591931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3592931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 35936335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 3594efd1ba6aSAndrew Lunn .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3595efd1ba6aSAndrew Lunn .serdes_irq_free = mv88e6390_serdes_irq_free, 3596a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 35970d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 35986d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 35996c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 36001a3b39ecSAndrew Lunn }; 36011a3b39ecSAndrew Lunn 3602b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = { 36034b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6320 */ 360493e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 360593e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3606cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3607ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3608ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3609b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3610b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3611b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 361208ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 36137f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 361496a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3615ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 361656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3617601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 361856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3619cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3620ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 36210898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3622c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 36239dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 36246c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 36252d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3626a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 362740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3628dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3629dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3630052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 3631fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3632fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 36339c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 363451c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 36359e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 363617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3637f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 36380ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 3639a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 36400d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 36416d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 36426c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3643b3469dd8SVivien Didelot }; 3644b3469dd8SVivien Didelot 3645b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = { 3646bd807204SVivien Didelot /* MV88E6XXX_FAMILY_6320 */ 364793e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 364893e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3649cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3650ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3651ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3652b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3653b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3654b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 365508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 36567f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 365796a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3658ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 365956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3660601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 366156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3662cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3663ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 36640898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3665c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 36669dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 36676c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 36682d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3669a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 367040cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3671dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3672dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3673052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 3674fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3675fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 36769c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 367717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3678f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 36790ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 3680a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 36810d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 36826d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 36836c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3684b3469dd8SVivien Didelot }; 3685b3469dd8SVivien Didelot 368616e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = { 368716e329aeSVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 368893e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 368993e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3690cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 369116e329aeSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 369216e329aeSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 369316e329aeSVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 369416e329aeSVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 369516e329aeSVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 369616e329aeSVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 369716e329aeSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 369816e329aeSVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 369926422340SMarek Behún .port_set_speed = mv88e6341_port_set_speed, 370016e329aeSVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 370116e329aeSVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 370216e329aeSVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 370316e329aeSVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 3704cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 370516e329aeSVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 37060898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 370716e329aeSVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 370816e329aeSVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 37096c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 37102d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 371116e329aeSVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 371240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 371316e329aeSVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 371416e329aeSVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 371516e329aeSVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 3716fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3717fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 371816e329aeSVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 371916e329aeSVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 37209e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 372116e329aeSVivien Didelot .reset = mv88e6352_g1_reset, 3722f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 37230ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 37246751e7c6SAndrew Lunn .serdes_power = mv88e6341_serdes_power, 3725a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 37260d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 37276d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 3728e3af71a3SMarek Behún .phylink_validate = mv88e6341_phylink_validate, 372916e329aeSVivien Didelot }; 373016e329aeSVivien Didelot 3731b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = { 37324b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 373393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 373493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3735cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3736b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3737b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3738b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 373908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 37407f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 374194d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 374296a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3743ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 374456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3745601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 374656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3747cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3748ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 37490898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3750c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 37519dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 37526c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 37532d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3754a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 375540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3756dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3757dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3758052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3759fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3760fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3761fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 376251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 37639e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 376417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3765f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 37660ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 37676c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3768b3469dd8SVivien Didelot }; 3769b3469dd8SVivien Didelot 3770b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = { 37714b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 377293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 377393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3774cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3775b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3776b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3777b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 377808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 37797f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 378094d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 378196a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3782ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 378356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3784601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 378556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3786cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3787ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 37880898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3789c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 37909dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 37916c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 37922d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3793a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 379440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3795dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3796dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3797052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3798fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3799fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3800fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 380151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 38029e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 380317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3804f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 38050ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 38060d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 38076d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 38086c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3809b3469dd8SVivien Didelot }; 3810b3469dd8SVivien Didelot 3811b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = { 38124b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 381393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 381493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3815cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3816ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3817ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3818b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3819b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3820b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 382108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 38227f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3823a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 382496a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 3825ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 382656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3827601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 382856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3829cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3830ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 38310898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3832c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 38339dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 38346c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 38352d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3836a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 383740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3838dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3839dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3840052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3841fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3842fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3843fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 384451c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 38459e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 384617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 38479e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 3848f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 38490ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 38506d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 38514382172fSAndrew Lunn .serdes_irq_setup = mv88e6352_serdes_irq_setup, 38524382172fSAndrew Lunn .serdes_irq_free = mv88e6352_serdes_irq_free, 3853a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 38540d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 38556d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 3856cda9f4aaSAndrew Lunn .serdes_get_sset_count = mv88e6352_serdes_get_sset_count, 3857cda9f4aaSAndrew Lunn .serdes_get_strings = mv88e6352_serdes_get_strings, 3858cda9f4aaSAndrew Lunn .serdes_get_stats = mv88e6352_serdes_get_stats, 38596c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3860b3469dd8SVivien Didelot }; 3861b3469dd8SVivien Didelot 38621a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = { 38634b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3864ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3865cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 386698fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 386798fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 38681a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 38691a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 38701a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 38711a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 38721a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 38731a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 38741a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 3875ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 387656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3877601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 387856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3879cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3880ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 38810898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3882c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 38839dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 38846c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 38852d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3886fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 388779523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3888de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3889dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3890dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3891e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3892fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3893fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 389461303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 38956e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 38969e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 389717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 38989e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 3899931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3900931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 39016335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 3902efd1ba6aSAndrew Lunn .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3903efd1ba6aSAndrew Lunn .serdes_irq_free = mv88e6390_serdes_irq_free, 3904a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 39050d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 39066d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 39076c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 39081a3b39ecSAndrew Lunn }; 39091a3b39ecSAndrew Lunn 39101a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = { 39114b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3912ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3913cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 391498fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 391598fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 39161a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 39171a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 39181a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 39191a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 39201a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 39211a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 39221a3b39ecSAndrew Lunn .port_set_speed = mv88e6390x_port_set_speed, 3923ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 392456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3925601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 392656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3927cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3928ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 39290898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3930c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 39319dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 39326c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 39332d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3934b3dce4daSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 393579523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3936de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3937dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3938dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3939e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3940fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3941fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 394261303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 39436e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 39449e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 394517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 39469e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 3947931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3948931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 394907ffbd74SAndrew Lunn .serdes_power = mv88e6390x_serdes_power, 39502defda1fSAndrew Lunn .serdes_irq_setup = mv88e6390x_serdes_irq_setup, 39512defda1fSAndrew Lunn .serdes_irq_free = mv88e6390x_serdes_irq_free, 3952a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 39530d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 39546d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 39556c422e34SRussell King .phylink_validate = mv88e6390x_phylink_validate, 39561a3b39ecSAndrew Lunn }; 39571a3b39ecSAndrew Lunn 3958fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = { 3959fad09c73SVivien Didelot [MV88E6085] = { 3960107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085, 3961fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6097, 3962fad09c73SVivien Didelot .name = "Marvell 88E6085", 3963fad09c73SVivien Didelot .num_databases = 4096, 3964fad09c73SVivien Didelot .num_ports = 10, 3965bc393155SAndrew Lunn .num_internal_phys = 5, 39663cf3c846SVivien Didelot .max_vid = 4095, 3967fad09c73SVivien Didelot .port_base_addr = 0x10, 39689255bacdSAndrew Lunn .phy_base_addr = 0x0, 3969a935c052SVivien Didelot .global1_addr = 0x1b, 39709069c13aSVivien Didelot .global2_addr = 0x1c, 3971acddbd21SVivien Didelot .age_time_coeff = 15000, 3972dc30c35bSAndrew Lunn .g1_irqs = 8, 3973d6c5e6afSVivien Didelot .g2_irqs = 10, 3974e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3975f3645652SVivien Didelot .pvt = true, 3976b3e05aa1SVivien Didelot .multi_chip = true, 3977443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3978b3469dd8SVivien Didelot .ops = &mv88e6085_ops, 3979fad09c73SVivien Didelot }, 3980fad09c73SVivien Didelot 3981fad09c73SVivien Didelot [MV88E6095] = { 3982107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095, 3983fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6095, 3984fad09c73SVivien Didelot .name = "Marvell 88E6095/88E6095F", 3985fad09c73SVivien Didelot .num_databases = 256, 3986fad09c73SVivien Didelot .num_ports = 11, 3987bc393155SAndrew Lunn .num_internal_phys = 0, 39883cf3c846SVivien Didelot .max_vid = 4095, 3989fad09c73SVivien Didelot .port_base_addr = 0x10, 39909255bacdSAndrew Lunn .phy_base_addr = 0x0, 3991a935c052SVivien Didelot .global1_addr = 0x1b, 39929069c13aSVivien Didelot .global2_addr = 0x1c, 3993acddbd21SVivien Didelot .age_time_coeff = 15000, 3994dc30c35bSAndrew Lunn .g1_irqs = 8, 3995e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3996b3e05aa1SVivien Didelot .multi_chip = true, 3997443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3998b3469dd8SVivien Didelot .ops = &mv88e6095_ops, 3999fad09c73SVivien Didelot }, 4000fad09c73SVivien Didelot 40017d381a02SStefan Eichenberger [MV88E6097] = { 4002107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097, 40037d381a02SStefan Eichenberger .family = MV88E6XXX_FAMILY_6097, 40047d381a02SStefan Eichenberger .name = "Marvell 88E6097/88E6097F", 40057d381a02SStefan Eichenberger .num_databases = 4096, 40067d381a02SStefan Eichenberger .num_ports = 11, 4007bc393155SAndrew Lunn .num_internal_phys = 8, 40083cf3c846SVivien Didelot .max_vid = 4095, 40097d381a02SStefan Eichenberger .port_base_addr = 0x10, 40109255bacdSAndrew Lunn .phy_base_addr = 0x0, 40117d381a02SStefan Eichenberger .global1_addr = 0x1b, 40129069c13aSVivien Didelot .global2_addr = 0x1c, 40137d381a02SStefan Eichenberger .age_time_coeff = 15000, 4014c534178bSStefan Eichenberger .g1_irqs = 8, 4015d6c5e6afSVivien Didelot .g2_irqs = 10, 4016e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4017f3645652SVivien Didelot .pvt = true, 4018b3e05aa1SVivien Didelot .multi_chip = true, 40192bfcfcd3SStefan Eichenberger .tag_protocol = DSA_TAG_PROTO_EDSA, 40207d381a02SStefan Eichenberger .ops = &mv88e6097_ops, 40217d381a02SStefan Eichenberger }, 40227d381a02SStefan Eichenberger 4023fad09c73SVivien Didelot [MV88E6123] = { 4024107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123, 4025fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4026fad09c73SVivien Didelot .name = "Marvell 88E6123", 4027fad09c73SVivien Didelot .num_databases = 4096, 4028fad09c73SVivien Didelot .num_ports = 3, 4029bc393155SAndrew Lunn .num_internal_phys = 5, 40303cf3c846SVivien Didelot .max_vid = 4095, 4031fad09c73SVivien Didelot .port_base_addr = 0x10, 40329255bacdSAndrew Lunn .phy_base_addr = 0x0, 4033a935c052SVivien Didelot .global1_addr = 0x1b, 40349069c13aSVivien Didelot .global2_addr = 0x1c, 4035acddbd21SVivien Didelot .age_time_coeff = 15000, 4036dc30c35bSAndrew Lunn .g1_irqs = 9, 4037d6c5e6afSVivien Didelot .g2_irqs = 10, 4038e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4039f3645652SVivien Didelot .pvt = true, 4040b3e05aa1SVivien Didelot .multi_chip = true, 40415ebe31d7SAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4042b3469dd8SVivien Didelot .ops = &mv88e6123_ops, 4043fad09c73SVivien Didelot }, 4044fad09c73SVivien Didelot 4045fad09c73SVivien Didelot [MV88E6131] = { 4046107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131, 4047fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 4048fad09c73SVivien Didelot .name = "Marvell 88E6131", 4049fad09c73SVivien Didelot .num_databases = 256, 4050fad09c73SVivien Didelot .num_ports = 8, 4051bc393155SAndrew Lunn .num_internal_phys = 0, 40523cf3c846SVivien Didelot .max_vid = 4095, 4053fad09c73SVivien Didelot .port_base_addr = 0x10, 40549255bacdSAndrew Lunn .phy_base_addr = 0x0, 4055a935c052SVivien Didelot .global1_addr = 0x1b, 40569069c13aSVivien Didelot .global2_addr = 0x1c, 4057acddbd21SVivien Didelot .age_time_coeff = 15000, 4058dc30c35bSAndrew Lunn .g1_irqs = 9, 4059e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4060b3e05aa1SVivien Didelot .multi_chip = true, 4061443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4062b3469dd8SVivien Didelot .ops = &mv88e6131_ops, 4063fad09c73SVivien Didelot }, 4064fad09c73SVivien Didelot 4065990e27b0SVivien Didelot [MV88E6141] = { 4066107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141, 4067990e27b0SVivien Didelot .family = MV88E6XXX_FAMILY_6341, 406879a68b26SUwe Kleine-König .name = "Marvell 88E6141", 4069990e27b0SVivien Didelot .num_databases = 4096, 4070990e27b0SVivien Didelot .num_ports = 6, 4071bc393155SAndrew Lunn .num_internal_phys = 5, 4072a73ccd61SBrandon Streiff .num_gpio = 11, 40733cf3c846SVivien Didelot .max_vid = 4095, 4074990e27b0SVivien Didelot .port_base_addr = 0x10, 40759255bacdSAndrew Lunn .phy_base_addr = 0x10, 4076990e27b0SVivien Didelot .global1_addr = 0x1b, 40779069c13aSVivien Didelot .global2_addr = 0x1c, 4078990e27b0SVivien Didelot .age_time_coeff = 3750, 4079990e27b0SVivien Didelot .atu_move_port_mask = 0x1f, 4080adfccf11SAndrew Lunn .g1_irqs = 9, 4081d6c5e6afSVivien Didelot .g2_irqs = 10, 4082f3645652SVivien Didelot .pvt = true, 4083b3e05aa1SVivien Didelot .multi_chip = true, 4084990e27b0SVivien Didelot .tag_protocol = DSA_TAG_PROTO_EDSA, 4085990e27b0SVivien Didelot .ops = &mv88e6141_ops, 4086990e27b0SVivien Didelot }, 4087990e27b0SVivien Didelot 4088fad09c73SVivien Didelot [MV88E6161] = { 4089107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161, 4090fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4091fad09c73SVivien Didelot .name = "Marvell 88E6161", 4092fad09c73SVivien Didelot .num_databases = 4096, 4093fad09c73SVivien Didelot .num_ports = 6, 4094bc393155SAndrew Lunn .num_internal_phys = 5, 40953cf3c846SVivien Didelot .max_vid = 4095, 4096fad09c73SVivien Didelot .port_base_addr = 0x10, 40979255bacdSAndrew Lunn .phy_base_addr = 0x0, 4098a935c052SVivien Didelot .global1_addr = 0x1b, 40999069c13aSVivien Didelot .global2_addr = 0x1c, 4100acddbd21SVivien Didelot .age_time_coeff = 15000, 4101dc30c35bSAndrew Lunn .g1_irqs = 9, 4102d6c5e6afSVivien Didelot .g2_irqs = 10, 4103e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4104f3645652SVivien Didelot .pvt = true, 4105b3e05aa1SVivien Didelot .multi_chip = true, 41065ebe31d7SAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4107dfa54348SAndrew Lunn .ptp_support = true, 4108b3469dd8SVivien Didelot .ops = &mv88e6161_ops, 4109fad09c73SVivien Didelot }, 4110fad09c73SVivien Didelot 4111fad09c73SVivien Didelot [MV88E6165] = { 4112107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165, 4113fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4114fad09c73SVivien Didelot .name = "Marvell 88E6165", 4115fad09c73SVivien Didelot .num_databases = 4096, 4116fad09c73SVivien Didelot .num_ports = 6, 4117bc393155SAndrew Lunn .num_internal_phys = 0, 41183cf3c846SVivien Didelot .max_vid = 4095, 4119fad09c73SVivien Didelot .port_base_addr = 0x10, 41209255bacdSAndrew Lunn .phy_base_addr = 0x0, 4121a935c052SVivien Didelot .global1_addr = 0x1b, 41229069c13aSVivien Didelot .global2_addr = 0x1c, 4123acddbd21SVivien Didelot .age_time_coeff = 15000, 4124dc30c35bSAndrew Lunn .g1_irqs = 9, 4125d6c5e6afSVivien Didelot .g2_irqs = 10, 4126e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4127f3645652SVivien Didelot .pvt = true, 4128b3e05aa1SVivien Didelot .multi_chip = true, 4129443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4130dfa54348SAndrew Lunn .ptp_support = true, 4131b3469dd8SVivien Didelot .ops = &mv88e6165_ops, 4132fad09c73SVivien Didelot }, 4133fad09c73SVivien Didelot 4134fad09c73SVivien Didelot [MV88E6171] = { 4135107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171, 4136fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4137fad09c73SVivien Didelot .name = "Marvell 88E6171", 4138fad09c73SVivien Didelot .num_databases = 4096, 4139fad09c73SVivien Didelot .num_ports = 7, 4140bc393155SAndrew Lunn .num_internal_phys = 5, 41413cf3c846SVivien Didelot .max_vid = 4095, 4142fad09c73SVivien Didelot .port_base_addr = 0x10, 41439255bacdSAndrew Lunn .phy_base_addr = 0x0, 4144a935c052SVivien Didelot .global1_addr = 0x1b, 41459069c13aSVivien Didelot .global2_addr = 0x1c, 4146acddbd21SVivien Didelot .age_time_coeff = 15000, 4147dc30c35bSAndrew Lunn .g1_irqs = 9, 4148d6c5e6afSVivien Didelot .g2_irqs = 10, 4149e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4150f3645652SVivien Didelot .pvt = true, 4151b3e05aa1SVivien Didelot .multi_chip = true, 4152443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4153b3469dd8SVivien Didelot .ops = &mv88e6171_ops, 4154fad09c73SVivien Didelot }, 4155fad09c73SVivien Didelot 4156fad09c73SVivien Didelot [MV88E6172] = { 4157107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172, 4158fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4159fad09c73SVivien Didelot .name = "Marvell 88E6172", 4160fad09c73SVivien Didelot .num_databases = 4096, 4161fad09c73SVivien Didelot .num_ports = 7, 4162bc393155SAndrew Lunn .num_internal_phys = 5, 4163a73ccd61SBrandon Streiff .num_gpio = 15, 41643cf3c846SVivien Didelot .max_vid = 4095, 4165fad09c73SVivien Didelot .port_base_addr = 0x10, 41669255bacdSAndrew Lunn .phy_base_addr = 0x0, 4167a935c052SVivien Didelot .global1_addr = 0x1b, 41689069c13aSVivien Didelot .global2_addr = 0x1c, 4169acddbd21SVivien Didelot .age_time_coeff = 15000, 4170dc30c35bSAndrew Lunn .g1_irqs = 9, 4171d6c5e6afSVivien Didelot .g2_irqs = 10, 4172e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4173f3645652SVivien Didelot .pvt = true, 4174b3e05aa1SVivien Didelot .multi_chip = true, 4175443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4176b3469dd8SVivien Didelot .ops = &mv88e6172_ops, 4177fad09c73SVivien Didelot }, 4178fad09c73SVivien Didelot 4179fad09c73SVivien Didelot [MV88E6175] = { 4180107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175, 4181fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4182fad09c73SVivien Didelot .name = "Marvell 88E6175", 4183fad09c73SVivien Didelot .num_databases = 4096, 4184fad09c73SVivien Didelot .num_ports = 7, 4185bc393155SAndrew Lunn .num_internal_phys = 5, 41863cf3c846SVivien Didelot .max_vid = 4095, 4187fad09c73SVivien Didelot .port_base_addr = 0x10, 41889255bacdSAndrew Lunn .phy_base_addr = 0x0, 4189a935c052SVivien Didelot .global1_addr = 0x1b, 41909069c13aSVivien Didelot .global2_addr = 0x1c, 4191acddbd21SVivien Didelot .age_time_coeff = 15000, 4192dc30c35bSAndrew Lunn .g1_irqs = 9, 4193d6c5e6afSVivien Didelot .g2_irqs = 10, 4194e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4195f3645652SVivien Didelot .pvt = true, 4196b3e05aa1SVivien Didelot .multi_chip = true, 4197443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4198b3469dd8SVivien Didelot .ops = &mv88e6175_ops, 4199fad09c73SVivien Didelot }, 4200fad09c73SVivien Didelot 4201fad09c73SVivien Didelot [MV88E6176] = { 4202107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176, 4203fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4204fad09c73SVivien Didelot .name = "Marvell 88E6176", 4205fad09c73SVivien Didelot .num_databases = 4096, 4206fad09c73SVivien Didelot .num_ports = 7, 4207bc393155SAndrew Lunn .num_internal_phys = 5, 4208a73ccd61SBrandon Streiff .num_gpio = 15, 42093cf3c846SVivien Didelot .max_vid = 4095, 4210fad09c73SVivien Didelot .port_base_addr = 0x10, 42119255bacdSAndrew Lunn .phy_base_addr = 0x0, 4212a935c052SVivien Didelot .global1_addr = 0x1b, 42139069c13aSVivien Didelot .global2_addr = 0x1c, 4214acddbd21SVivien Didelot .age_time_coeff = 15000, 4215dc30c35bSAndrew Lunn .g1_irqs = 9, 4216d6c5e6afSVivien Didelot .g2_irqs = 10, 4217e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4218f3645652SVivien Didelot .pvt = true, 4219b3e05aa1SVivien Didelot .multi_chip = true, 4220443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4221b3469dd8SVivien Didelot .ops = &mv88e6176_ops, 4222fad09c73SVivien Didelot }, 4223fad09c73SVivien Didelot 4224fad09c73SVivien Didelot [MV88E6185] = { 4225107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185, 4226fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 4227fad09c73SVivien Didelot .name = "Marvell 88E6185", 4228fad09c73SVivien Didelot .num_databases = 256, 4229fad09c73SVivien Didelot .num_ports = 10, 4230bc393155SAndrew Lunn .num_internal_phys = 0, 42313cf3c846SVivien Didelot .max_vid = 4095, 4232fad09c73SVivien Didelot .port_base_addr = 0x10, 42339255bacdSAndrew Lunn .phy_base_addr = 0x0, 4234a935c052SVivien Didelot .global1_addr = 0x1b, 42359069c13aSVivien Didelot .global2_addr = 0x1c, 4236acddbd21SVivien Didelot .age_time_coeff = 15000, 4237dc30c35bSAndrew Lunn .g1_irqs = 8, 4238e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4239b3e05aa1SVivien Didelot .multi_chip = true, 4240443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4241b3469dd8SVivien Didelot .ops = &mv88e6185_ops, 4242fad09c73SVivien Didelot }, 4243fad09c73SVivien Didelot 42441a3b39ecSAndrew Lunn [MV88E6190] = { 4245107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190, 42461a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 42471a3b39ecSAndrew Lunn .name = "Marvell 88E6190", 42481a3b39ecSAndrew Lunn .num_databases = 4096, 42491a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 4250bc393155SAndrew Lunn .num_internal_phys = 11, 4251a73ccd61SBrandon Streiff .num_gpio = 16, 4252931d1822SVivien Didelot .max_vid = 8191, 42531a3b39ecSAndrew Lunn .port_base_addr = 0x0, 42549255bacdSAndrew Lunn .phy_base_addr = 0x0, 42551a3b39ecSAndrew Lunn .global1_addr = 0x1b, 42569069c13aSVivien Didelot .global2_addr = 0x1c, 4257443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4258b91e055cSAndrew Lunn .age_time_coeff = 3750, 42591a3b39ecSAndrew Lunn .g1_irqs = 9, 4260d6c5e6afSVivien Didelot .g2_irqs = 14, 4261f3645652SVivien Didelot .pvt = true, 4262b3e05aa1SVivien Didelot .multi_chip = true, 4263e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 42641a3b39ecSAndrew Lunn .ops = &mv88e6190_ops, 42651a3b39ecSAndrew Lunn }, 42661a3b39ecSAndrew Lunn 42671a3b39ecSAndrew Lunn [MV88E6190X] = { 4268107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X, 42691a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 42701a3b39ecSAndrew Lunn .name = "Marvell 88E6190X", 42711a3b39ecSAndrew Lunn .num_databases = 4096, 42721a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 4273bc393155SAndrew Lunn .num_internal_phys = 11, 4274a73ccd61SBrandon Streiff .num_gpio = 16, 4275931d1822SVivien Didelot .max_vid = 8191, 42761a3b39ecSAndrew Lunn .port_base_addr = 0x0, 42779255bacdSAndrew Lunn .phy_base_addr = 0x0, 42781a3b39ecSAndrew Lunn .global1_addr = 0x1b, 42799069c13aSVivien Didelot .global2_addr = 0x1c, 4280b91e055cSAndrew Lunn .age_time_coeff = 3750, 42811a3b39ecSAndrew Lunn .g1_irqs = 9, 4282d6c5e6afSVivien Didelot .g2_irqs = 14, 4283e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4284f3645652SVivien Didelot .pvt = true, 4285b3e05aa1SVivien Didelot .multi_chip = true, 4286443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 42871a3b39ecSAndrew Lunn .ops = &mv88e6190x_ops, 42881a3b39ecSAndrew Lunn }, 42891a3b39ecSAndrew Lunn 42901a3b39ecSAndrew Lunn [MV88E6191] = { 4291107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191, 42921a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 42931a3b39ecSAndrew Lunn .name = "Marvell 88E6191", 42941a3b39ecSAndrew Lunn .num_databases = 4096, 42951a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 4296bc393155SAndrew Lunn .num_internal_phys = 11, 4297931d1822SVivien Didelot .max_vid = 8191, 42981a3b39ecSAndrew Lunn .port_base_addr = 0x0, 42999255bacdSAndrew Lunn .phy_base_addr = 0x0, 43001a3b39ecSAndrew Lunn .global1_addr = 0x1b, 43019069c13aSVivien Didelot .global2_addr = 0x1c, 4302b91e055cSAndrew Lunn .age_time_coeff = 3750, 4303443d5a1bSAndrew Lunn .g1_irqs = 9, 4304d6c5e6afSVivien Didelot .g2_irqs = 14, 4305e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4306f3645652SVivien Didelot .pvt = true, 4307b3e05aa1SVivien Didelot .multi_chip = true, 4308443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 43092fa8d3afSBrandon Streiff .ptp_support = true, 43102cf4cefbSVivien Didelot .ops = &mv88e6191_ops, 43111a3b39ecSAndrew Lunn }, 43121a3b39ecSAndrew Lunn 4313fad09c73SVivien Didelot [MV88E6240] = { 4314107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240, 4315fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4316fad09c73SVivien Didelot .name = "Marvell 88E6240", 4317fad09c73SVivien Didelot .num_databases = 4096, 4318fad09c73SVivien Didelot .num_ports = 7, 4319bc393155SAndrew Lunn .num_internal_phys = 5, 4320a73ccd61SBrandon Streiff .num_gpio = 15, 43213cf3c846SVivien Didelot .max_vid = 4095, 4322fad09c73SVivien Didelot .port_base_addr = 0x10, 43239255bacdSAndrew Lunn .phy_base_addr = 0x0, 4324a935c052SVivien Didelot .global1_addr = 0x1b, 43259069c13aSVivien Didelot .global2_addr = 0x1c, 4326acddbd21SVivien Didelot .age_time_coeff = 15000, 4327dc30c35bSAndrew Lunn .g1_irqs = 9, 4328d6c5e6afSVivien Didelot .g2_irqs = 10, 4329e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4330f3645652SVivien Didelot .pvt = true, 4331b3e05aa1SVivien Didelot .multi_chip = true, 4332443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 43332fa8d3afSBrandon Streiff .ptp_support = true, 4334b3469dd8SVivien Didelot .ops = &mv88e6240_ops, 4335fad09c73SVivien Didelot }, 4336fad09c73SVivien Didelot 43371a3b39ecSAndrew Lunn [MV88E6290] = { 4338107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290, 43391a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 43401a3b39ecSAndrew Lunn .name = "Marvell 88E6290", 43411a3b39ecSAndrew Lunn .num_databases = 4096, 43421a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 4343bc393155SAndrew Lunn .num_internal_phys = 11, 4344a73ccd61SBrandon Streiff .num_gpio = 16, 4345931d1822SVivien Didelot .max_vid = 8191, 43461a3b39ecSAndrew Lunn .port_base_addr = 0x0, 43479255bacdSAndrew Lunn .phy_base_addr = 0x0, 43481a3b39ecSAndrew Lunn .global1_addr = 0x1b, 43499069c13aSVivien Didelot .global2_addr = 0x1c, 4350b91e055cSAndrew Lunn .age_time_coeff = 3750, 43511a3b39ecSAndrew Lunn .g1_irqs = 9, 4352d6c5e6afSVivien Didelot .g2_irqs = 14, 4353e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4354f3645652SVivien Didelot .pvt = true, 4355b3e05aa1SVivien Didelot .multi_chip = true, 4356443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 43572fa8d3afSBrandon Streiff .ptp_support = true, 43581a3b39ecSAndrew Lunn .ops = &mv88e6290_ops, 43591a3b39ecSAndrew Lunn }, 43601a3b39ecSAndrew Lunn 4361fad09c73SVivien Didelot [MV88E6320] = { 4362107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320, 4363fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 4364fad09c73SVivien Didelot .name = "Marvell 88E6320", 4365fad09c73SVivien Didelot .num_databases = 4096, 4366fad09c73SVivien Didelot .num_ports = 7, 4367bc393155SAndrew Lunn .num_internal_phys = 5, 4368a73ccd61SBrandon Streiff .num_gpio = 15, 43693cf3c846SVivien Didelot .max_vid = 4095, 4370fad09c73SVivien Didelot .port_base_addr = 0x10, 43719255bacdSAndrew Lunn .phy_base_addr = 0x0, 4372a935c052SVivien Didelot .global1_addr = 0x1b, 43739069c13aSVivien Didelot .global2_addr = 0x1c, 4374acddbd21SVivien Didelot .age_time_coeff = 15000, 4375dc30c35bSAndrew Lunn .g1_irqs = 8, 4376bc393155SAndrew Lunn .g2_irqs = 10, 4377e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4378f3645652SVivien Didelot .pvt = true, 4379b3e05aa1SVivien Didelot .multi_chip = true, 4380443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 43812fa8d3afSBrandon Streiff .ptp_support = true, 4382b3469dd8SVivien Didelot .ops = &mv88e6320_ops, 4383fad09c73SVivien Didelot }, 4384fad09c73SVivien Didelot 4385fad09c73SVivien Didelot [MV88E6321] = { 4386107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321, 4387fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 4388fad09c73SVivien Didelot .name = "Marvell 88E6321", 4389fad09c73SVivien Didelot .num_databases = 4096, 4390fad09c73SVivien Didelot .num_ports = 7, 4391bc393155SAndrew Lunn .num_internal_phys = 5, 4392a73ccd61SBrandon Streiff .num_gpio = 15, 43933cf3c846SVivien Didelot .max_vid = 4095, 4394fad09c73SVivien Didelot .port_base_addr = 0x10, 43959255bacdSAndrew Lunn .phy_base_addr = 0x0, 4396a935c052SVivien Didelot .global1_addr = 0x1b, 43979069c13aSVivien Didelot .global2_addr = 0x1c, 4398acddbd21SVivien Didelot .age_time_coeff = 15000, 4399dc30c35bSAndrew Lunn .g1_irqs = 8, 4400bc393155SAndrew Lunn .g2_irqs = 10, 4401e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4402b3e05aa1SVivien Didelot .multi_chip = true, 4403443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 44042fa8d3afSBrandon Streiff .ptp_support = true, 4405b3469dd8SVivien Didelot .ops = &mv88e6321_ops, 4406fad09c73SVivien Didelot }, 4407fad09c73SVivien Didelot 4408a75961d0SGregory CLEMENT [MV88E6341] = { 4409107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, 4410a75961d0SGregory CLEMENT .family = MV88E6XXX_FAMILY_6341, 4411a75961d0SGregory CLEMENT .name = "Marvell 88E6341", 4412a75961d0SGregory CLEMENT .num_databases = 4096, 4413bc393155SAndrew Lunn .num_internal_phys = 5, 4414a75961d0SGregory CLEMENT .num_ports = 6, 4415a73ccd61SBrandon Streiff .num_gpio = 11, 44163cf3c846SVivien Didelot .max_vid = 4095, 4417a75961d0SGregory CLEMENT .port_base_addr = 0x10, 44189255bacdSAndrew Lunn .phy_base_addr = 0x10, 4419a75961d0SGregory CLEMENT .global1_addr = 0x1b, 44209069c13aSVivien Didelot .global2_addr = 0x1c, 4421a75961d0SGregory CLEMENT .age_time_coeff = 3750, 4422e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4423adfccf11SAndrew Lunn .g1_irqs = 9, 4424d6c5e6afSVivien Didelot .g2_irqs = 10, 4425f3645652SVivien Didelot .pvt = true, 4426b3e05aa1SVivien Didelot .multi_chip = true, 4427a75961d0SGregory CLEMENT .tag_protocol = DSA_TAG_PROTO_EDSA, 44282fa8d3afSBrandon Streiff .ptp_support = true, 4429a75961d0SGregory CLEMENT .ops = &mv88e6341_ops, 4430a75961d0SGregory CLEMENT }, 4431a75961d0SGregory CLEMENT 4432fad09c73SVivien Didelot [MV88E6350] = { 4433107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350, 4434fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4435fad09c73SVivien Didelot .name = "Marvell 88E6350", 4436fad09c73SVivien Didelot .num_databases = 4096, 4437fad09c73SVivien Didelot .num_ports = 7, 4438bc393155SAndrew Lunn .num_internal_phys = 5, 44393cf3c846SVivien Didelot .max_vid = 4095, 4440fad09c73SVivien Didelot .port_base_addr = 0x10, 44419255bacdSAndrew Lunn .phy_base_addr = 0x0, 4442a935c052SVivien Didelot .global1_addr = 0x1b, 44439069c13aSVivien Didelot .global2_addr = 0x1c, 4444acddbd21SVivien Didelot .age_time_coeff = 15000, 4445dc30c35bSAndrew Lunn .g1_irqs = 9, 4446d6c5e6afSVivien Didelot .g2_irqs = 10, 4447e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4448f3645652SVivien Didelot .pvt = true, 4449b3e05aa1SVivien Didelot .multi_chip = true, 4450443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4451b3469dd8SVivien Didelot .ops = &mv88e6350_ops, 4452fad09c73SVivien Didelot }, 4453fad09c73SVivien Didelot 4454fad09c73SVivien Didelot [MV88E6351] = { 4455107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351, 4456fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4457fad09c73SVivien Didelot .name = "Marvell 88E6351", 4458fad09c73SVivien Didelot .num_databases = 4096, 4459fad09c73SVivien Didelot .num_ports = 7, 4460bc393155SAndrew Lunn .num_internal_phys = 5, 44613cf3c846SVivien Didelot .max_vid = 4095, 4462fad09c73SVivien Didelot .port_base_addr = 0x10, 44639255bacdSAndrew Lunn .phy_base_addr = 0x0, 4464a935c052SVivien Didelot .global1_addr = 0x1b, 44659069c13aSVivien Didelot .global2_addr = 0x1c, 4466acddbd21SVivien Didelot .age_time_coeff = 15000, 4467dc30c35bSAndrew Lunn .g1_irqs = 9, 4468d6c5e6afSVivien Didelot .g2_irqs = 10, 4469e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4470f3645652SVivien Didelot .pvt = true, 4471b3e05aa1SVivien Didelot .multi_chip = true, 4472443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4473b3469dd8SVivien Didelot .ops = &mv88e6351_ops, 4474fad09c73SVivien Didelot }, 4475fad09c73SVivien Didelot 4476fad09c73SVivien Didelot [MV88E6352] = { 4477107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352, 4478fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4479fad09c73SVivien Didelot .name = "Marvell 88E6352", 4480fad09c73SVivien Didelot .num_databases = 4096, 4481fad09c73SVivien Didelot .num_ports = 7, 4482bc393155SAndrew Lunn .num_internal_phys = 5, 4483a73ccd61SBrandon Streiff .num_gpio = 15, 44843cf3c846SVivien Didelot .max_vid = 4095, 4485fad09c73SVivien Didelot .port_base_addr = 0x10, 44869255bacdSAndrew Lunn .phy_base_addr = 0x0, 4487a935c052SVivien Didelot .global1_addr = 0x1b, 44889069c13aSVivien Didelot .global2_addr = 0x1c, 4489acddbd21SVivien Didelot .age_time_coeff = 15000, 4490dc30c35bSAndrew Lunn .g1_irqs = 9, 4491d6c5e6afSVivien Didelot .g2_irqs = 10, 4492e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4493f3645652SVivien Didelot .pvt = true, 4494b3e05aa1SVivien Didelot .multi_chip = true, 4495443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 44962fa8d3afSBrandon Streiff .ptp_support = true, 4497b3469dd8SVivien Didelot .ops = &mv88e6352_ops, 4498fad09c73SVivien Didelot }, 44991a3b39ecSAndrew Lunn [MV88E6390] = { 4500107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, 45011a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 45021a3b39ecSAndrew Lunn .name = "Marvell 88E6390", 45031a3b39ecSAndrew Lunn .num_databases = 4096, 45041a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 4505bc393155SAndrew Lunn .num_internal_phys = 11, 4506a73ccd61SBrandon Streiff .num_gpio = 16, 4507931d1822SVivien Didelot .max_vid = 8191, 45081a3b39ecSAndrew Lunn .port_base_addr = 0x0, 45099255bacdSAndrew Lunn .phy_base_addr = 0x0, 45101a3b39ecSAndrew Lunn .global1_addr = 0x1b, 45119069c13aSVivien Didelot .global2_addr = 0x1c, 4512b91e055cSAndrew Lunn .age_time_coeff = 3750, 45131a3b39ecSAndrew Lunn .g1_irqs = 9, 4514d6c5e6afSVivien Didelot .g2_irqs = 14, 4515e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4516f3645652SVivien Didelot .pvt = true, 4517b3e05aa1SVivien Didelot .multi_chip = true, 4518443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 45192fa8d3afSBrandon Streiff .ptp_support = true, 45201a3b39ecSAndrew Lunn .ops = &mv88e6390_ops, 45211a3b39ecSAndrew Lunn }, 45221a3b39ecSAndrew Lunn [MV88E6390X] = { 4523107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X, 45241a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 45251a3b39ecSAndrew Lunn .name = "Marvell 88E6390X", 45261a3b39ecSAndrew Lunn .num_databases = 4096, 45271a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 4528bc393155SAndrew Lunn .num_internal_phys = 11, 4529a73ccd61SBrandon Streiff .num_gpio = 16, 4530931d1822SVivien Didelot .max_vid = 8191, 45311a3b39ecSAndrew Lunn .port_base_addr = 0x0, 45329255bacdSAndrew Lunn .phy_base_addr = 0x0, 45331a3b39ecSAndrew Lunn .global1_addr = 0x1b, 45349069c13aSVivien Didelot .global2_addr = 0x1c, 4535b91e055cSAndrew Lunn .age_time_coeff = 3750, 45361a3b39ecSAndrew Lunn .g1_irqs = 9, 4537d6c5e6afSVivien Didelot .g2_irqs = 14, 4538e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4539f3645652SVivien Didelot .pvt = true, 4540b3e05aa1SVivien Didelot .multi_chip = true, 4541443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 45422fa8d3afSBrandon Streiff .ptp_support = true, 45431a3b39ecSAndrew Lunn .ops = &mv88e6390x_ops, 45441a3b39ecSAndrew Lunn }, 4545fad09c73SVivien Didelot }; 4546fad09c73SVivien Didelot 4547fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) 4548fad09c73SVivien Didelot { 4549fad09c73SVivien Didelot int i; 4550fad09c73SVivien Didelot 4551fad09c73SVivien Didelot for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i) 4552fad09c73SVivien Didelot if (mv88e6xxx_table[i].prod_num == prod_num) 4553fad09c73SVivien Didelot return &mv88e6xxx_table[i]; 4554fad09c73SVivien Didelot 4555fad09c73SVivien Didelot return NULL; 4556fad09c73SVivien Didelot } 4557fad09c73SVivien Didelot 4558fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip) 4559fad09c73SVivien Didelot { 4560fad09c73SVivien Didelot const struct mv88e6xxx_info *info; 45618f6345b2SVivien Didelot unsigned int prod_num, rev; 45628f6345b2SVivien Didelot u16 id; 45638f6345b2SVivien Didelot int err; 4564fad09c73SVivien Didelot 45658f6345b2SVivien Didelot mutex_lock(&chip->reg_lock); 4566107fcc10SVivien Didelot err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id); 45678f6345b2SVivien Didelot mutex_unlock(&chip->reg_lock); 45688f6345b2SVivien Didelot if (err) 45698f6345b2SVivien Didelot return err; 4570fad09c73SVivien Didelot 4571107fcc10SVivien Didelot prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK; 4572107fcc10SVivien Didelot rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK; 4573fad09c73SVivien Didelot 4574fad09c73SVivien Didelot info = mv88e6xxx_lookup_info(prod_num); 4575fad09c73SVivien Didelot if (!info) 4576fad09c73SVivien Didelot return -ENODEV; 4577fad09c73SVivien Didelot 4578fad09c73SVivien Didelot /* Update the compatible info with the probed one */ 4579fad09c73SVivien Didelot chip->info = info; 4580fad09c73SVivien Didelot 4581ca070c10SVivien Didelot err = mv88e6xxx_g2_require(chip); 4582ca070c10SVivien Didelot if (err) 4583ca070c10SVivien Didelot return err; 4584ca070c10SVivien Didelot 4585fad09c73SVivien Didelot dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n", 4586fad09c73SVivien Didelot chip->info->prod_num, chip->info->name, rev); 4587fad09c73SVivien Didelot 4588fad09c73SVivien Didelot return 0; 4589fad09c73SVivien Didelot } 4590fad09c73SVivien Didelot 4591fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) 4592fad09c73SVivien Didelot { 4593fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 4594fad09c73SVivien Didelot 4595fad09c73SVivien Didelot chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 4596fad09c73SVivien Didelot if (!chip) 4597fad09c73SVivien Didelot return NULL; 4598fad09c73SVivien Didelot 4599fad09c73SVivien Didelot chip->dev = dev; 4600fad09c73SVivien Didelot 4601fad09c73SVivien Didelot mutex_init(&chip->reg_lock); 4602a3c53be5SAndrew Lunn INIT_LIST_HEAD(&chip->mdios); 4603fad09c73SVivien Didelot 4604fad09c73SVivien Didelot return chip; 4605fad09c73SVivien Didelot } 4606fad09c73SVivien Didelot 4607fad09c73SVivien Didelot static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip, 4608fad09c73SVivien Didelot struct mii_bus *bus, int sw_addr) 4609fad09c73SVivien Didelot { 4610fad09c73SVivien Didelot if (sw_addr == 0) 4611fad09c73SVivien Didelot chip->smi_ops = &mv88e6xxx_smi_single_chip_ops; 4612b3e05aa1SVivien Didelot else if (chip->info->multi_chip) 4613fad09c73SVivien Didelot chip->smi_ops = &mv88e6xxx_smi_multi_chip_ops; 4614fad09c73SVivien Didelot else 4615fad09c73SVivien Didelot return -EINVAL; 4616fad09c73SVivien Didelot 4617fad09c73SVivien Didelot chip->bus = bus; 4618fad09c73SVivien Didelot chip->sw_addr = sw_addr; 4619fad09c73SVivien Didelot 4620fad09c73SVivien Didelot return 0; 4621fad09c73SVivien Didelot } 4622fad09c73SVivien Didelot 4623ed8fe202SHeiner Kallweit static void mv88e6xxx_ports_cmode_init(struct mv88e6xxx_chip *chip) 4624ed8fe202SHeiner Kallweit { 4625ed8fe202SHeiner Kallweit int i; 4626ed8fe202SHeiner Kallweit 4627ed8fe202SHeiner Kallweit for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 4628ed8fe202SHeiner Kallweit chip->ports[i].cmode = MV88E6XXX_PORT_STS_CMODE_INVALID; 4629ed8fe202SHeiner Kallweit } 4630ed8fe202SHeiner Kallweit 46315ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds, 46325ed4e3ebSFlorian Fainelli int port) 46337b314362SAndrew Lunn { 463404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 46352bbb33beSAndrew Lunn 4636443d5a1bSAndrew Lunn return chip->info->tag_protocol; 46377b314362SAndrew Lunn } 46387b314362SAndrew Lunn 46392a93c1a3SFlorian Fainelli #if IS_ENABLED(CONFIG_NET_DSA_LEGACY) 4640fad09c73SVivien Didelot static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, 4641fad09c73SVivien Didelot struct device *host_dev, int sw_addr, 4642fad09c73SVivien Didelot void **priv) 4643fad09c73SVivien Didelot { 4644fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 4645fad09c73SVivien Didelot struct mii_bus *bus; 4646fad09c73SVivien Didelot int err; 4647fad09c73SVivien Didelot 4648fad09c73SVivien Didelot bus = dsa_host_dev_to_mii_bus(host_dev); 4649fad09c73SVivien Didelot if (!bus) 4650fad09c73SVivien Didelot return NULL; 4651fad09c73SVivien Didelot 4652fad09c73SVivien Didelot chip = mv88e6xxx_alloc_chip(dsa_dev); 4653fad09c73SVivien Didelot if (!chip) 4654fad09c73SVivien Didelot return NULL; 4655fad09c73SVivien Didelot 4656fad09c73SVivien Didelot /* Legacy SMI probing will only support chips similar to 88E6085 */ 4657fad09c73SVivien Didelot chip->info = &mv88e6xxx_table[MV88E6085]; 4658fad09c73SVivien Didelot 4659fad09c73SVivien Didelot err = mv88e6xxx_smi_init(chip, bus, sw_addr); 4660fad09c73SVivien Didelot if (err) 4661fad09c73SVivien Didelot goto free; 4662fad09c73SVivien Didelot 4663fad09c73SVivien Didelot err = mv88e6xxx_detect(chip); 4664fad09c73SVivien Didelot if (err) 4665fad09c73SVivien Didelot goto free; 4666fad09c73SVivien Didelot 4667ed8fe202SHeiner Kallweit mv88e6xxx_ports_cmode_init(chip); 4668ed8fe202SHeiner Kallweit 4669dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 4670dc30c35bSAndrew Lunn err = mv88e6xxx_switch_reset(chip); 4671dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 4672dc30c35bSAndrew Lunn if (err) 4673dc30c35bSAndrew Lunn goto free; 4674dc30c35bSAndrew Lunn 4675e57e5e77SVivien Didelot mv88e6xxx_phy_init(chip); 4676e57e5e77SVivien Didelot 4677a3c53be5SAndrew Lunn err = mv88e6xxx_mdios_register(chip, NULL); 4678fad09c73SVivien Didelot if (err) 4679fad09c73SVivien Didelot goto free; 4680fad09c73SVivien Didelot 4681fad09c73SVivien Didelot *priv = chip; 4682fad09c73SVivien Didelot 4683fad09c73SVivien Didelot return chip->info->name; 4684fad09c73SVivien Didelot free: 4685fad09c73SVivien Didelot devm_kfree(dsa_dev, chip); 4686fad09c73SVivien Didelot 4687fad09c73SVivien Didelot return NULL; 4688fad09c73SVivien Didelot } 46892a93c1a3SFlorian Fainelli #endif 4690fad09c73SVivien Didelot 46917df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port, 46923709aadcSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 46937df8fbddSVivien Didelot { 46947df8fbddSVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 46957df8fbddSVivien Didelot * so skip the prepare phase. 46967df8fbddSVivien Didelot */ 46977df8fbddSVivien Didelot 46987df8fbddSVivien Didelot return 0; 46997df8fbddSVivien Didelot } 47007df8fbddSVivien Didelot 47017df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port, 47023709aadcSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 47037df8fbddSVivien Didelot { 470404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 47057df8fbddSVivien Didelot 47067df8fbddSVivien Didelot mutex_lock(&chip->reg_lock); 47077df8fbddSVivien Didelot if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 470827c0e600SVivien Didelot MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC)) 4709774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to load multicast MAC address\n", 4710774439e5SVivien Didelot port); 47117df8fbddSVivien Didelot mutex_unlock(&chip->reg_lock); 47127df8fbddSVivien Didelot } 47137df8fbddSVivien Didelot 47147df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, 47157df8fbddSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 47167df8fbddSVivien Didelot { 471704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 47187df8fbddSVivien Didelot int err; 47197df8fbddSVivien Didelot 47207df8fbddSVivien Didelot mutex_lock(&chip->reg_lock); 47217df8fbddSVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 472227c0e600SVivien Didelot MV88E6XXX_G1_ATU_DATA_STATE_UNUSED); 47237df8fbddSVivien Didelot mutex_unlock(&chip->reg_lock); 47247df8fbddSVivien Didelot 47257df8fbddSVivien Didelot return err; 47267df8fbddSVivien Didelot } 47277df8fbddSVivien Didelot 47284f85901fSRussell King static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port, 47294f85901fSRussell King bool unicast, bool multicast) 47304f85901fSRussell King { 47314f85901fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 47324f85901fSRussell King int err = -EOPNOTSUPP; 47334f85901fSRussell King 47344f85901fSRussell King mutex_lock(&chip->reg_lock); 47354f85901fSRussell King if (chip->info->ops->port_set_egress_floods) 47364f85901fSRussell King err = chip->info->ops->port_set_egress_floods(chip, port, 47374f85901fSRussell King unicast, 47384f85901fSRussell King multicast); 47394f85901fSRussell King mutex_unlock(&chip->reg_lock); 47404f85901fSRussell King 47414f85901fSRussell King return err; 47424f85901fSRussell King } 47434f85901fSRussell King 4744a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = { 47452a93c1a3SFlorian Fainelli #if IS_ENABLED(CONFIG_NET_DSA_LEGACY) 4746fad09c73SVivien Didelot .probe = mv88e6xxx_drv_probe, 47472a93c1a3SFlorian Fainelli #endif 47487b314362SAndrew Lunn .get_tag_protocol = mv88e6xxx_get_tag_protocol, 4749fad09c73SVivien Didelot .setup = mv88e6xxx_setup, 4750fad09c73SVivien Didelot .adjust_link = mv88e6xxx_adjust_link, 4751c9a2356fSRussell King .phylink_validate = mv88e6xxx_validate, 4752c9a2356fSRussell King .phylink_mac_link_state = mv88e6xxx_link_state, 4753c9a2356fSRussell King .phylink_mac_config = mv88e6xxx_mac_config, 4754c9a2356fSRussell King .phylink_mac_link_down = mv88e6xxx_mac_link_down, 4755c9a2356fSRussell King .phylink_mac_link_up = mv88e6xxx_mac_link_up, 4756fad09c73SVivien Didelot .get_strings = mv88e6xxx_get_strings, 4757fad09c73SVivien Didelot .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, 4758fad09c73SVivien Didelot .get_sset_count = mv88e6xxx_get_sset_count, 475904aca993SAndrew Lunn .port_enable = mv88e6xxx_port_enable, 476004aca993SAndrew Lunn .port_disable = mv88e6xxx_port_disable, 476108f50061SVivien Didelot .get_mac_eee = mv88e6xxx_get_mac_eee, 476208f50061SVivien Didelot .set_mac_eee = mv88e6xxx_set_mac_eee, 4763fad09c73SVivien Didelot .get_eeprom_len = mv88e6xxx_get_eeprom_len, 4764fad09c73SVivien Didelot .get_eeprom = mv88e6xxx_get_eeprom, 4765fad09c73SVivien Didelot .set_eeprom = mv88e6xxx_set_eeprom, 4766fad09c73SVivien Didelot .get_regs_len = mv88e6xxx_get_regs_len, 4767fad09c73SVivien Didelot .get_regs = mv88e6xxx_get_regs, 47682cfcd964SVivien Didelot .set_ageing_time = mv88e6xxx_set_ageing_time, 4769fad09c73SVivien Didelot .port_bridge_join = mv88e6xxx_port_bridge_join, 4770fad09c73SVivien Didelot .port_bridge_leave = mv88e6xxx_port_bridge_leave, 47714f85901fSRussell King .port_egress_floods = mv88e6xxx_port_egress_floods, 4772fad09c73SVivien Didelot .port_stp_state_set = mv88e6xxx_port_stp_state_set, 4773749efcb8SVivien Didelot .port_fast_age = mv88e6xxx_port_fast_age, 4774fad09c73SVivien Didelot .port_vlan_filtering = mv88e6xxx_port_vlan_filtering, 4775fad09c73SVivien Didelot .port_vlan_prepare = mv88e6xxx_port_vlan_prepare, 4776fad09c73SVivien Didelot .port_vlan_add = mv88e6xxx_port_vlan_add, 4777fad09c73SVivien Didelot .port_vlan_del = mv88e6xxx_port_vlan_del, 4778fad09c73SVivien Didelot .port_fdb_add = mv88e6xxx_port_fdb_add, 4779fad09c73SVivien Didelot .port_fdb_del = mv88e6xxx_port_fdb_del, 4780fad09c73SVivien Didelot .port_fdb_dump = mv88e6xxx_port_fdb_dump, 47817df8fbddSVivien Didelot .port_mdb_prepare = mv88e6xxx_port_mdb_prepare, 47827df8fbddSVivien Didelot .port_mdb_add = mv88e6xxx_port_mdb_add, 47837df8fbddSVivien Didelot .port_mdb_del = mv88e6xxx_port_mdb_del, 4784aec5ac88SVivien Didelot .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join, 4785aec5ac88SVivien Didelot .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave, 4786c6fe0ad2SBrandon Streiff .port_hwtstamp_set = mv88e6xxx_port_hwtstamp_set, 4787c6fe0ad2SBrandon Streiff .port_hwtstamp_get = mv88e6xxx_port_hwtstamp_get, 4788c6fe0ad2SBrandon Streiff .port_txtstamp = mv88e6xxx_port_txtstamp, 4789c6fe0ad2SBrandon Streiff .port_rxtstamp = mv88e6xxx_port_rxtstamp, 4790c6fe0ad2SBrandon Streiff .get_ts_info = mv88e6xxx_get_ts_info, 4791fad09c73SVivien Didelot }; 4792fad09c73SVivien Didelot 4793ab3d408dSFlorian Fainelli static struct dsa_switch_driver mv88e6xxx_switch_drv = { 4794ab3d408dSFlorian Fainelli .ops = &mv88e6xxx_switch_ops, 4795ab3d408dSFlorian Fainelli }; 4796ab3d408dSFlorian Fainelli 479755ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) 4798fad09c73SVivien Didelot { 4799fad09c73SVivien Didelot struct device *dev = chip->dev; 4800fad09c73SVivien Didelot struct dsa_switch *ds; 4801fad09c73SVivien Didelot 480273b1204dSVivien Didelot ds = dsa_switch_alloc(dev, mv88e6xxx_num_ports(chip)); 4803fad09c73SVivien Didelot if (!ds) 4804fad09c73SVivien Didelot return -ENOMEM; 4805fad09c73SVivien Didelot 4806fad09c73SVivien Didelot ds->priv = chip; 4807877b7cb0SAndrew Lunn ds->dev = dev; 48089d490b4eSVivien Didelot ds->ops = &mv88e6xxx_switch_ops; 48099ff74f24SVivien Didelot ds->ageing_time_min = chip->info->age_time_coeff; 48109ff74f24SVivien Didelot ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; 4811fad09c73SVivien Didelot 4812fad09c73SVivien Didelot dev_set_drvdata(dev, ds); 4813fad09c73SVivien Didelot 481423c9ee49SVivien Didelot return dsa_register_switch(ds); 4815fad09c73SVivien Didelot } 4816fad09c73SVivien Didelot 4817fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip) 4818fad09c73SVivien Didelot { 4819fad09c73SVivien Didelot dsa_unregister_switch(chip->ds); 4820fad09c73SVivien Didelot } 4821fad09c73SVivien Didelot 4822877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev) 4823877b7cb0SAndrew Lunn { 4824877b7cb0SAndrew Lunn const struct of_device_id *matches = dev->driver->of_match_table; 4825877b7cb0SAndrew Lunn const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data; 4826877b7cb0SAndrew Lunn 4827877b7cb0SAndrew Lunn for (; matches->name[0] || matches->type[0] || matches->compatible[0]; 4828877b7cb0SAndrew Lunn matches++) { 4829877b7cb0SAndrew Lunn if (!strcmp(pdata->compatible, matches->compatible)) 4830877b7cb0SAndrew Lunn return matches->data; 4831877b7cb0SAndrew Lunn } 4832877b7cb0SAndrew Lunn return NULL; 4833877b7cb0SAndrew Lunn } 4834877b7cb0SAndrew Lunn 4835bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration 4836bcd3d9d9SMiquel Raynal * would be lost after a power cycle so prevent it to be suspended. 4837bcd3d9d9SMiquel Raynal */ 4838bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev) 4839bcd3d9d9SMiquel Raynal { 4840bcd3d9d9SMiquel Raynal return -EOPNOTSUPP; 4841bcd3d9d9SMiquel Raynal } 4842bcd3d9d9SMiquel Raynal 4843bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev) 4844bcd3d9d9SMiquel Raynal { 4845bcd3d9d9SMiquel Raynal return 0; 4846bcd3d9d9SMiquel Raynal } 4847bcd3d9d9SMiquel Raynal 4848bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume); 4849bcd3d9d9SMiquel Raynal 4850fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev) 4851fad09c73SVivien Didelot { 4852877b7cb0SAndrew Lunn struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data; 48537ddae24fSDavid S. Miller const struct mv88e6xxx_info *compat_info = NULL; 4854fad09c73SVivien Didelot struct device *dev = &mdiodev->dev; 4855fad09c73SVivien Didelot struct device_node *np = dev->of_node; 4856fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 4857877b7cb0SAndrew Lunn int port; 4858fad09c73SVivien Didelot int err; 4859fad09c73SVivien Didelot 48607bb8c996SAndrew Lunn if (!np && !pdata) 48617bb8c996SAndrew Lunn return -EINVAL; 48627bb8c996SAndrew Lunn 4863877b7cb0SAndrew Lunn if (np) 4864fad09c73SVivien Didelot compat_info = of_device_get_match_data(dev); 4865877b7cb0SAndrew Lunn 4866877b7cb0SAndrew Lunn if (pdata) { 4867877b7cb0SAndrew Lunn compat_info = pdata_device_get_match_data(dev); 4868877b7cb0SAndrew Lunn 4869877b7cb0SAndrew Lunn if (!pdata->netdev) 4870877b7cb0SAndrew Lunn return -EINVAL; 4871877b7cb0SAndrew Lunn 4872877b7cb0SAndrew Lunn for (port = 0; port < DSA_MAX_PORTS; port++) { 4873877b7cb0SAndrew Lunn if (!(pdata->enabled_ports & (1 << port))) 4874877b7cb0SAndrew Lunn continue; 4875877b7cb0SAndrew Lunn if (strcmp(pdata->cd.port_names[port], "cpu")) 4876877b7cb0SAndrew Lunn continue; 4877877b7cb0SAndrew Lunn pdata->cd.netdev[port] = &pdata->netdev->dev; 4878877b7cb0SAndrew Lunn break; 4879877b7cb0SAndrew Lunn } 4880877b7cb0SAndrew Lunn } 4881877b7cb0SAndrew Lunn 4882fad09c73SVivien Didelot if (!compat_info) 4883fad09c73SVivien Didelot return -EINVAL; 4884fad09c73SVivien Didelot 4885fad09c73SVivien Didelot chip = mv88e6xxx_alloc_chip(dev); 4886877b7cb0SAndrew Lunn if (!chip) { 4887877b7cb0SAndrew Lunn err = -ENOMEM; 4888877b7cb0SAndrew Lunn goto out; 4889877b7cb0SAndrew Lunn } 4890fad09c73SVivien Didelot 4891fad09c73SVivien Didelot chip->info = compat_info; 4892fad09c73SVivien Didelot 4893fad09c73SVivien Didelot err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr); 4894fad09c73SVivien Didelot if (err) 4895877b7cb0SAndrew Lunn goto out; 4896fad09c73SVivien Didelot 4897b4308f04SAndrew Lunn chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 4898877b7cb0SAndrew Lunn if (IS_ERR(chip->reset)) { 4899877b7cb0SAndrew Lunn err = PTR_ERR(chip->reset); 4900877b7cb0SAndrew Lunn goto out; 4901877b7cb0SAndrew Lunn } 4902b4308f04SAndrew Lunn 4903fad09c73SVivien Didelot err = mv88e6xxx_detect(chip); 4904fad09c73SVivien Didelot if (err) 4905877b7cb0SAndrew Lunn goto out; 4906fad09c73SVivien Didelot 4907e57e5e77SVivien Didelot mv88e6xxx_phy_init(chip); 4908e57e5e77SVivien Didelot 490900baabe5SAndrew Lunn if (chip->info->ops->get_eeprom) { 491000baabe5SAndrew Lunn if (np) 491100baabe5SAndrew Lunn of_property_read_u32(np, "eeprom-length", 491200baabe5SAndrew Lunn &chip->eeprom_len); 491300baabe5SAndrew Lunn else 491400baabe5SAndrew Lunn chip->eeprom_len = pdata->eeprom_len; 491500baabe5SAndrew Lunn } 4916fad09c73SVivien Didelot 4917dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 4918dc30c35bSAndrew Lunn err = mv88e6xxx_switch_reset(chip); 4919dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 4920fad09c73SVivien Didelot if (err) 4921dc30c35bSAndrew Lunn goto out; 4922fad09c73SVivien Didelot 4923dc30c35bSAndrew Lunn chip->irq = of_irq_get(np, 0); 4924dc30c35bSAndrew Lunn if (chip->irq == -EPROBE_DEFER) { 4925dc30c35bSAndrew Lunn err = chip->irq; 4926dc30c35bSAndrew Lunn goto out; 4927fad09c73SVivien Didelot } 4928fad09c73SVivien Didelot 4929294d711eSAndrew Lunn /* Has to be performed before the MDIO bus is created, because 4930a708767eSUwe Kleine-König * the PHYs will link their interrupts to these interrupt 4931294d711eSAndrew Lunn * controllers 4932dc30c35bSAndrew Lunn */ 4933dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 4934294d711eSAndrew Lunn if (chip->irq > 0) 4935dc30c35bSAndrew Lunn err = mv88e6xxx_g1_irq_setup(chip); 4936294d711eSAndrew Lunn else 4937294d711eSAndrew Lunn err = mv88e6xxx_irq_poll_setup(chip); 4938dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 4939dc30c35bSAndrew Lunn 4940dc30c35bSAndrew Lunn if (err) 4941dc30c35bSAndrew Lunn goto out; 4942dc30c35bSAndrew Lunn 4943d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) { 4944dc30c35bSAndrew Lunn err = mv88e6xxx_g2_irq_setup(chip); 4945dc30c35bSAndrew Lunn if (err) 4946dc30c35bSAndrew Lunn goto out_g1_irq; 4947dc30c35bSAndrew Lunn } 49480977644cSAndrew Lunn 49490977644cSAndrew Lunn err = mv88e6xxx_g1_atu_prob_irq_setup(chip); 49500977644cSAndrew Lunn if (err) 49510977644cSAndrew Lunn goto out_g2_irq; 495262eb1162SAndrew Lunn 495362eb1162SAndrew Lunn err = mv88e6xxx_g1_vtu_prob_irq_setup(chip); 495462eb1162SAndrew Lunn if (err) 495562eb1162SAndrew Lunn goto out_g1_atu_prob_irq; 4956dc30c35bSAndrew Lunn 4957a3c53be5SAndrew Lunn err = mv88e6xxx_mdios_register(chip, np); 4958dc30c35bSAndrew Lunn if (err) 495962eb1162SAndrew Lunn goto out_g1_vtu_prob_irq; 4960dc30c35bSAndrew Lunn 496155ed0ce0SFlorian Fainelli err = mv88e6xxx_register_switch(chip); 4962dc30c35bSAndrew Lunn if (err) 4963dc30c35bSAndrew Lunn goto out_mdio; 4964dc30c35bSAndrew Lunn 4965fad09c73SVivien Didelot return 0; 4966dc30c35bSAndrew Lunn 4967dc30c35bSAndrew Lunn out_mdio: 4968a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 496962eb1162SAndrew Lunn out_g1_vtu_prob_irq: 497062eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 49710977644cSAndrew Lunn out_g1_atu_prob_irq: 49720977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 4973dc30c35bSAndrew Lunn out_g2_irq: 4974294d711eSAndrew Lunn if (chip->info->g2_irqs > 0) 4975dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 4976dc30c35bSAndrew Lunn out_g1_irq: 4977294d711eSAndrew Lunn if (chip->irq > 0) 4978dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 4979294d711eSAndrew Lunn else 4980294d711eSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 4981dc30c35bSAndrew Lunn out: 4982877b7cb0SAndrew Lunn if (pdata) 4983877b7cb0SAndrew Lunn dev_put(pdata->netdev); 4984877b7cb0SAndrew Lunn 4985dc30c35bSAndrew Lunn return err; 4986fad09c73SVivien Didelot } 4987fad09c73SVivien Didelot 4988fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev) 4989fad09c73SVivien Didelot { 4990fad09c73SVivien Didelot struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 499104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 4992fad09c73SVivien Didelot 4993c6fe0ad2SBrandon Streiff if (chip->info->ptp_support) { 4994c6fe0ad2SBrandon Streiff mv88e6xxx_hwtstamp_free(chip); 49952fa8d3afSBrandon Streiff mv88e6xxx_ptp_free(chip); 4996c6fe0ad2SBrandon Streiff } 49972fa8d3afSBrandon Streiff 4998930188ceSAndrew Lunn mv88e6xxx_phy_destroy(chip); 4999fad09c73SVivien Didelot mv88e6xxx_unregister_switch(chip); 5000a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 5001dc30c35bSAndrew Lunn 500262eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 50030977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 500476f38f1fSAndrew Lunn 5005d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) 5006dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 500776f38f1fSAndrew Lunn 500876f38f1fSAndrew Lunn if (chip->irq > 0) 5009dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 501076f38f1fSAndrew Lunn else 501176f38f1fSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 5012fad09c73SVivien Didelot } 5013fad09c73SVivien Didelot 5014fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = { 5015fad09c73SVivien Didelot { 5016fad09c73SVivien Didelot .compatible = "marvell,mv88e6085", 5017fad09c73SVivien Didelot .data = &mv88e6xxx_table[MV88E6085], 5018fad09c73SVivien Didelot }, 50191a3b39ecSAndrew Lunn { 50201a3b39ecSAndrew Lunn .compatible = "marvell,mv88e6190", 50211a3b39ecSAndrew Lunn .data = &mv88e6xxx_table[MV88E6190], 50221a3b39ecSAndrew Lunn }, 5023fad09c73SVivien Didelot { /* sentinel */ }, 5024fad09c73SVivien Didelot }; 5025fad09c73SVivien Didelot 5026fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match); 5027fad09c73SVivien Didelot 5028fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = { 5029fad09c73SVivien Didelot .probe = mv88e6xxx_probe, 5030fad09c73SVivien Didelot .remove = mv88e6xxx_remove, 5031fad09c73SVivien Didelot .mdiodrv.driver = { 5032fad09c73SVivien Didelot .name = "mv88e6085", 5033fad09c73SVivien Didelot .of_match_table = mv88e6xxx_of_match, 5034bcd3d9d9SMiquel Raynal .pm = &mv88e6xxx_pm_ops, 5035fad09c73SVivien Didelot }, 5036fad09c73SVivien Didelot }; 5037fad09c73SVivien Didelot 5038fad09c73SVivien Didelot static int __init mv88e6xxx_init(void) 5039fad09c73SVivien Didelot { 5040ab3d408dSFlorian Fainelli register_switch_driver(&mv88e6xxx_switch_drv); 5041fad09c73SVivien Didelot return mdio_driver_register(&mv88e6xxx_driver); 5042fad09c73SVivien Didelot } 5043fad09c73SVivien Didelot module_init(mv88e6xxx_init); 5044fad09c73SVivien Didelot 5045fad09c73SVivien Didelot static void __exit mv88e6xxx_cleanup(void) 5046fad09c73SVivien Didelot { 5047fad09c73SVivien Didelot mdio_driver_unregister(&mv88e6xxx_driver); 5048ab3d408dSFlorian Fainelli unregister_switch_driver(&mv88e6xxx_switch_drv); 5049fad09c73SVivien Didelot } 5050fad09c73SVivien Didelot module_exit(mv88e6xxx_cleanup); 5051fad09c73SVivien Didelot 5052fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); 5053fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips"); 5054fad09c73SVivien Didelot MODULE_LICENSE("GPL"); 5055