12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2fad09c73SVivien Didelot /* 3fad09c73SVivien Didelot * Marvell 88e6xxx Ethernet switch single-chip support 4fad09c73SVivien Didelot * 5fad09c73SVivien Didelot * Copyright (c) 2008 Marvell Semiconductor 6fad09c73SVivien Didelot * 7fad09c73SVivien Didelot * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch> 8fad09c73SVivien Didelot * 94333d619SVivien Didelot * Copyright (c) 2016-2017 Savoir-faire Linux Inc. 104333d619SVivien Didelot * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 11fad09c73SVivien Didelot */ 12fad09c73SVivien Didelot 13fad09c73SVivien Didelot #include <linux/delay.h> 14fad09c73SVivien Didelot #include <linux/etherdevice.h> 15fad09c73SVivien Didelot #include <linux/ethtool.h> 16fad09c73SVivien Didelot #include <linux/if_bridge.h> 17dc30c35bSAndrew Lunn #include <linux/interrupt.h> 18dc30c35bSAndrew Lunn #include <linux/irq.h> 19dc30c35bSAndrew Lunn #include <linux/irqdomain.h> 20fad09c73SVivien Didelot #include <linux/jiffies.h> 21fad09c73SVivien Didelot #include <linux/list.h> 22fad09c73SVivien Didelot #include <linux/mdio.h> 23fad09c73SVivien Didelot #include <linux/module.h> 24fad09c73SVivien Didelot #include <linux/of_device.h> 25dc30c35bSAndrew Lunn #include <linux/of_irq.h> 26fad09c73SVivien Didelot #include <linux/of_mdio.h> 27877b7cb0SAndrew Lunn #include <linux/platform_data/mv88e6xxx.h> 28fad09c73SVivien Didelot #include <linux/netdevice.h> 29fad09c73SVivien Didelot #include <linux/gpio/consumer.h> 30fad09c73SVivien Didelot #include <linux/phy.h> 31c9a2356fSRussell King #include <linux/phylink.h> 32fad09c73SVivien Didelot #include <net/dsa.h> 33ec561276SVivien Didelot 344d5f2ba7SVivien Didelot #include "chip.h" 35a935c052SVivien Didelot #include "global1.h" 36ec561276SVivien Didelot #include "global2.h" 37c6fe0ad2SBrandon Streiff #include "hwtstamp.h" 3810fa5bfcSAndrew Lunn #include "phy.h" 3918abed21SVivien Didelot #include "port.h" 402fa8d3afSBrandon Streiff #include "ptp.h" 416d91782fSAndrew Lunn #include "serdes.h" 42e7ba0fadSVivien Didelot #include "smi.h" 43fad09c73SVivien Didelot 44fad09c73SVivien Didelot static void assert_reg_lock(struct mv88e6xxx_chip *chip) 45fad09c73SVivien Didelot { 46fad09c73SVivien Didelot if (unlikely(!mutex_is_locked(&chip->reg_lock))) { 47fad09c73SVivien Didelot dev_err(chip->dev, "Switch registers lock not held!\n"); 48fad09c73SVivien Didelot dump_stack(); 49fad09c73SVivien Didelot } 50fad09c73SVivien Didelot } 51fad09c73SVivien Didelot 52ec561276SVivien Didelot int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val) 53fad09c73SVivien Didelot { 54fad09c73SVivien Didelot int err; 55fad09c73SVivien Didelot 56fad09c73SVivien Didelot assert_reg_lock(chip); 57fad09c73SVivien Didelot 58fad09c73SVivien Didelot err = mv88e6xxx_smi_read(chip, addr, reg, val); 59fad09c73SVivien Didelot if (err) 60fad09c73SVivien Didelot return err; 61fad09c73SVivien Didelot 62fad09c73SVivien Didelot dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 63fad09c73SVivien Didelot addr, reg, *val); 64fad09c73SVivien Didelot 65fad09c73SVivien Didelot return 0; 66fad09c73SVivien Didelot } 67fad09c73SVivien Didelot 68ec561276SVivien Didelot int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val) 69fad09c73SVivien Didelot { 70fad09c73SVivien Didelot int err; 71fad09c73SVivien Didelot 72fad09c73SVivien Didelot assert_reg_lock(chip); 73fad09c73SVivien Didelot 74fad09c73SVivien Didelot err = mv88e6xxx_smi_write(chip, addr, reg, val); 75fad09c73SVivien Didelot if (err) 76fad09c73SVivien Didelot return err; 77fad09c73SVivien Didelot 78fad09c73SVivien Didelot dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 79fad09c73SVivien Didelot addr, reg, val); 80fad09c73SVivien Didelot 81fad09c73SVivien Didelot return 0; 82fad09c73SVivien Didelot } 83fad09c73SVivien Didelot 8410fa5bfcSAndrew Lunn struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) 85a3c53be5SAndrew Lunn { 86a3c53be5SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 87a3c53be5SAndrew Lunn 88a3c53be5SAndrew Lunn mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus, 89a3c53be5SAndrew Lunn list); 90a3c53be5SAndrew Lunn if (!mdio_bus) 91a3c53be5SAndrew Lunn return NULL; 92a3c53be5SAndrew Lunn 93a3c53be5SAndrew Lunn return mdio_bus->bus; 94a3c53be5SAndrew Lunn } 95a3c53be5SAndrew Lunn 96dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_mask(struct irq_data *d) 97dc30c35bSAndrew Lunn { 98dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 99dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 100dc30c35bSAndrew Lunn 101dc30c35bSAndrew Lunn chip->g1_irq.masked |= (1 << n); 102dc30c35bSAndrew Lunn } 103dc30c35bSAndrew Lunn 104dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_unmask(struct irq_data *d) 105dc30c35bSAndrew Lunn { 106dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 107dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 108dc30c35bSAndrew Lunn 109dc30c35bSAndrew Lunn chip->g1_irq.masked &= ~(1 << n); 110dc30c35bSAndrew Lunn } 111dc30c35bSAndrew Lunn 112294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip) 113dc30c35bSAndrew Lunn { 114dc30c35bSAndrew Lunn unsigned int nhandled = 0; 115dc30c35bSAndrew Lunn unsigned int sub_irq; 116dc30c35bSAndrew Lunn unsigned int n; 117dc30c35bSAndrew Lunn u16 reg; 1187c0db24cSJohn David Anglin u16 ctl1; 119dc30c35bSAndrew Lunn int err; 120dc30c35bSAndrew Lunn 121dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 12282466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 123dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 124dc30c35bSAndrew Lunn 125dc30c35bSAndrew Lunn if (err) 126dc30c35bSAndrew Lunn goto out; 127dc30c35bSAndrew Lunn 1287c0db24cSJohn David Anglin do { 129dc30c35bSAndrew Lunn for (n = 0; n < chip->g1_irq.nirqs; ++n) { 130dc30c35bSAndrew Lunn if (reg & (1 << n)) { 1317c0db24cSJohn David Anglin sub_irq = irq_find_mapping(chip->g1_irq.domain, 1327c0db24cSJohn David Anglin n); 133dc30c35bSAndrew Lunn handle_nested_irq(sub_irq); 134dc30c35bSAndrew Lunn ++nhandled; 135dc30c35bSAndrew Lunn } 136dc30c35bSAndrew Lunn } 1377c0db24cSJohn David Anglin 1387c0db24cSJohn David Anglin mutex_lock(&chip->reg_lock); 1397c0db24cSJohn David Anglin err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1); 1407c0db24cSJohn David Anglin if (err) 1417c0db24cSJohn David Anglin goto unlock; 1427c0db24cSJohn David Anglin err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 1437c0db24cSJohn David Anglin unlock: 1447c0db24cSJohn David Anglin mutex_unlock(&chip->reg_lock); 1457c0db24cSJohn David Anglin if (err) 1467c0db24cSJohn David Anglin goto out; 1477c0db24cSJohn David Anglin ctl1 &= GENMASK(chip->g1_irq.nirqs, 0); 1487c0db24cSJohn David Anglin } while (reg & ctl1); 1497c0db24cSJohn David Anglin 150dc30c35bSAndrew Lunn out: 151dc30c35bSAndrew Lunn return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); 152dc30c35bSAndrew Lunn } 153dc30c35bSAndrew Lunn 154294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id) 155294d711eSAndrew Lunn { 156294d711eSAndrew Lunn struct mv88e6xxx_chip *chip = dev_id; 157294d711eSAndrew Lunn 158294d711eSAndrew Lunn return mv88e6xxx_g1_irq_thread_work(chip); 159294d711eSAndrew Lunn } 160294d711eSAndrew Lunn 161dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d) 162dc30c35bSAndrew Lunn { 163dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 164dc30c35bSAndrew Lunn 165dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 166dc30c35bSAndrew Lunn } 167dc30c35bSAndrew Lunn 168dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d) 169dc30c35bSAndrew Lunn { 170dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 171dc30c35bSAndrew Lunn u16 mask = GENMASK(chip->g1_irq.nirqs, 0); 172dc30c35bSAndrew Lunn u16 reg; 173dc30c35bSAndrew Lunn int err; 174dc30c35bSAndrew Lunn 175d77f4321SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, ®); 176dc30c35bSAndrew Lunn if (err) 177dc30c35bSAndrew Lunn goto out; 178dc30c35bSAndrew Lunn 179dc30c35bSAndrew Lunn reg &= ~mask; 180dc30c35bSAndrew Lunn reg |= (~chip->g1_irq.masked & mask); 181dc30c35bSAndrew Lunn 182d77f4321SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg); 183dc30c35bSAndrew Lunn if (err) 184dc30c35bSAndrew Lunn goto out; 185dc30c35bSAndrew Lunn 186dc30c35bSAndrew Lunn out: 187dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 188dc30c35bSAndrew Lunn } 189dc30c35bSAndrew Lunn 1906eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g1_irq_chip = { 191dc30c35bSAndrew Lunn .name = "mv88e6xxx-g1", 192dc30c35bSAndrew Lunn .irq_mask = mv88e6xxx_g1_irq_mask, 193dc30c35bSAndrew Lunn .irq_unmask = mv88e6xxx_g1_irq_unmask, 194dc30c35bSAndrew Lunn .irq_bus_lock = mv88e6xxx_g1_irq_bus_lock, 195dc30c35bSAndrew Lunn .irq_bus_sync_unlock = mv88e6xxx_g1_irq_bus_sync_unlock, 196dc30c35bSAndrew Lunn }; 197dc30c35bSAndrew Lunn 198dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d, 199dc30c35bSAndrew Lunn unsigned int irq, 200dc30c35bSAndrew Lunn irq_hw_number_t hwirq) 201dc30c35bSAndrew Lunn { 202dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = d->host_data; 203dc30c35bSAndrew Lunn 204dc30c35bSAndrew Lunn irq_set_chip_data(irq, d->host_data); 205dc30c35bSAndrew Lunn irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq); 206dc30c35bSAndrew Lunn irq_set_noprobe(irq); 207dc30c35bSAndrew Lunn 208dc30c35bSAndrew Lunn return 0; 209dc30c35bSAndrew Lunn } 210dc30c35bSAndrew Lunn 211dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = { 212dc30c35bSAndrew Lunn .map = mv88e6xxx_g1_irq_domain_map, 213dc30c35bSAndrew Lunn .xlate = irq_domain_xlate_twocell, 214dc30c35bSAndrew Lunn }; 215dc30c35bSAndrew Lunn 2163d82475aSUwe Kleine-König /* To be called with reg_lock held */ 217294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip) 218dc30c35bSAndrew Lunn { 219dc30c35bSAndrew Lunn int irq, virq; 2203460a577SAndrew Lunn u16 mask; 2213460a577SAndrew Lunn 222d77f4321SVivien Didelot mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 2233d5fdba1SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 224d77f4321SVivien Didelot mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 2253460a577SAndrew Lunn 2265edef2f2SAndreas Färber for (irq = 0; irq < chip->g1_irq.nirqs; irq++) { 227a3db3d3aSAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 228dc30c35bSAndrew Lunn irq_dispose_mapping(virq); 229dc30c35bSAndrew Lunn } 230dc30c35bSAndrew Lunn 231a3db3d3aSAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 232dc30c35bSAndrew Lunn } 233dc30c35bSAndrew Lunn 234294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) 235294d711eSAndrew Lunn { 2363d82475aSUwe Kleine-König /* 2373d82475aSUwe Kleine-König * free_irq must be called without reg_lock taken because the irq 2383d82475aSUwe Kleine-König * handler takes this lock, too. 2393d82475aSUwe Kleine-König */ 240294d711eSAndrew Lunn free_irq(chip->irq, chip); 2413d82475aSUwe Kleine-König 2423d82475aSUwe Kleine-König mutex_lock(&chip->reg_lock); 2433d82475aSUwe Kleine-König mv88e6xxx_g1_irq_free_common(chip); 2443d82475aSUwe Kleine-König mutex_unlock(&chip->reg_lock); 245294d711eSAndrew Lunn } 246294d711eSAndrew Lunn 247294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip) 248dc30c35bSAndrew Lunn { 2493dd0ef05SAndrew Lunn int err, irq, virq; 2503dd0ef05SAndrew Lunn u16 reg, mask; 251dc30c35bSAndrew Lunn 252dc30c35bSAndrew Lunn chip->g1_irq.nirqs = chip->info->g1_irqs; 253dc30c35bSAndrew Lunn chip->g1_irq.domain = irq_domain_add_simple( 254dc30c35bSAndrew Lunn NULL, chip->g1_irq.nirqs, 0, 255dc30c35bSAndrew Lunn &mv88e6xxx_g1_irq_domain_ops, chip); 256dc30c35bSAndrew Lunn if (!chip->g1_irq.domain) 257dc30c35bSAndrew Lunn return -ENOMEM; 258dc30c35bSAndrew Lunn 259dc30c35bSAndrew Lunn for (irq = 0; irq < chip->g1_irq.nirqs; irq++) 260dc30c35bSAndrew Lunn irq_create_mapping(chip->g1_irq.domain, irq); 261dc30c35bSAndrew Lunn 262dc30c35bSAndrew Lunn chip->g1_irq.chip = mv88e6xxx_g1_irq_chip; 263dc30c35bSAndrew Lunn chip->g1_irq.masked = ~0; 264dc30c35bSAndrew Lunn 265d77f4321SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 266dc30c35bSAndrew Lunn if (err) 2673dd0ef05SAndrew Lunn goto out_mapping; 268dc30c35bSAndrew Lunn 2693dd0ef05SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 270dc30c35bSAndrew Lunn 271d77f4321SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 272dc30c35bSAndrew Lunn if (err) 2733dd0ef05SAndrew Lunn goto out_disable; 274dc30c35bSAndrew Lunn 275dc30c35bSAndrew Lunn /* Reading the interrupt status clears (most of) them */ 27682466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 277dc30c35bSAndrew Lunn if (err) 2783dd0ef05SAndrew Lunn goto out_disable; 279dc30c35bSAndrew Lunn 280dc30c35bSAndrew Lunn return 0; 281dc30c35bSAndrew Lunn 2823dd0ef05SAndrew Lunn out_disable: 2833d5fdba1SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 284d77f4321SVivien Didelot mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 2853dd0ef05SAndrew Lunn 2863dd0ef05SAndrew Lunn out_mapping: 2873dd0ef05SAndrew Lunn for (irq = 0; irq < 16; irq++) { 2883dd0ef05SAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 2893dd0ef05SAndrew Lunn irq_dispose_mapping(virq); 2903dd0ef05SAndrew Lunn } 2913dd0ef05SAndrew Lunn 2923dd0ef05SAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 293dc30c35bSAndrew Lunn 294dc30c35bSAndrew Lunn return err; 295dc30c35bSAndrew Lunn } 296dc30c35bSAndrew Lunn 297294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) 298294d711eSAndrew Lunn { 299f6d9758bSAndrew Lunn static struct lock_class_key lock_key; 300f6d9758bSAndrew Lunn static struct lock_class_key request_key; 301294d711eSAndrew Lunn int err; 302294d711eSAndrew Lunn 303294d711eSAndrew Lunn err = mv88e6xxx_g1_irq_setup_common(chip); 304294d711eSAndrew Lunn if (err) 305294d711eSAndrew Lunn return err; 306294d711eSAndrew Lunn 307f6d9758bSAndrew Lunn /* These lock classes tells lockdep that global 1 irqs are in 308f6d9758bSAndrew Lunn * a different category than their parent GPIO, so it won't 309f6d9758bSAndrew Lunn * report false recursion. 310f6d9758bSAndrew Lunn */ 311f6d9758bSAndrew Lunn irq_set_lockdep_class(chip->irq, &lock_key, &request_key); 312f6d9758bSAndrew Lunn 313342a0ee7SAndrew Lunn mutex_unlock(&chip->reg_lock); 314294d711eSAndrew Lunn err = request_threaded_irq(chip->irq, NULL, 315294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_fn, 3160340376eSMarek Behún IRQF_ONESHOT | IRQF_SHARED, 317294d711eSAndrew Lunn dev_name(chip->dev), chip); 318342a0ee7SAndrew Lunn mutex_lock(&chip->reg_lock); 319294d711eSAndrew Lunn if (err) 320294d711eSAndrew Lunn mv88e6xxx_g1_irq_free_common(chip); 321294d711eSAndrew Lunn 322294d711eSAndrew Lunn return err; 323294d711eSAndrew Lunn } 324294d711eSAndrew Lunn 325294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work) 326294d711eSAndrew Lunn { 327294d711eSAndrew Lunn struct mv88e6xxx_chip *chip = container_of(work, 328294d711eSAndrew Lunn struct mv88e6xxx_chip, 329294d711eSAndrew Lunn irq_poll_work.work); 330294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_work(chip); 331294d711eSAndrew Lunn 332294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 333294d711eSAndrew Lunn msecs_to_jiffies(100)); 334294d711eSAndrew Lunn } 335294d711eSAndrew Lunn 336294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip) 337294d711eSAndrew Lunn { 338294d711eSAndrew Lunn int err; 339294d711eSAndrew Lunn 340294d711eSAndrew Lunn err = mv88e6xxx_g1_irq_setup_common(chip); 341294d711eSAndrew Lunn if (err) 342294d711eSAndrew Lunn return err; 343294d711eSAndrew Lunn 344294d711eSAndrew Lunn kthread_init_delayed_work(&chip->irq_poll_work, 345294d711eSAndrew Lunn mv88e6xxx_irq_poll); 346294d711eSAndrew Lunn 3473f8b8696SFlorian Fainelli chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev)); 348294d711eSAndrew Lunn if (IS_ERR(chip->kworker)) 349294d711eSAndrew Lunn return PTR_ERR(chip->kworker); 350294d711eSAndrew Lunn 351294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 352294d711eSAndrew Lunn msecs_to_jiffies(100)); 353294d711eSAndrew Lunn 354294d711eSAndrew Lunn return 0; 355294d711eSAndrew Lunn } 356294d711eSAndrew Lunn 357294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip) 358294d711eSAndrew Lunn { 359294d711eSAndrew Lunn kthread_cancel_delayed_work_sync(&chip->irq_poll_work); 360294d711eSAndrew Lunn kthread_destroy_worker(chip->kworker); 3613d82475aSUwe Kleine-König 3623d82475aSUwe Kleine-König mutex_lock(&chip->reg_lock); 3633d82475aSUwe Kleine-König mv88e6xxx_g1_irq_free_common(chip); 3643d82475aSUwe Kleine-König mutex_unlock(&chip->reg_lock); 365294d711eSAndrew Lunn } 366294d711eSAndrew Lunn 367ec561276SVivien Didelot int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask) 3682d79af6eSVivien Didelot { 3696441e669SAndrew Lunn int i; 3702d79af6eSVivien Didelot 3716441e669SAndrew Lunn for (i = 0; i < 16; i++) { 3722d79af6eSVivien Didelot u16 val; 3732d79af6eSVivien Didelot int err; 3742d79af6eSVivien Didelot 3752d79af6eSVivien Didelot err = mv88e6xxx_read(chip, addr, reg, &val); 3762d79af6eSVivien Didelot if (err) 3772d79af6eSVivien Didelot return err; 3782d79af6eSVivien Didelot 3792d79af6eSVivien Didelot if (!(val & mask)) 3802d79af6eSVivien Didelot return 0; 3812d79af6eSVivien Didelot 3822d79af6eSVivien Didelot usleep_range(1000, 2000); 3832d79af6eSVivien Didelot } 3842d79af6eSVivien Didelot 38530853553SAndrew Lunn dev_err(chip->dev, "Timeout while waiting for switch\n"); 3862d79af6eSVivien Didelot return -ETIMEDOUT; 3872d79af6eSVivien Didelot } 3882d79af6eSVivien Didelot 389f22ab641SVivien Didelot /* Indirect write to single pointer-data register with an Update bit */ 390ec561276SVivien Didelot int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update) 391f22ab641SVivien Didelot { 392f22ab641SVivien Didelot u16 val; 3930f02b4f7SAndrew Lunn int err; 394f22ab641SVivien Didelot 395f22ab641SVivien Didelot /* Wait until the previous operation is completed */ 3960f02b4f7SAndrew Lunn err = mv88e6xxx_wait(chip, addr, reg, BIT(15)); 397f22ab641SVivien Didelot if (err) 398f22ab641SVivien Didelot return err; 399f22ab641SVivien Didelot 400f22ab641SVivien Didelot /* Set the Update bit to trigger a write operation */ 401f22ab641SVivien Didelot val = BIT(15) | update; 402f22ab641SVivien Didelot 403f22ab641SVivien Didelot return mv88e6xxx_write(chip, addr, reg, val); 404f22ab641SVivien Didelot } 405f22ab641SVivien Didelot 40672d8b4fdSHeiner Kallweit int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link, 40772d8b4fdSHeiner Kallweit int speed, int duplex, int pause, 408d78343d2SVivien Didelot phy_interface_t mode) 409d78343d2SVivien Didelot { 410a26deec6SAndrew Lunn struct phylink_link_state state; 411d78343d2SVivien Didelot int err; 412d78343d2SVivien Didelot 413d78343d2SVivien Didelot if (!chip->info->ops->port_set_link) 414d78343d2SVivien Didelot return 0; 415d78343d2SVivien Didelot 416a26deec6SAndrew Lunn if (!chip->info->ops->port_link_state) 417a26deec6SAndrew Lunn return 0; 418a26deec6SAndrew Lunn 419a26deec6SAndrew Lunn err = chip->info->ops->port_link_state(chip, port, &state); 420a26deec6SAndrew Lunn if (err) 421a26deec6SAndrew Lunn return err; 422a26deec6SAndrew Lunn 423a26deec6SAndrew Lunn /* Has anything actually changed? We don't expect the 424a26deec6SAndrew Lunn * interface mode to change without one of the other 425a26deec6SAndrew Lunn * parameters also changing 426a26deec6SAndrew Lunn */ 427a26deec6SAndrew Lunn if (state.link == link && 428a26deec6SAndrew Lunn state.speed == speed && 429a26deec6SAndrew Lunn state.duplex == duplex) 430a26deec6SAndrew Lunn return 0; 431a26deec6SAndrew Lunn 432d78343d2SVivien Didelot /* Port's MAC control must not be changed unless the link is down */ 433d78343d2SVivien Didelot err = chip->info->ops->port_set_link(chip, port, 0); 434d78343d2SVivien Didelot if (err) 435d78343d2SVivien Didelot return err; 436d78343d2SVivien Didelot 437d78343d2SVivien Didelot if (chip->info->ops->port_set_speed) { 438d78343d2SVivien Didelot err = chip->info->ops->port_set_speed(chip, port, speed); 439d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 440d78343d2SVivien Didelot goto restore_link; 441d78343d2SVivien Didelot } 442d78343d2SVivien Didelot 4437cbbee05SAndrew Lunn if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode) 4447cbbee05SAndrew Lunn mode = chip->info->ops->port_max_speed_mode(port); 4457cbbee05SAndrew Lunn 44654186b91SAndrew Lunn if (chip->info->ops->port_set_pause) { 44754186b91SAndrew Lunn err = chip->info->ops->port_set_pause(chip, port, pause); 44854186b91SAndrew Lunn if (err) 44954186b91SAndrew Lunn goto restore_link; 45054186b91SAndrew Lunn } 45154186b91SAndrew Lunn 452d78343d2SVivien Didelot if (chip->info->ops->port_set_duplex) { 453d78343d2SVivien Didelot err = chip->info->ops->port_set_duplex(chip, port, duplex); 454d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 455d78343d2SVivien Didelot goto restore_link; 456d78343d2SVivien Didelot } 457d78343d2SVivien Didelot 458d78343d2SVivien Didelot if (chip->info->ops->port_set_rgmii_delay) { 459d78343d2SVivien Didelot err = chip->info->ops->port_set_rgmii_delay(chip, port, mode); 460d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 461d78343d2SVivien Didelot goto restore_link; 462d78343d2SVivien Didelot } 463d78343d2SVivien Didelot 464f39908d3SAndrew Lunn if (chip->info->ops->port_set_cmode) { 465f39908d3SAndrew Lunn err = chip->info->ops->port_set_cmode(chip, port, mode); 466f39908d3SAndrew Lunn if (err && err != -EOPNOTSUPP) 467f39908d3SAndrew Lunn goto restore_link; 468f39908d3SAndrew Lunn } 469f39908d3SAndrew Lunn 470d78343d2SVivien Didelot err = 0; 471d78343d2SVivien Didelot restore_link: 472d78343d2SVivien Didelot if (chip->info->ops->port_set_link(chip, port, link)) 473774439e5SVivien Didelot dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port); 474d78343d2SVivien Didelot 475d78343d2SVivien Didelot return err; 476d78343d2SVivien Didelot } 477d78343d2SVivien Didelot 478d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) 479d700ec41SMarek Vasut { 480d700ec41SMarek Vasut struct mv88e6xxx_chip *chip = ds->priv; 481d700ec41SMarek Vasut 482d700ec41SMarek Vasut return port < chip->info->num_internal_phys; 483d700ec41SMarek Vasut } 484d700ec41SMarek Vasut 485fad09c73SVivien Didelot /* We expect the switch to perform auto negotiation if there is a real 486fad09c73SVivien Didelot * phy. However, in the case of a fixed link phy, we force the port 487fad09c73SVivien Didelot * settings from the fixed link settings. 488fad09c73SVivien Didelot */ 489fad09c73SVivien Didelot static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, 490fad09c73SVivien Didelot struct phy_device *phydev) 491fad09c73SVivien Didelot { 49204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 4930e7b9925SAndrew Lunn int err; 494fad09c73SVivien Didelot 495d700ec41SMarek Vasut if (!phy_is_pseudo_fixed_link(phydev) && 496d700ec41SMarek Vasut mv88e6xxx_phy_is_internal(ds, port)) 497fad09c73SVivien Didelot return; 498fad09c73SVivien Didelot 499fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 500d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed, 50154186b91SAndrew Lunn phydev->duplex, phydev->pause, 50254186b91SAndrew Lunn phydev->interface); 503fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 504d78343d2SVivien Didelot 505d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 506774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to configure MAC\n", port); 507fad09c73SVivien Didelot } 508fad09c73SVivien Didelot 5096c422e34SRussell King static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5106c422e34SRussell King unsigned long *mask, 5116c422e34SRussell King struct phylink_link_state *state) 5126c422e34SRussell King { 5136c422e34SRussell King if (!phy_interface_mode_is_8023z(state->interface)) { 5146c422e34SRussell King /* 10M and 100M are only supported in non-802.3z mode */ 5156c422e34SRussell King phylink_set(mask, 10baseT_Half); 5166c422e34SRussell King phylink_set(mask, 10baseT_Full); 5176c422e34SRussell King phylink_set(mask, 100baseT_Half); 5186c422e34SRussell King phylink_set(mask, 100baseT_Full); 5196c422e34SRussell King } 5206c422e34SRussell King } 5216c422e34SRussell King 5226c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5236c422e34SRussell King unsigned long *mask, 5246c422e34SRussell King struct phylink_link_state *state) 5256c422e34SRussell King { 5266c422e34SRussell King /* FIXME: if the port is in 1000Base-X mode, then it only supports 5276c422e34SRussell King * 1000M FD speeds. In this case, CMODE will indicate 5. 5286c422e34SRussell King */ 5296c422e34SRussell King phylink_set(mask, 1000baseT_Full); 5306c422e34SRussell King phylink_set(mask, 1000baseX_Full); 5316c422e34SRussell King 5326c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 5336c422e34SRussell King } 5346c422e34SRussell King 535e3af71a3SMarek Behún static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port, 536e3af71a3SMarek Behún unsigned long *mask, 537e3af71a3SMarek Behún struct phylink_link_state *state) 538e3af71a3SMarek Behún { 539e3af71a3SMarek Behún if (port >= 5) 540e3af71a3SMarek Behún phylink_set(mask, 2500baseX_Full); 541e3af71a3SMarek Behún 542e3af71a3SMarek Behún /* No ethtool bits for 200Mbps */ 543e3af71a3SMarek Behún phylink_set(mask, 1000baseT_Full); 544e3af71a3SMarek Behún phylink_set(mask, 1000baseX_Full); 545e3af71a3SMarek Behún 546e3af71a3SMarek Behún mv88e6065_phylink_validate(chip, port, mask, state); 547e3af71a3SMarek Behún } 548e3af71a3SMarek Behún 5496c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5506c422e34SRussell King unsigned long *mask, 5516c422e34SRussell King struct phylink_link_state *state) 5526c422e34SRussell King { 5536c422e34SRussell King /* No ethtool bits for 200Mbps */ 5546c422e34SRussell King phylink_set(mask, 1000baseT_Full); 5556c422e34SRussell King phylink_set(mask, 1000baseX_Full); 5566c422e34SRussell King 5576c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 5586c422e34SRussell King } 5596c422e34SRussell King 5606c422e34SRussell King static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5616c422e34SRussell King unsigned long *mask, 5626c422e34SRussell King struct phylink_link_state *state) 5636c422e34SRussell King { 564ec26016bSAndrew Lunn if (port >= 9) { 5656c422e34SRussell King phylink_set(mask, 2500baseX_Full); 566ec26016bSAndrew Lunn phylink_set(mask, 2500baseT_Full); 567ec26016bSAndrew Lunn } 5686c422e34SRussell King 5696c422e34SRussell King /* No ethtool bits for 200Mbps */ 5706c422e34SRussell King phylink_set(mask, 1000baseT_Full); 5716c422e34SRussell King phylink_set(mask, 1000baseX_Full); 5726c422e34SRussell King 5736c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 5746c422e34SRussell King } 5756c422e34SRussell King 5766c422e34SRussell King static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5776c422e34SRussell King unsigned long *mask, 5786c422e34SRussell King struct phylink_link_state *state) 5796c422e34SRussell King { 5806c422e34SRussell King if (port >= 9) { 5816c422e34SRussell King phylink_set(mask, 10000baseT_Full); 5826c422e34SRussell King phylink_set(mask, 10000baseKR_Full); 5836c422e34SRussell King } 5846c422e34SRussell King 5856c422e34SRussell King mv88e6390_phylink_validate(chip, port, mask, state); 5866c422e34SRussell King } 5876c422e34SRussell King 588c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port, 589c9a2356fSRussell King unsigned long *supported, 590c9a2356fSRussell King struct phylink_link_state *state) 591c9a2356fSRussell King { 5926c422e34SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 5936c422e34SRussell King struct mv88e6xxx_chip *chip = ds->priv; 5946c422e34SRussell King 5956c422e34SRussell King /* Allow all the expected bits */ 5966c422e34SRussell King phylink_set(mask, Autoneg); 5976c422e34SRussell King phylink_set(mask, Pause); 5986c422e34SRussell King phylink_set_port_modes(mask); 5996c422e34SRussell King 6006c422e34SRussell King if (chip->info->ops->phylink_validate) 6016c422e34SRussell King chip->info->ops->phylink_validate(chip, port, mask, state); 6026c422e34SRussell King 6036c422e34SRussell King bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); 6046c422e34SRussell King bitmap_and(state->advertising, state->advertising, mask, 6056c422e34SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS); 6066c422e34SRussell King 6076c422e34SRussell King /* We can only operate at 2500BaseX or 1000BaseX. If requested 6086c422e34SRussell King * to advertise both, only report advertising at 2500BaseX. 6096c422e34SRussell King */ 6106c422e34SRussell King phylink_helper_basex_speed(state); 611c9a2356fSRussell King } 612c9a2356fSRussell King 613c9a2356fSRussell King static int mv88e6xxx_link_state(struct dsa_switch *ds, int port, 614c9a2356fSRussell King struct phylink_link_state *state) 615c9a2356fSRussell King { 616c9a2356fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 617c9a2356fSRussell King int err; 618c9a2356fSRussell King 619c9a2356fSRussell King mutex_lock(&chip->reg_lock); 6206c422e34SRussell King if (chip->info->ops->port_link_state) 6216c422e34SRussell King err = chip->info->ops->port_link_state(chip, port, state); 6226c422e34SRussell King else 6236c422e34SRussell King err = -EOPNOTSUPP; 624c9a2356fSRussell King mutex_unlock(&chip->reg_lock); 625c9a2356fSRussell King 626c9a2356fSRussell King return err; 627c9a2356fSRussell King } 628c9a2356fSRussell King 629c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, 630c9a2356fSRussell King unsigned int mode, 631c9a2356fSRussell King const struct phylink_link_state *state) 632c9a2356fSRussell King { 633c9a2356fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 63454186b91SAndrew Lunn int speed, duplex, link, pause, err; 635c9a2356fSRussell King 636d700ec41SMarek Vasut if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port)) 637c9a2356fSRussell King return; 638c9a2356fSRussell King 639c9a2356fSRussell King if (mode == MLO_AN_FIXED) { 640c9a2356fSRussell King link = LINK_FORCED_UP; 641c9a2356fSRussell King speed = state->speed; 642c9a2356fSRussell King duplex = state->duplex; 643d700ec41SMarek Vasut } else if (!mv88e6xxx_phy_is_internal(ds, port)) { 644d700ec41SMarek Vasut link = state->link; 645d700ec41SMarek Vasut speed = state->speed; 646d700ec41SMarek Vasut duplex = state->duplex; 647c9a2356fSRussell King } else { 648c9a2356fSRussell King speed = SPEED_UNFORCED; 649c9a2356fSRussell King duplex = DUPLEX_UNFORCED; 650c9a2356fSRussell King link = LINK_UNFORCED; 651c9a2356fSRussell King } 65254186b91SAndrew Lunn pause = !!phylink_test(state->advertising, Pause); 653c9a2356fSRussell King 654c9a2356fSRussell King mutex_lock(&chip->reg_lock); 65554186b91SAndrew Lunn err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, pause, 656c9a2356fSRussell King state->interface); 657c9a2356fSRussell King mutex_unlock(&chip->reg_lock); 658c9a2356fSRussell King 659c9a2356fSRussell King if (err && err != -EOPNOTSUPP) 660c9a2356fSRussell King dev_err(ds->dev, "p%d: failed to configure MAC\n", port); 661c9a2356fSRussell King } 662c9a2356fSRussell King 663c9a2356fSRussell King static void mv88e6xxx_mac_link_force(struct dsa_switch *ds, int port, int link) 664c9a2356fSRussell King { 665c9a2356fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 666c9a2356fSRussell King int err; 667c9a2356fSRussell King 668c9a2356fSRussell King mutex_lock(&chip->reg_lock); 669c9a2356fSRussell King err = chip->info->ops->port_set_link(chip, port, link); 670c9a2356fSRussell King mutex_unlock(&chip->reg_lock); 671c9a2356fSRussell King 672c9a2356fSRussell King if (err) 673c9a2356fSRussell King dev_err(chip->dev, "p%d: failed to force MAC link\n", port); 674c9a2356fSRussell King } 675c9a2356fSRussell King 676c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port, 677c9a2356fSRussell King unsigned int mode, 678c9a2356fSRussell King phy_interface_t interface) 679c9a2356fSRussell King { 680c9a2356fSRussell King if (mode == MLO_AN_FIXED) 681c9a2356fSRussell King mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_DOWN); 682c9a2356fSRussell King } 683c9a2356fSRussell King 684c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, 685c9a2356fSRussell King unsigned int mode, phy_interface_t interface, 686c9a2356fSRussell King struct phy_device *phydev) 687c9a2356fSRussell King { 688c9a2356fSRussell King if (mode == MLO_AN_FIXED) 689c9a2356fSRussell King mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_UP); 690c9a2356fSRussell King } 691c9a2356fSRussell King 692a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 693fad09c73SVivien Didelot { 694a605a0feSAndrew Lunn if (!chip->info->ops->stats_snapshot) 695a605a0feSAndrew Lunn return -EOPNOTSUPP; 696fad09c73SVivien Didelot 697a605a0feSAndrew Lunn return chip->info->ops->stats_snapshot(chip, port); 698fad09c73SVivien Didelot } 699fad09c73SVivien Didelot 700fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = { 701dfafe449SAndrew Lunn { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, }, 702dfafe449SAndrew Lunn { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, }, 703dfafe449SAndrew Lunn { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, }, 704dfafe449SAndrew Lunn { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, }, 705dfafe449SAndrew Lunn { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, }, 706dfafe449SAndrew Lunn { "in_pause", 4, 0x16, STATS_TYPE_BANK0, }, 707dfafe449SAndrew Lunn { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, }, 708dfafe449SAndrew Lunn { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, }, 709dfafe449SAndrew Lunn { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, }, 710dfafe449SAndrew Lunn { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, }, 711dfafe449SAndrew Lunn { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, }, 712dfafe449SAndrew Lunn { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, }, 713dfafe449SAndrew Lunn { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, }, 714dfafe449SAndrew Lunn { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, }, 715dfafe449SAndrew Lunn { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, }, 716dfafe449SAndrew Lunn { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, }, 717dfafe449SAndrew Lunn { "out_pause", 4, 0x15, STATS_TYPE_BANK0, }, 718dfafe449SAndrew Lunn { "excessive", 4, 0x11, STATS_TYPE_BANK0, }, 719dfafe449SAndrew Lunn { "collisions", 4, 0x1e, STATS_TYPE_BANK0, }, 720dfafe449SAndrew Lunn { "deferred", 4, 0x05, STATS_TYPE_BANK0, }, 721dfafe449SAndrew Lunn { "single", 4, 0x14, STATS_TYPE_BANK0, }, 722dfafe449SAndrew Lunn { "multiple", 4, 0x17, STATS_TYPE_BANK0, }, 723dfafe449SAndrew Lunn { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, }, 724dfafe449SAndrew Lunn { "late", 4, 0x1f, STATS_TYPE_BANK0, }, 725dfafe449SAndrew Lunn { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, }, 726dfafe449SAndrew Lunn { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, }, 727dfafe449SAndrew Lunn { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, }, 728dfafe449SAndrew Lunn { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, }, 729dfafe449SAndrew Lunn { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, }, 730dfafe449SAndrew Lunn { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, }, 731dfafe449SAndrew Lunn { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, }, 732dfafe449SAndrew Lunn { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, }, 733dfafe449SAndrew Lunn { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, }, 734dfafe449SAndrew Lunn { "in_discards", 4, 0x00, STATS_TYPE_BANK1, }, 735dfafe449SAndrew Lunn { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, }, 736dfafe449SAndrew Lunn { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, }, 737dfafe449SAndrew Lunn { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, }, 738dfafe449SAndrew Lunn { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, }, 739dfafe449SAndrew Lunn { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, }, 740dfafe449SAndrew Lunn { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, }, 741dfafe449SAndrew Lunn { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, }, 742dfafe449SAndrew Lunn { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, }, 743dfafe449SAndrew Lunn { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, }, 744dfafe449SAndrew Lunn { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, }, 745dfafe449SAndrew Lunn { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, }, 746dfafe449SAndrew Lunn { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, }, 747dfafe449SAndrew Lunn { "in_management", 4, 0x0f, STATS_TYPE_BANK1, }, 748dfafe449SAndrew Lunn { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, }, 749dfafe449SAndrew Lunn { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, }, 750dfafe449SAndrew Lunn { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, }, 751dfafe449SAndrew Lunn { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, }, 752dfafe449SAndrew Lunn { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, }, 753dfafe449SAndrew Lunn { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, }, 754dfafe449SAndrew Lunn { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, }, 755dfafe449SAndrew Lunn { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, }, 756dfafe449SAndrew Lunn { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, }, 757dfafe449SAndrew Lunn { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, }, 758dfafe449SAndrew Lunn { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, }, 759dfafe449SAndrew Lunn { "out_management", 4, 0x1f, STATS_TYPE_BANK1, }, 760fad09c73SVivien Didelot }; 761fad09c73SVivien Didelot 762fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, 763fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *s, 764e0d8b615SAndrew Lunn int port, u16 bank1_select, 765e0d8b615SAndrew Lunn u16 histogram) 766fad09c73SVivien Didelot { 767fad09c73SVivien Didelot u32 low; 768fad09c73SVivien Didelot u32 high = 0; 769dfafe449SAndrew Lunn u16 reg = 0; 7700e7b9925SAndrew Lunn int err; 771fad09c73SVivien Didelot u64 value; 772fad09c73SVivien Didelot 773fad09c73SVivien Didelot switch (s->type) { 774dfafe449SAndrew Lunn case STATS_TYPE_PORT: 7750e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg, ®); 7760e7b9925SAndrew Lunn if (err) 7776c3442f5SJisheng Zhang return U64_MAX; 778fad09c73SVivien Didelot 7790e7b9925SAndrew Lunn low = reg; 780cda9f4aaSAndrew Lunn if (s->size == 4) { 7810e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg + 1, ®); 7820e7b9925SAndrew Lunn if (err) 7836c3442f5SJisheng Zhang return U64_MAX; 78484b3fd1fSRasmus Villemoes low |= ((u32)reg) << 16; 785fad09c73SVivien Didelot } 786fad09c73SVivien Didelot break; 787dfafe449SAndrew Lunn case STATS_TYPE_BANK1: 788e0d8b615SAndrew Lunn reg = bank1_select; 789dfafe449SAndrew Lunn /* fall through */ 790dfafe449SAndrew Lunn case STATS_TYPE_BANK0: 791e0d8b615SAndrew Lunn reg |= s->reg | histogram; 7927f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg, &low); 793cda9f4aaSAndrew Lunn if (s->size == 8) 7947f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg + 1, &high); 7959fc3e4dcSGustavo A. R. Silva break; 7969fc3e4dcSGustavo A. R. Silva default: 7976c3442f5SJisheng Zhang return U64_MAX; 798fad09c73SVivien Didelot } 7996e46e2d8SAndrew Lunn value = (((u64)high) << 32) | low; 800fad09c73SVivien Didelot return value; 801fad09c73SVivien Didelot } 802fad09c73SVivien Didelot 803436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, 804dfafe449SAndrew Lunn uint8_t *data, int types) 805fad09c73SVivien Didelot { 806fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 807fad09c73SVivien Didelot int i, j; 808fad09c73SVivien Didelot 809fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 810fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 811dfafe449SAndrew Lunn if (stat->type & types) { 812fad09c73SVivien Didelot memcpy(data + j * ETH_GSTRING_LEN, stat->string, 813fad09c73SVivien Didelot ETH_GSTRING_LEN); 814fad09c73SVivien Didelot j++; 815fad09c73SVivien Didelot } 816fad09c73SVivien Didelot } 817436fe17dSAndrew Lunn 818436fe17dSAndrew Lunn return j; 819fad09c73SVivien Didelot } 820fad09c73SVivien Didelot 821436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, 822dfafe449SAndrew Lunn uint8_t *data) 823dfafe449SAndrew Lunn { 824436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 825dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT); 826dfafe449SAndrew Lunn } 827dfafe449SAndrew Lunn 8281f71836fSRasmus Villemoes static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip, 8291f71836fSRasmus Villemoes uint8_t *data) 8301f71836fSRasmus Villemoes { 8311f71836fSRasmus Villemoes return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0); 8321f71836fSRasmus Villemoes } 8331f71836fSRasmus Villemoes 834436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, 835dfafe449SAndrew Lunn uint8_t *data) 836dfafe449SAndrew Lunn { 837436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 838dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1); 839dfafe449SAndrew Lunn } 840dfafe449SAndrew Lunn 84165f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = { 84265f60e45SAndrew Lunn "atu_member_violation", 84365f60e45SAndrew Lunn "atu_miss_violation", 84465f60e45SAndrew Lunn "atu_full_violation", 84565f60e45SAndrew Lunn "vtu_member_violation", 84665f60e45SAndrew Lunn "vtu_miss_violation", 84765f60e45SAndrew Lunn }; 84865f60e45SAndrew Lunn 84965f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data) 85065f60e45SAndrew Lunn { 85165f60e45SAndrew Lunn unsigned int i; 85265f60e45SAndrew Lunn 85365f60e45SAndrew Lunn for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++) 85465f60e45SAndrew Lunn strlcpy(data + i * ETH_GSTRING_LEN, 85565f60e45SAndrew Lunn mv88e6xxx_atu_vtu_stats_strings[i], 85665f60e45SAndrew Lunn ETH_GSTRING_LEN); 85765f60e45SAndrew Lunn } 85865f60e45SAndrew Lunn 859dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, 86089f09048SFlorian Fainelli u32 stringset, uint8_t *data) 861fad09c73SVivien Didelot { 86204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 863436fe17dSAndrew Lunn int count = 0; 864dfafe449SAndrew Lunn 86589f09048SFlorian Fainelli if (stringset != ETH_SS_STATS) 86689f09048SFlorian Fainelli return; 86789f09048SFlorian Fainelli 868c6c8cd5eSAndrew Lunn mutex_lock(&chip->reg_lock); 869c6c8cd5eSAndrew Lunn 870dfafe449SAndrew Lunn if (chip->info->ops->stats_get_strings) 871436fe17dSAndrew Lunn count = chip->info->ops->stats_get_strings(chip, data); 872436fe17dSAndrew Lunn 873436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_strings) { 874436fe17dSAndrew Lunn data += count * ETH_GSTRING_LEN; 87565f60e45SAndrew Lunn count = chip->info->ops->serdes_get_strings(chip, port, data); 876436fe17dSAndrew Lunn } 877c6c8cd5eSAndrew Lunn 87865f60e45SAndrew Lunn data += count * ETH_GSTRING_LEN; 87965f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_strings(data); 88065f60e45SAndrew Lunn 881c6c8cd5eSAndrew Lunn mutex_unlock(&chip->reg_lock); 882dfafe449SAndrew Lunn } 883dfafe449SAndrew Lunn 884dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip, 885dfafe449SAndrew Lunn int types) 886dfafe449SAndrew Lunn { 887fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 888fad09c73SVivien Didelot int i, j; 889fad09c73SVivien Didelot 890fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 891fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 892dfafe449SAndrew Lunn if (stat->type & types) 893fad09c73SVivien Didelot j++; 894fad09c73SVivien Didelot } 895fad09c73SVivien Didelot return j; 896fad09c73SVivien Didelot } 897fad09c73SVivien Didelot 898dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip) 899dfafe449SAndrew Lunn { 900dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 901dfafe449SAndrew Lunn STATS_TYPE_PORT); 902dfafe449SAndrew Lunn } 903dfafe449SAndrew Lunn 9041f71836fSRasmus Villemoes static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip) 9051f71836fSRasmus Villemoes { 9061f71836fSRasmus Villemoes return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0); 9071f71836fSRasmus Villemoes } 9081f71836fSRasmus Villemoes 909dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip) 910dfafe449SAndrew Lunn { 911dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 912dfafe449SAndrew Lunn STATS_TYPE_BANK1); 913dfafe449SAndrew Lunn } 914dfafe449SAndrew Lunn 91589f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset) 916dfafe449SAndrew Lunn { 917dfafe449SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 918436fe17dSAndrew Lunn int serdes_count = 0; 919436fe17dSAndrew Lunn int count = 0; 920dfafe449SAndrew Lunn 92189f09048SFlorian Fainelli if (sset != ETH_SS_STATS) 92289f09048SFlorian Fainelli return 0; 92389f09048SFlorian Fainelli 924c6c8cd5eSAndrew Lunn mutex_lock(&chip->reg_lock); 925dfafe449SAndrew Lunn if (chip->info->ops->stats_get_sset_count) 926436fe17dSAndrew Lunn count = chip->info->ops->stats_get_sset_count(chip); 927436fe17dSAndrew Lunn if (count < 0) 928436fe17dSAndrew Lunn goto out; 929436fe17dSAndrew Lunn 930436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_sset_count) 931436fe17dSAndrew Lunn serdes_count = chip->info->ops->serdes_get_sset_count(chip, 932436fe17dSAndrew Lunn port); 93365f60e45SAndrew Lunn if (serdes_count < 0) { 934436fe17dSAndrew Lunn count = serdes_count; 93565f60e45SAndrew Lunn goto out; 93665f60e45SAndrew Lunn } 937436fe17dSAndrew Lunn count += serdes_count; 93865f60e45SAndrew Lunn count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); 93965f60e45SAndrew Lunn 940436fe17dSAndrew Lunn out: 941c6c8cd5eSAndrew Lunn mutex_unlock(&chip->reg_lock); 942dfafe449SAndrew Lunn 943436fe17dSAndrew Lunn return count; 944dfafe449SAndrew Lunn } 945dfafe449SAndrew Lunn 946436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 947e0d8b615SAndrew Lunn uint64_t *data, int types, 948e0d8b615SAndrew Lunn u16 bank1_select, u16 histogram) 949052f947fSAndrew Lunn { 950052f947fSAndrew Lunn struct mv88e6xxx_hw_stat *stat; 951052f947fSAndrew Lunn int i, j; 952052f947fSAndrew Lunn 953052f947fSAndrew Lunn for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 954052f947fSAndrew Lunn stat = &mv88e6xxx_hw_stats[i]; 955052f947fSAndrew Lunn if (stat->type & types) { 956377cda13SAndrew Lunn mutex_lock(&chip->reg_lock); 957e0d8b615SAndrew Lunn data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 958e0d8b615SAndrew Lunn bank1_select, 959e0d8b615SAndrew Lunn histogram); 960377cda13SAndrew Lunn mutex_unlock(&chip->reg_lock); 961377cda13SAndrew Lunn 962052f947fSAndrew Lunn j++; 963052f947fSAndrew Lunn } 964052f947fSAndrew Lunn } 965436fe17dSAndrew Lunn return j; 966052f947fSAndrew Lunn } 967052f947fSAndrew Lunn 968436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 969052f947fSAndrew Lunn uint64_t *data) 970052f947fSAndrew Lunn { 971052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 972e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT, 97357d1ef38SVivien Didelot 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 974052f947fSAndrew Lunn } 975052f947fSAndrew Lunn 9761f71836fSRasmus Villemoes static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 9771f71836fSRasmus Villemoes uint64_t *data) 9781f71836fSRasmus Villemoes { 9791f71836fSRasmus Villemoes return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0, 9801f71836fSRasmus Villemoes 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 9811f71836fSRasmus Villemoes } 9821f71836fSRasmus Villemoes 983436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 984052f947fSAndrew Lunn uint64_t *data) 985052f947fSAndrew Lunn { 986052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 987e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 98857d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9, 98957d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 990e0d8b615SAndrew Lunn } 991e0d8b615SAndrew Lunn 992436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 993e0d8b615SAndrew Lunn uint64_t *data) 994e0d8b615SAndrew Lunn { 995e0d8b615SAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 996e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 99757d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10, 99857d1ef38SVivien Didelot 0); 999052f947fSAndrew Lunn } 1000052f947fSAndrew Lunn 100165f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port, 100265f60e45SAndrew Lunn uint64_t *data) 100365f60e45SAndrew Lunn { 100465f60e45SAndrew Lunn *data++ = chip->ports[port].atu_member_violation; 100565f60e45SAndrew Lunn *data++ = chip->ports[port].atu_miss_violation; 100665f60e45SAndrew Lunn *data++ = chip->ports[port].atu_full_violation; 100765f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_member_violation; 100865f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_miss_violation; 100965f60e45SAndrew Lunn } 101065f60e45SAndrew Lunn 1011052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, 1012052f947fSAndrew Lunn uint64_t *data) 1013052f947fSAndrew Lunn { 1014436fe17dSAndrew Lunn int count = 0; 1015436fe17dSAndrew Lunn 1016052f947fSAndrew Lunn if (chip->info->ops->stats_get_stats) 1017436fe17dSAndrew Lunn count = chip->info->ops->stats_get_stats(chip, port, data); 1018436fe17dSAndrew Lunn 101965f60e45SAndrew Lunn mutex_lock(&chip->reg_lock); 1020436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_stats) { 1021436fe17dSAndrew Lunn data += count; 102265f60e45SAndrew Lunn count = chip->info->ops->serdes_get_stats(chip, port, data); 1023436fe17dSAndrew Lunn } 102465f60e45SAndrew Lunn data += count; 102565f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_stats(chip, port, data); 102665f60e45SAndrew Lunn mutex_unlock(&chip->reg_lock); 1027052f947fSAndrew Lunn } 1028052f947fSAndrew Lunn 1029fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, 1030fad09c73SVivien Didelot uint64_t *data) 1031fad09c73SVivien Didelot { 103204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1033fad09c73SVivien Didelot int ret; 1034fad09c73SVivien Didelot 1035fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1036fad09c73SVivien Didelot 1037a605a0feSAndrew Lunn ret = mv88e6xxx_stats_snapshot(chip, port); 1038fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1039377cda13SAndrew Lunn 1040377cda13SAndrew Lunn if (ret < 0) 1041fad09c73SVivien Didelot return; 1042052f947fSAndrew Lunn 1043052f947fSAndrew Lunn mv88e6xxx_get_stats(chip, port, data); 1044fad09c73SVivien Didelot 1045fad09c73SVivien Didelot } 1046fad09c73SVivien Didelot 1047fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) 1048fad09c73SVivien Didelot { 1049fad09c73SVivien Didelot return 32 * sizeof(u16); 1050fad09c73SVivien Didelot } 1051fad09c73SVivien Didelot 1052fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, 1053fad09c73SVivien Didelot struct ethtool_regs *regs, void *_p) 1054fad09c73SVivien Didelot { 105504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 10560e7b9925SAndrew Lunn int err; 10570e7b9925SAndrew Lunn u16 reg; 1058fad09c73SVivien Didelot u16 *p = _p; 1059fad09c73SVivien Didelot int i; 1060fad09c73SVivien Didelot 1061a5f39326SVivien Didelot regs->version = chip->info->prod_num; 1062fad09c73SVivien Didelot 1063fad09c73SVivien Didelot memset(p, 0xff, 32 * sizeof(u16)); 1064fad09c73SVivien Didelot 1065fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1066fad09c73SVivien Didelot 1067fad09c73SVivien Didelot for (i = 0; i < 32; i++) { 1068fad09c73SVivien Didelot 10690e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, i, ®); 10700e7b9925SAndrew Lunn if (!err) 10710e7b9925SAndrew Lunn p[i] = reg; 1072fad09c73SVivien Didelot } 1073fad09c73SVivien Didelot 1074fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1075fad09c73SVivien Didelot } 1076fad09c73SVivien Didelot 107708f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port, 1078fad09c73SVivien Didelot struct ethtool_eee *e) 1079fad09c73SVivien Didelot { 10805480db69SVivien Didelot /* Nothing to do on the port's MAC */ 10815480db69SVivien Didelot return 0; 1082fad09c73SVivien Didelot } 1083fad09c73SVivien Didelot 108408f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port, 108546587e4aSVivien Didelot struct ethtool_eee *e) 1086fad09c73SVivien Didelot { 10875480db69SVivien Didelot /* Nothing to do on the port's MAC */ 10885480db69SVivien Didelot return 0; 1089fad09c73SVivien Didelot } 1090fad09c73SVivien Didelot 1091e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port) 1092fad09c73SVivien Didelot { 1093e5887a2aSVivien Didelot struct dsa_switch *ds = NULL; 1094e5887a2aSVivien Didelot struct net_device *br; 1095e5887a2aSVivien Didelot u16 pvlan; 1096fad09c73SVivien Didelot int i; 1097fad09c73SVivien Didelot 1098e5887a2aSVivien Didelot if (dev < DSA_MAX_SWITCHES) 1099e5887a2aSVivien Didelot ds = chip->ds->dst->ds[dev]; 1100fad09c73SVivien Didelot 1101e5887a2aSVivien Didelot /* Prevent frames from unknown switch or port */ 1102e5887a2aSVivien Didelot if (!ds || port >= ds->num_ports) 1103e5887a2aSVivien Didelot return 0; 1104e5887a2aSVivien Didelot 1105e5887a2aSVivien Didelot /* Frames from DSA links and CPU ports can egress any local port */ 1106e5887a2aSVivien Didelot if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) 1107e5887a2aSVivien Didelot return mv88e6xxx_port_mask(chip); 1108e5887a2aSVivien Didelot 1109e5887a2aSVivien Didelot br = ds->ports[port].bridge_dev; 1110e5887a2aSVivien Didelot pvlan = 0; 1111e5887a2aSVivien Didelot 1112e5887a2aSVivien Didelot /* Frames from user ports can egress any local DSA links and CPU ports, 1113e5887a2aSVivien Didelot * as well as any local member of their bridge group. 1114e5887a2aSVivien Didelot */ 1115e5887a2aSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 1116e5887a2aSVivien Didelot if (dsa_is_cpu_port(chip->ds, i) || 1117e5887a2aSVivien Didelot dsa_is_dsa_port(chip->ds, i) || 1118c8652c83SVivien Didelot (br && dsa_to_port(chip->ds, i)->bridge_dev == br)) 1119e5887a2aSVivien Didelot pvlan |= BIT(i); 1120e5887a2aSVivien Didelot 1121e5887a2aSVivien Didelot return pvlan; 1122fad09c73SVivien Didelot } 1123e5887a2aSVivien Didelot 1124240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port) 1125e5887a2aSVivien Didelot { 1126e5887a2aSVivien Didelot u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port); 1127fad09c73SVivien Didelot 1128fad09c73SVivien Didelot /* prevent frames from going back out of the port they came in on */ 1129fad09c73SVivien Didelot output_ports &= ~BIT(port); 1130fad09c73SVivien Didelot 11315a7921f4SVivien Didelot return mv88e6xxx_port_set_vlan_map(chip, port, output_ports); 1132fad09c73SVivien Didelot } 1133fad09c73SVivien Didelot 1134fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, 1135fad09c73SVivien Didelot u8 state) 1136fad09c73SVivien Didelot { 113704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1138fad09c73SVivien Didelot int err; 1139fad09c73SVivien Didelot 1140fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1141f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, port, state); 1142fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1143fad09c73SVivien Didelot 1144fad09c73SVivien Didelot if (err) 1145774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to update state\n", port); 1146fad09c73SVivien Didelot } 1147fad09c73SVivien Didelot 114893e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip) 114993e18d61SVivien Didelot { 115093e18d61SVivien Didelot int err; 115193e18d61SVivien Didelot 115293e18d61SVivien Didelot if (chip->info->ops->ieee_pri_map) { 115393e18d61SVivien Didelot err = chip->info->ops->ieee_pri_map(chip); 115493e18d61SVivien Didelot if (err) 115593e18d61SVivien Didelot return err; 115693e18d61SVivien Didelot } 115793e18d61SVivien Didelot 115893e18d61SVivien Didelot if (chip->info->ops->ip_pri_map) { 115993e18d61SVivien Didelot err = chip->info->ops->ip_pri_map(chip); 116093e18d61SVivien Didelot if (err) 116193e18d61SVivien Didelot return err; 116293e18d61SVivien Didelot } 116393e18d61SVivien Didelot 116493e18d61SVivien Didelot return 0; 116593e18d61SVivien Didelot } 116693e18d61SVivien Didelot 1167c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) 1168c7f047b6SVivien Didelot { 1169c7f047b6SVivien Didelot int target, port; 1170c7f047b6SVivien Didelot int err; 1171c7f047b6SVivien Didelot 1172c7f047b6SVivien Didelot if (!chip->info->global2_addr) 1173c7f047b6SVivien Didelot return 0; 1174c7f047b6SVivien Didelot 1175c7f047b6SVivien Didelot /* Initialize the routing port to the 32 possible target devices */ 1176c7f047b6SVivien Didelot for (target = 0; target < 32; target++) { 1177c7f047b6SVivien Didelot port = 0x1f; 1178c7f047b6SVivien Didelot if (target < DSA_MAX_SWITCHES) 1179c7f047b6SVivien Didelot if (chip->ds->rtable[target] != DSA_RTABLE_NONE) 1180c7f047b6SVivien Didelot port = chip->ds->rtable[target]; 1181c7f047b6SVivien Didelot 1182c7f047b6SVivien Didelot err = mv88e6xxx_g2_device_mapping_write(chip, target, port); 1183c7f047b6SVivien Didelot if (err) 1184c7f047b6SVivien Didelot return err; 1185c7f047b6SVivien Didelot } 1186c7f047b6SVivien Didelot 118702317e68SVivien Didelot if (chip->info->ops->set_cascade_port) { 118802317e68SVivien Didelot port = MV88E6XXX_CASCADE_PORT_MULTIPLE; 118902317e68SVivien Didelot err = chip->info->ops->set_cascade_port(chip, port); 119002317e68SVivien Didelot if (err) 119102317e68SVivien Didelot return err; 119202317e68SVivien Didelot } 119302317e68SVivien Didelot 119423c98919SVivien Didelot err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index); 119523c98919SVivien Didelot if (err) 119623c98919SVivien Didelot return err; 119723c98919SVivien Didelot 1198c7f047b6SVivien Didelot return 0; 1199c7f047b6SVivien Didelot } 1200c7f047b6SVivien Didelot 1201b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip) 1202b28f872dSVivien Didelot { 1203b28f872dSVivien Didelot /* Clear all trunk masks and mapping */ 1204b28f872dSVivien Didelot if (chip->info->global2_addr) 1205b28f872dSVivien Didelot return mv88e6xxx_g2_trunk_clear(chip); 1206b28f872dSVivien Didelot 1207b28f872dSVivien Didelot return 0; 1208b28f872dSVivien Didelot } 1209b28f872dSVivien Didelot 12109e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip) 12119e5baf9bSVivien Didelot { 12129e5baf9bSVivien Didelot if (chip->info->ops->rmu_disable) 12139e5baf9bSVivien Didelot return chip->info->ops->rmu_disable(chip); 12149e5baf9bSVivien Didelot 12159e5baf9bSVivien Didelot return 0; 12169e5baf9bSVivien Didelot } 12179e5baf9bSVivien Didelot 12189e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip) 12199e907d73SVivien Didelot { 12209e907d73SVivien Didelot if (chip->info->ops->pot_clear) 12219e907d73SVivien Didelot return chip->info->ops->pot_clear(chip); 12229e907d73SVivien Didelot 12239e907d73SVivien Didelot return 0; 12249e907d73SVivien Didelot } 12259e907d73SVivien Didelot 122651c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip) 122751c901a7SVivien Didelot { 122851c901a7SVivien Didelot if (chip->info->ops->mgmt_rsvd2cpu) 122951c901a7SVivien Didelot return chip->info->ops->mgmt_rsvd2cpu(chip); 123051c901a7SVivien Didelot 123151c901a7SVivien Didelot return 0; 123251c901a7SVivien Didelot } 123351c901a7SVivien Didelot 1234a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) 1235a2ac29d2SVivien Didelot { 1236c3a7d4adSVivien Didelot int err; 1237c3a7d4adSVivien Didelot 1238daefc943SVivien Didelot err = mv88e6xxx_g1_atu_flush(chip, 0, true); 1239daefc943SVivien Didelot if (err) 1240daefc943SVivien Didelot return err; 1241daefc943SVivien Didelot 1242c3a7d4adSVivien Didelot err = mv88e6xxx_g1_atu_set_learn2all(chip, true); 1243c3a7d4adSVivien Didelot if (err) 1244c3a7d4adSVivien Didelot return err; 1245c3a7d4adSVivien Didelot 1246a2ac29d2SVivien Didelot return mv88e6xxx_g1_atu_set_age_time(chip, 300000); 1247a2ac29d2SVivien Didelot } 1248a2ac29d2SVivien Didelot 1249cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip) 1250cd8da8bbSVivien Didelot { 1251cd8da8bbSVivien Didelot int port; 1252cd8da8bbSVivien Didelot int err; 1253cd8da8bbSVivien Didelot 1254cd8da8bbSVivien Didelot if (!chip->info->ops->irl_init_all) 1255cd8da8bbSVivien Didelot return 0; 1256cd8da8bbSVivien Didelot 1257cd8da8bbSVivien Didelot for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 1258cd8da8bbSVivien Didelot /* Disable ingress rate limiting by resetting all per port 1259cd8da8bbSVivien Didelot * ingress rate limit resources to their initial state. 1260cd8da8bbSVivien Didelot */ 1261cd8da8bbSVivien Didelot err = chip->info->ops->irl_init_all(chip, port); 1262cd8da8bbSVivien Didelot if (err) 1263cd8da8bbSVivien Didelot return err; 1264cd8da8bbSVivien Didelot } 1265cd8da8bbSVivien Didelot 1266cd8da8bbSVivien Didelot return 0; 1267cd8da8bbSVivien Didelot } 1268cd8da8bbSVivien Didelot 126904a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip) 127004a69a17SVivien Didelot { 127104a69a17SVivien Didelot if (chip->info->ops->set_switch_mac) { 127204a69a17SVivien Didelot u8 addr[ETH_ALEN]; 127304a69a17SVivien Didelot 127404a69a17SVivien Didelot eth_random_addr(addr); 127504a69a17SVivien Didelot 127604a69a17SVivien Didelot return chip->info->ops->set_switch_mac(chip, addr); 127704a69a17SVivien Didelot } 127804a69a17SVivien Didelot 127904a69a17SVivien Didelot return 0; 128004a69a17SVivien Didelot } 128104a69a17SVivien Didelot 128217a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port) 128317a1594eSVivien Didelot { 128417a1594eSVivien Didelot u16 pvlan = 0; 128517a1594eSVivien Didelot 128617a1594eSVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 128717a1594eSVivien Didelot return -EOPNOTSUPP; 128817a1594eSVivien Didelot 128917a1594eSVivien Didelot /* Skip the local source device, which uses in-chip port VLAN */ 129017a1594eSVivien Didelot if (dev != chip->ds->index) 1291aec5ac88SVivien Didelot pvlan = mv88e6xxx_port_vlan(chip, dev, port); 129217a1594eSVivien Didelot 129317a1594eSVivien Didelot return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan); 129417a1594eSVivien Didelot } 129517a1594eSVivien Didelot 129681228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip) 129781228996SVivien Didelot { 129817a1594eSVivien Didelot int dev, port; 129917a1594eSVivien Didelot int err; 130017a1594eSVivien Didelot 130181228996SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 130281228996SVivien Didelot return 0; 130381228996SVivien Didelot 130481228996SVivien Didelot /* Clear 5 Bit Port for usage with Marvell Link Street devices: 130581228996SVivien Didelot * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev. 130681228996SVivien Didelot */ 130717a1594eSVivien Didelot err = mv88e6xxx_g2_misc_4_bit_port(chip); 130817a1594eSVivien Didelot if (err) 130917a1594eSVivien Didelot return err; 131017a1594eSVivien Didelot 131117a1594eSVivien Didelot for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) { 131217a1594eSVivien Didelot for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) { 131317a1594eSVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 131417a1594eSVivien Didelot if (err) 131517a1594eSVivien Didelot return err; 131617a1594eSVivien Didelot } 131717a1594eSVivien Didelot } 131817a1594eSVivien Didelot 131917a1594eSVivien Didelot return 0; 132081228996SVivien Didelot } 132181228996SVivien Didelot 1322749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port) 1323749efcb8SVivien Didelot { 1324749efcb8SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1325749efcb8SVivien Didelot int err; 1326749efcb8SVivien Didelot 1327749efcb8SVivien Didelot mutex_lock(&chip->reg_lock); 1328e606ca36SVivien Didelot err = mv88e6xxx_g1_atu_remove(chip, 0, port, false); 1329749efcb8SVivien Didelot mutex_unlock(&chip->reg_lock); 1330749efcb8SVivien Didelot 1331749efcb8SVivien Didelot if (err) 1332774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to flush ATU\n", port); 1333749efcb8SVivien Didelot } 1334749efcb8SVivien Didelot 1335b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip) 1336b486d7c9SVivien Didelot { 1337b486d7c9SVivien Didelot if (!chip->info->max_vid) 1338b486d7c9SVivien Didelot return 0; 1339b486d7c9SVivien Didelot 1340b486d7c9SVivien Didelot return mv88e6xxx_g1_vtu_flush(chip); 1341b486d7c9SVivien Didelot } 1342b486d7c9SVivien Didelot 1343f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip, 1344f1394b78SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 1345f1394b78SVivien Didelot { 1346f1394b78SVivien Didelot if (!chip->info->ops->vtu_getnext) 1347f1394b78SVivien Didelot return -EOPNOTSUPP; 1348f1394b78SVivien Didelot 1349f1394b78SVivien Didelot return chip->info->ops->vtu_getnext(chip, entry); 1350f1394b78SVivien Didelot } 1351f1394b78SVivien Didelot 13520ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, 13530ad5daf6SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 13540ad5daf6SVivien Didelot { 13550ad5daf6SVivien Didelot if (!chip->info->ops->vtu_loadpurge) 13560ad5daf6SVivien Didelot return -EOPNOTSUPP; 13570ad5daf6SVivien Didelot 13580ad5daf6SVivien Didelot return chip->info->ops->vtu_loadpurge(chip, entry); 13590ad5daf6SVivien Didelot } 13600ad5daf6SVivien Didelot 1361d7f435f9SVivien Didelot static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) 1362fad09c73SVivien Didelot { 1363fad09c73SVivien Didelot DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); 13643afb4bdeSVivien Didelot struct mv88e6xxx_vtu_entry vlan = { 13653afb4bdeSVivien Didelot .vid = chip->info->max_vid, 13663afb4bdeSVivien Didelot }; 1367fad09c73SVivien Didelot int i, err; 1368fad09c73SVivien Didelot 1369fad09c73SVivien Didelot bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); 1370fad09c73SVivien Didelot 1371fad09c73SVivien Didelot /* Set every FID bit used by the (un)bridged ports */ 1372370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1373b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, i, fid); 1374fad09c73SVivien Didelot if (err) 1375fad09c73SVivien Didelot return err; 1376fad09c73SVivien Didelot 1377fad09c73SVivien Didelot set_bit(*fid, fid_bitmap); 1378fad09c73SVivien Didelot } 1379fad09c73SVivien Didelot 1380fad09c73SVivien Didelot /* Set every FID bit used by the VLAN entries */ 1381fad09c73SVivien Didelot do { 1382f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1383fad09c73SVivien Didelot if (err) 1384fad09c73SVivien Didelot return err; 1385fad09c73SVivien Didelot 1386fad09c73SVivien Didelot if (!vlan.valid) 1387fad09c73SVivien Didelot break; 1388fad09c73SVivien Didelot 1389fad09c73SVivien Didelot set_bit(vlan.fid, fid_bitmap); 13903cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 1391fad09c73SVivien Didelot 1392fad09c73SVivien Didelot /* The reset value 0x000 is used to indicate that multiple address 1393fad09c73SVivien Didelot * databases are not needed. Return the next positive available. 1394fad09c73SVivien Didelot */ 1395fad09c73SVivien Didelot *fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1); 1396fad09c73SVivien Didelot if (unlikely(*fid >= mv88e6xxx_num_databases(chip))) 1397fad09c73SVivien Didelot return -ENOSPC; 1398fad09c73SVivien Didelot 1399fad09c73SVivien Didelot /* Clear the database */ 1400daefc943SVivien Didelot return mv88e6xxx_g1_atu_flush(chip, *fid, true); 1401fad09c73SVivien Didelot } 1402fad09c73SVivien Didelot 1403567aa59aSVivien Didelot static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid, 1404567aa59aSVivien Didelot struct mv88e6xxx_vtu_entry *entry, bool new) 1405fad09c73SVivien Didelot { 1406fad09c73SVivien Didelot int err; 1407fad09c73SVivien Didelot 1408fad09c73SVivien Didelot if (!vid) 140962394708SNikita Yushchenko return -EOPNOTSUPP; 1410fad09c73SVivien Didelot 14113afb4bdeSVivien Didelot entry->vid = vid - 1; 14123afb4bdeSVivien Didelot entry->valid = false; 1413fad09c73SVivien Didelot 1414f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, entry); 1415fad09c73SVivien Didelot if (err) 1416fad09c73SVivien Didelot return err; 1417fad09c73SVivien Didelot 1418567aa59aSVivien Didelot if (entry->vid == vid && entry->valid) 1419567aa59aSVivien Didelot return 0; 1420fad09c73SVivien Didelot 1421567aa59aSVivien Didelot if (new) { 1422567aa59aSVivien Didelot int i; 1423567aa59aSVivien Didelot 1424567aa59aSVivien Didelot /* Initialize a fresh VLAN entry */ 1425567aa59aSVivien Didelot memset(entry, 0, sizeof(*entry)); 1426567aa59aSVivien Didelot entry->valid = true; 1427567aa59aSVivien Didelot entry->vid = vid; 1428567aa59aSVivien Didelot 1429553a768dSVivien Didelot /* Exclude all ports */ 1430567aa59aSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 1431553a768dSVivien Didelot entry->member[i] = 14327ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 1433567aa59aSVivien Didelot 1434567aa59aSVivien Didelot return mv88e6xxx_atu_new(chip, &entry->fid); 1435fad09c73SVivien Didelot } 1436fad09c73SVivien Didelot 1437567aa59aSVivien Didelot /* switchdev expects -EOPNOTSUPP to honor software VLANs */ 1438567aa59aSVivien Didelot return -EOPNOTSUPP; 1439fad09c73SVivien Didelot } 1440fad09c73SVivien Didelot 1441fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, 1442fad09c73SVivien Didelot u16 vid_begin, u16 vid_end) 1443fad09c73SVivien Didelot { 144404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 14453afb4bdeSVivien Didelot struct mv88e6xxx_vtu_entry vlan = { 14463afb4bdeSVivien Didelot .vid = vid_begin - 1, 14473afb4bdeSVivien Didelot }; 1448fad09c73SVivien Didelot int i, err; 1449fad09c73SVivien Didelot 1450db06ae41SAndrew Lunn /* DSA and CPU ports have to be members of multiple vlans */ 1451db06ae41SAndrew Lunn if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 1452db06ae41SAndrew Lunn return 0; 1453db06ae41SAndrew Lunn 1454fad09c73SVivien Didelot if (!vid_begin) 1455fad09c73SVivien Didelot return -EOPNOTSUPP; 1456fad09c73SVivien Didelot 1457fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1458fad09c73SVivien Didelot 1459fad09c73SVivien Didelot do { 1460f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1461fad09c73SVivien Didelot if (err) 1462fad09c73SVivien Didelot goto unlock; 1463fad09c73SVivien Didelot 1464fad09c73SVivien Didelot if (!vlan.valid) 1465fad09c73SVivien Didelot break; 1466fad09c73SVivien Didelot 1467fad09c73SVivien Didelot if (vlan.vid > vid_end) 1468fad09c73SVivien Didelot break; 1469fad09c73SVivien Didelot 1470370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1471fad09c73SVivien Didelot if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i)) 1472fad09c73SVivien Didelot continue; 1473fad09c73SVivien Didelot 1474cd886469SAndrew Lunn if (!ds->ports[i].slave) 147566e2809dSAndrew Lunn continue; 147666e2809dSAndrew Lunn 1477bd00e053SVivien Didelot if (vlan.member[i] == 14787ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1479fad09c73SVivien Didelot continue; 1480fad09c73SVivien Didelot 1481c8652c83SVivien Didelot if (dsa_to_port(ds, i)->bridge_dev == 1482fae8a25eSVivien Didelot ds->ports[port].bridge_dev) 1483fad09c73SVivien Didelot break; /* same bridge, check next VLAN */ 1484fad09c73SVivien Didelot 1485c8652c83SVivien Didelot if (!dsa_to_port(ds, i)->bridge_dev) 148666e2809dSAndrew Lunn continue; 148766e2809dSAndrew Lunn 1488743fcc28SAndrew Lunn dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n", 1489743fcc28SAndrew Lunn port, vlan.vid, i, 1490c8652c83SVivien Didelot netdev_name(dsa_to_port(ds, i)->bridge_dev)); 1491fad09c73SVivien Didelot err = -EOPNOTSUPP; 1492fad09c73SVivien Didelot goto unlock; 1493fad09c73SVivien Didelot } 1494fad09c73SVivien Didelot } while (vlan.vid < vid_end); 1495fad09c73SVivien Didelot 1496fad09c73SVivien Didelot unlock: 1497fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1498fad09c73SVivien Didelot 1499fad09c73SVivien Didelot return err; 1500fad09c73SVivien Didelot } 1501fad09c73SVivien Didelot 1502fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, 1503fad09c73SVivien Didelot bool vlan_filtering) 1504fad09c73SVivien Didelot { 150504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 150681c6edb2SVivien Didelot u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE : 150781c6edb2SVivien Didelot MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED; 15080e7b9925SAndrew Lunn int err; 1509fad09c73SVivien Didelot 15103cf3c846SVivien Didelot if (!chip->info->max_vid) 1511fad09c73SVivien Didelot return -EOPNOTSUPP; 1512fad09c73SVivien Didelot 1513fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1514385a0995SVivien Didelot err = mv88e6xxx_port_set_8021q_mode(chip, port, mode); 1515fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1516fad09c73SVivien Didelot 15170e7b9925SAndrew Lunn return err; 1518fad09c73SVivien Didelot } 1519fad09c73SVivien Didelot 1520fad09c73SVivien Didelot static int 1521fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, 152280e02360SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1523fad09c73SVivien Didelot { 152404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1525fad09c73SVivien Didelot int err; 1526fad09c73SVivien Didelot 15273cf3c846SVivien Didelot if (!chip->info->max_vid) 1528fad09c73SVivien Didelot return -EOPNOTSUPP; 1529fad09c73SVivien Didelot 1530fad09c73SVivien Didelot /* If the requested port doesn't belong to the same bridge as the VLAN 1531fad09c73SVivien Didelot * members, do not support it (yet) and fallback to software VLAN. 1532fad09c73SVivien Didelot */ 1533fad09c73SVivien Didelot err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin, 1534fad09c73SVivien Didelot vlan->vid_end); 1535fad09c73SVivien Didelot if (err) 1536fad09c73SVivien Didelot return err; 1537fad09c73SVivien Didelot 1538fad09c73SVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 1539fad09c73SVivien Didelot * so skip the prepare phase. 1540fad09c73SVivien Didelot */ 1541fad09c73SVivien Didelot return 0; 1542fad09c73SVivien Didelot } 1543fad09c73SVivien Didelot 1544a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, 1545a4c93ae1SAndrew Lunn const unsigned char *addr, u16 vid, 1546a4c93ae1SAndrew Lunn u8 state) 1547a4c93ae1SAndrew Lunn { 1548a4c93ae1SAndrew Lunn struct mv88e6xxx_vtu_entry vlan; 1549a4c93ae1SAndrew Lunn struct mv88e6xxx_atu_entry entry; 1550a4c93ae1SAndrew Lunn int err; 1551a4c93ae1SAndrew Lunn 1552a4c93ae1SAndrew Lunn /* Null VLAN ID corresponds to the port private database */ 1553a4c93ae1SAndrew Lunn if (vid == 0) 1554a4c93ae1SAndrew Lunn err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid); 1555a4c93ae1SAndrew Lunn else 1556a4c93ae1SAndrew Lunn err = mv88e6xxx_vtu_get(chip, vid, &vlan, false); 1557a4c93ae1SAndrew Lunn if (err) 1558a4c93ae1SAndrew Lunn return err; 1559a4c93ae1SAndrew Lunn 1560a4c93ae1SAndrew Lunn entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED; 1561a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 1562a4c93ae1SAndrew Lunn eth_addr_dec(entry.mac); 1563a4c93ae1SAndrew Lunn 1564a4c93ae1SAndrew Lunn err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry); 1565a4c93ae1SAndrew Lunn if (err) 1566a4c93ae1SAndrew Lunn return err; 1567a4c93ae1SAndrew Lunn 1568a4c93ae1SAndrew Lunn /* Initialize a fresh ATU entry if it isn't found */ 1569a4c93ae1SAndrew Lunn if (entry.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED || 1570a4c93ae1SAndrew Lunn !ether_addr_equal(entry.mac, addr)) { 1571a4c93ae1SAndrew Lunn memset(&entry, 0, sizeof(entry)); 1572a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 1573a4c93ae1SAndrew Lunn } 1574a4c93ae1SAndrew Lunn 1575a4c93ae1SAndrew Lunn /* Purge the ATU entry only if no port is using it anymore */ 1576a4c93ae1SAndrew Lunn if (state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) { 1577a4c93ae1SAndrew Lunn entry.portvec &= ~BIT(port); 1578a4c93ae1SAndrew Lunn if (!entry.portvec) 1579a4c93ae1SAndrew Lunn entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED; 1580a4c93ae1SAndrew Lunn } else { 1581a4c93ae1SAndrew Lunn entry.portvec |= BIT(port); 1582a4c93ae1SAndrew Lunn entry.state = state; 1583a4c93ae1SAndrew Lunn } 1584a4c93ae1SAndrew Lunn 1585a4c93ae1SAndrew Lunn return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry); 1586a4c93ae1SAndrew Lunn } 1587a4c93ae1SAndrew Lunn 158887fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port, 158987fa886eSAndrew Lunn u16 vid) 159087fa886eSAndrew Lunn { 159187fa886eSAndrew Lunn const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 159287fa886eSAndrew Lunn u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC; 159387fa886eSAndrew Lunn 159487fa886eSAndrew Lunn return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state); 159587fa886eSAndrew Lunn } 159687fa886eSAndrew Lunn 159787fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid) 159887fa886eSAndrew Lunn { 159987fa886eSAndrew Lunn int port; 160087fa886eSAndrew Lunn int err; 160187fa886eSAndrew Lunn 160287fa886eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 160387fa886eSAndrew Lunn err = mv88e6xxx_port_add_broadcast(chip, port, vid); 160487fa886eSAndrew Lunn if (err) 160587fa886eSAndrew Lunn return err; 160687fa886eSAndrew Lunn } 160787fa886eSAndrew Lunn 160887fa886eSAndrew Lunn return 0; 160987fa886eSAndrew Lunn } 161087fa886eSAndrew Lunn 1611fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port, 1612c91498e1SVivien Didelot u16 vid, u8 member) 1613fad09c73SVivien Didelot { 1614b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1615fad09c73SVivien Didelot int err; 1616fad09c73SVivien Didelot 1617567aa59aSVivien Didelot err = mv88e6xxx_vtu_get(chip, vid, &vlan, true); 1618fad09c73SVivien Didelot if (err) 1619fad09c73SVivien Didelot return err; 1620fad09c73SVivien Didelot 1621c91498e1SVivien Didelot vlan.member[port] = member; 1622fad09c73SVivien Didelot 162387fa886eSAndrew Lunn err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 162487fa886eSAndrew Lunn if (err) 162587fa886eSAndrew Lunn return err; 162687fa886eSAndrew Lunn 162787fa886eSAndrew Lunn return mv88e6xxx_broadcast_setup(chip, vid); 1628fad09c73SVivien Didelot } 1629fad09c73SVivien Didelot 1630fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, 163180e02360SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1632fad09c73SVivien Didelot { 163304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1634fad09c73SVivien Didelot bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; 1635fad09c73SVivien Didelot bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 1636c91498e1SVivien Didelot u8 member; 1637fad09c73SVivien Didelot u16 vid; 1638fad09c73SVivien Didelot 16393cf3c846SVivien Didelot if (!chip->info->max_vid) 1640fad09c73SVivien Didelot return; 1641fad09c73SVivien Didelot 1642c91498e1SVivien Didelot if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 16437ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED; 1644c91498e1SVivien Didelot else if (untagged) 16457ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED; 1646c91498e1SVivien Didelot else 16477ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED; 1648c91498e1SVivien Didelot 1649fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1650fad09c73SVivien Didelot 1651fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) 1652c91498e1SVivien Didelot if (_mv88e6xxx_port_vlan_add(chip, port, vid, member)) 1653774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port, 1654fad09c73SVivien Didelot vid, untagged ? 'u' : 't'); 1655fad09c73SVivien Didelot 165677064f37SVivien Didelot if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end)) 1657774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to set PVID %d\n", port, 1658fad09c73SVivien Didelot vlan->vid_end); 1659fad09c73SVivien Didelot 1660fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1661fad09c73SVivien Didelot } 1662fad09c73SVivien Didelot 1663fad09c73SVivien Didelot static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip, 1664fad09c73SVivien Didelot int port, u16 vid) 1665fad09c73SVivien Didelot { 1666b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1667fad09c73SVivien Didelot int i, err; 1668fad09c73SVivien Didelot 1669567aa59aSVivien Didelot err = mv88e6xxx_vtu_get(chip, vid, &vlan, false); 1670fad09c73SVivien Didelot if (err) 1671fad09c73SVivien Didelot return err; 1672fad09c73SVivien Didelot 1673fad09c73SVivien Didelot /* Tell switchdev if this VLAN is handled in software */ 16747ec60d6eSVivien Didelot if (vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1675fad09c73SVivien Didelot return -EOPNOTSUPP; 1676fad09c73SVivien Didelot 16777ec60d6eSVivien Didelot vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 1678fad09c73SVivien Didelot 1679fad09c73SVivien Didelot /* keep the VLAN unless all ports are excluded */ 1680fad09c73SVivien Didelot vlan.valid = false; 1681370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 16827ec60d6eSVivien Didelot if (vlan.member[i] != 16837ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) { 1684fad09c73SVivien Didelot vlan.valid = true; 1685fad09c73SVivien Didelot break; 1686fad09c73SVivien Didelot } 1687fad09c73SVivien Didelot } 1688fad09c73SVivien Didelot 16890ad5daf6SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 1690fad09c73SVivien Didelot if (err) 1691fad09c73SVivien Didelot return err; 1692fad09c73SVivien Didelot 1693e606ca36SVivien Didelot return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); 1694fad09c73SVivien Didelot } 1695fad09c73SVivien Didelot 1696fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, 1697fad09c73SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1698fad09c73SVivien Didelot { 169904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1700fad09c73SVivien Didelot u16 pvid, vid; 1701fad09c73SVivien Didelot int err = 0; 1702fad09c73SVivien Didelot 17033cf3c846SVivien Didelot if (!chip->info->max_vid) 1704fad09c73SVivien Didelot return -EOPNOTSUPP; 1705fad09c73SVivien Didelot 1706fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1707fad09c73SVivien Didelot 170877064f37SVivien Didelot err = mv88e6xxx_port_get_pvid(chip, port, &pvid); 1709fad09c73SVivien Didelot if (err) 1710fad09c73SVivien Didelot goto unlock; 1711fad09c73SVivien Didelot 1712fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { 1713fad09c73SVivien Didelot err = _mv88e6xxx_port_vlan_del(chip, port, vid); 1714fad09c73SVivien Didelot if (err) 1715fad09c73SVivien Didelot goto unlock; 1716fad09c73SVivien Didelot 1717fad09c73SVivien Didelot if (vid == pvid) { 171877064f37SVivien Didelot err = mv88e6xxx_port_set_pvid(chip, port, 0); 1719fad09c73SVivien Didelot if (err) 1720fad09c73SVivien Didelot goto unlock; 1721fad09c73SVivien Didelot } 1722fad09c73SVivien Didelot } 1723fad09c73SVivien Didelot 1724fad09c73SVivien Didelot unlock: 1725fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1726fad09c73SVivien Didelot 1727fad09c73SVivien Didelot return err; 1728fad09c73SVivien Didelot } 1729fad09c73SVivien Didelot 17301b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, 17316c2c1dcbSArkadi Sharshevsky const unsigned char *addr, u16 vid) 1732fad09c73SVivien Didelot { 173304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 17341b6dd556SArkadi Sharshevsky int err; 1735fad09c73SVivien Didelot 1736fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 17371b6dd556SArkadi Sharshevsky err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 17381b6dd556SArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 1739fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 17401b6dd556SArkadi Sharshevsky 17411b6dd556SArkadi Sharshevsky return err; 1742fad09c73SVivien Didelot } 1743fad09c73SVivien Didelot 1744fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, 17456c2c1dcbSArkadi Sharshevsky const unsigned char *addr, u16 vid) 1746fad09c73SVivien Didelot { 174704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 174883dabd1fSVivien Didelot int err; 1749fad09c73SVivien Didelot 1750fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 17516c2c1dcbSArkadi Sharshevsky err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 175227c0e600SVivien Didelot MV88E6XXX_G1_ATU_DATA_STATE_UNUSED); 1753fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1754fad09c73SVivien Didelot 175583dabd1fSVivien Didelot return err; 1756fad09c73SVivien Didelot } 1757fad09c73SVivien Didelot 175883dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, 1759fad09c73SVivien Didelot u16 fid, u16 vid, int port, 17602bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 1761fad09c73SVivien Didelot { 1762dabc1a96SVivien Didelot struct mv88e6xxx_atu_entry addr; 17632bedde1aSArkadi Sharshevsky bool is_static; 1764fad09c73SVivien Didelot int err; 1765fad09c73SVivien Didelot 176627c0e600SVivien Didelot addr.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED; 1767dabc1a96SVivien Didelot eth_broadcast_addr(addr.mac); 1768fad09c73SVivien Didelot 1769fad09c73SVivien Didelot do { 1770dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); 1771fad09c73SVivien Didelot if (err) 177283dabd1fSVivien Didelot return err; 1773fad09c73SVivien Didelot 177427c0e600SVivien Didelot if (addr.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) 1775fad09c73SVivien Didelot break; 1776fad09c73SVivien Didelot 177701bd96c8SVivien Didelot if (addr.trunk || (addr.portvec & BIT(port)) == 0) 177883dabd1fSVivien Didelot continue; 1779fad09c73SVivien Didelot 178083dabd1fSVivien Didelot if (!is_unicast_ether_addr(addr.mac)) 178183dabd1fSVivien Didelot continue; 178283dabd1fSVivien Didelot 17832bedde1aSArkadi Sharshevsky is_static = (addr.state == 17842bedde1aSArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 17852bedde1aSArkadi Sharshevsky err = cb(addr.mac, vid, is_static, data); 178683dabd1fSVivien Didelot if (err) 178783dabd1fSVivien Didelot return err; 1788fad09c73SVivien Didelot } while (!is_broadcast_ether_addr(addr.mac)); 1789fad09c73SVivien Didelot 1790fad09c73SVivien Didelot return err; 1791fad09c73SVivien Didelot } 1792fad09c73SVivien Didelot 179383dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, 17942bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 179583dabd1fSVivien Didelot { 1796b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan = { 17973cf3c846SVivien Didelot .vid = chip->info->max_vid, 179883dabd1fSVivien Didelot }; 179983dabd1fSVivien Didelot u16 fid; 180083dabd1fSVivien Didelot int err; 180183dabd1fSVivien Didelot 180283dabd1fSVivien Didelot /* Dump port's default Filtering Information Database (VLAN ID 0) */ 1803b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &fid); 180483dabd1fSVivien Didelot if (err) 180583dabd1fSVivien Didelot return err; 180683dabd1fSVivien Didelot 18072bedde1aSArkadi Sharshevsky err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data); 180883dabd1fSVivien Didelot if (err) 180983dabd1fSVivien Didelot return err; 181083dabd1fSVivien Didelot 181183dabd1fSVivien Didelot /* Dump VLANs' Filtering Information Databases */ 181283dabd1fSVivien Didelot do { 1813f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 181483dabd1fSVivien Didelot if (err) 181583dabd1fSVivien Didelot return err; 181683dabd1fSVivien Didelot 181783dabd1fSVivien Didelot if (!vlan.valid) 181883dabd1fSVivien Didelot break; 181983dabd1fSVivien Didelot 182083dabd1fSVivien Didelot err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port, 18212bedde1aSArkadi Sharshevsky cb, data); 182283dabd1fSVivien Didelot if (err) 182383dabd1fSVivien Didelot return err; 18243cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 182583dabd1fSVivien Didelot 182683dabd1fSVivien Didelot return err; 182783dabd1fSVivien Didelot } 182883dabd1fSVivien Didelot 1829fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, 18302bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 1831fad09c73SVivien Didelot { 183204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1833fcf15367SVivien Didelot int err; 1834fad09c73SVivien Didelot 1835fcf15367SVivien Didelot mutex_lock(&chip->reg_lock); 1836fcf15367SVivien Didelot err = mv88e6xxx_port_db_dump(chip, port, cb, data); 1837fcf15367SVivien Didelot mutex_unlock(&chip->reg_lock); 1838fcf15367SVivien Didelot 1839fcf15367SVivien Didelot return err; 1840fad09c73SVivien Didelot } 1841fad09c73SVivien Didelot 1842240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, 1843240ea3efSVivien Didelot struct net_device *br) 1844240ea3efSVivien Didelot { 1845e96a6e02SVivien Didelot struct dsa_switch *ds; 1846240ea3efSVivien Didelot int port; 1847e96a6e02SVivien Didelot int dev; 1848240ea3efSVivien Didelot int err; 1849240ea3efSVivien Didelot 1850240ea3efSVivien Didelot /* Remap the Port VLAN of each local bridge group member */ 1851240ea3efSVivien Didelot for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) { 1852240ea3efSVivien Didelot if (chip->ds->ports[port].bridge_dev == br) { 1853240ea3efSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, port); 1854240ea3efSVivien Didelot if (err) 1855240ea3efSVivien Didelot return err; 1856240ea3efSVivien Didelot } 1857240ea3efSVivien Didelot } 1858240ea3efSVivien Didelot 1859e96a6e02SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1860e96a6e02SVivien Didelot return 0; 1861e96a6e02SVivien Didelot 1862e96a6e02SVivien Didelot /* Remap the Port VLAN of each cross-chip bridge group member */ 1863e96a6e02SVivien Didelot for (dev = 0; dev < DSA_MAX_SWITCHES; ++dev) { 1864e96a6e02SVivien Didelot ds = chip->ds->dst->ds[dev]; 1865e96a6e02SVivien Didelot if (!ds) 1866e96a6e02SVivien Didelot break; 1867e96a6e02SVivien Didelot 1868e96a6e02SVivien Didelot for (port = 0; port < ds->num_ports; ++port) { 1869e96a6e02SVivien Didelot if (ds->ports[port].bridge_dev == br) { 1870e96a6e02SVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 1871e96a6e02SVivien Didelot if (err) 1872e96a6e02SVivien Didelot return err; 1873e96a6e02SVivien Didelot } 1874e96a6e02SVivien Didelot } 1875e96a6e02SVivien Didelot } 1876e96a6e02SVivien Didelot 1877240ea3efSVivien Didelot return 0; 1878240ea3efSVivien Didelot } 1879240ea3efSVivien Didelot 1880fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, 1881fae8a25eSVivien Didelot struct net_device *br) 1882fad09c73SVivien Didelot { 188304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1884240ea3efSVivien Didelot int err; 1885fad09c73SVivien Didelot 1886fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1887240ea3efSVivien Didelot err = mv88e6xxx_bridge_map(chip, br); 1888fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1889fad09c73SVivien Didelot 1890fad09c73SVivien Didelot return err; 1891fad09c73SVivien Didelot } 1892fad09c73SVivien Didelot 1893f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, 1894f123f2fbSVivien Didelot struct net_device *br) 1895fad09c73SVivien Didelot { 189604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1897fad09c73SVivien Didelot 1898fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 1899240ea3efSVivien Didelot if (mv88e6xxx_bridge_map(chip, br) || 1900240ea3efSVivien Didelot mv88e6xxx_port_vlan_map(chip, port)) 1901240ea3efSVivien Didelot dev_err(ds->dev, "failed to remap in-chip Port VLAN\n"); 1902fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 1903fad09c73SVivien Didelot } 1904fad09c73SVivien Didelot 1905aec5ac88SVivien Didelot static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev, 1906aec5ac88SVivien Didelot int port, struct net_device *br) 1907aec5ac88SVivien Didelot { 1908aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1909aec5ac88SVivien Didelot int err; 1910aec5ac88SVivien Didelot 1911aec5ac88SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1912aec5ac88SVivien Didelot return 0; 1913aec5ac88SVivien Didelot 1914aec5ac88SVivien Didelot mutex_lock(&chip->reg_lock); 1915aec5ac88SVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 1916aec5ac88SVivien Didelot mutex_unlock(&chip->reg_lock); 1917aec5ac88SVivien Didelot 1918aec5ac88SVivien Didelot return err; 1919aec5ac88SVivien Didelot } 1920aec5ac88SVivien Didelot 1921aec5ac88SVivien Didelot static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev, 1922aec5ac88SVivien Didelot int port, struct net_device *br) 1923aec5ac88SVivien Didelot { 1924aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1925aec5ac88SVivien Didelot 1926aec5ac88SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1927aec5ac88SVivien Didelot return; 1928aec5ac88SVivien Didelot 1929aec5ac88SVivien Didelot mutex_lock(&chip->reg_lock); 1930aec5ac88SVivien Didelot if (mv88e6xxx_pvt_map(chip, dev, port)) 1931aec5ac88SVivien Didelot dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); 1932aec5ac88SVivien Didelot mutex_unlock(&chip->reg_lock); 1933aec5ac88SVivien Didelot } 1934aec5ac88SVivien Didelot 193517e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip) 193617e708baSVivien Didelot { 193717e708baSVivien Didelot if (chip->info->ops->reset) 193817e708baSVivien Didelot return chip->info->ops->reset(chip); 193917e708baSVivien Didelot 194017e708baSVivien Didelot return 0; 194117e708baSVivien Didelot } 194217e708baSVivien Didelot 1943309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) 1944309eca6dSVivien Didelot { 1945309eca6dSVivien Didelot struct gpio_desc *gpiod = chip->reset; 1946309eca6dSVivien Didelot 1947309eca6dSVivien Didelot /* If there is a GPIO connected to the reset pin, toggle it */ 1948309eca6dSVivien Didelot if (gpiod) { 1949309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 1); 1950309eca6dSVivien Didelot usleep_range(10000, 20000); 1951309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 0); 1952309eca6dSVivien Didelot usleep_range(10000, 20000); 1953309eca6dSVivien Didelot } 1954309eca6dSVivien Didelot } 1955309eca6dSVivien Didelot 19564ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip) 19574ac4b5a6SVivien Didelot { 19584ac4b5a6SVivien Didelot int i, err; 19594ac4b5a6SVivien Didelot 19604ac4b5a6SVivien Didelot /* Set all ports to the Disabled state */ 19614ac4b5a6SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 1962f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED); 19634ac4b5a6SVivien Didelot if (err) 19644ac4b5a6SVivien Didelot return err; 19654ac4b5a6SVivien Didelot } 19664ac4b5a6SVivien Didelot 19674ac4b5a6SVivien Didelot /* Wait for transmit queues to drain, 19684ac4b5a6SVivien Didelot * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps. 19694ac4b5a6SVivien Didelot */ 19704ac4b5a6SVivien Didelot usleep_range(2000, 4000); 19714ac4b5a6SVivien Didelot 19724ac4b5a6SVivien Didelot return 0; 19734ac4b5a6SVivien Didelot } 19744ac4b5a6SVivien Didelot 1975fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip) 1976fad09c73SVivien Didelot { 1977a935c052SVivien Didelot int err; 1978fad09c73SVivien Didelot 19794ac4b5a6SVivien Didelot err = mv88e6xxx_disable_ports(chip); 19800e7b9925SAndrew Lunn if (err) 19810e7b9925SAndrew Lunn return err; 1982fad09c73SVivien Didelot 1983309eca6dSVivien Didelot mv88e6xxx_hardware_reset(chip); 1984fad09c73SVivien Didelot 198517e708baSVivien Didelot return mv88e6xxx_software_reset(chip); 1986fad09c73SVivien Didelot } 1987fad09c73SVivien Didelot 19884314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, 198931bef4e9SVivien Didelot enum mv88e6xxx_frame_mode frame, 199031bef4e9SVivien Didelot enum mv88e6xxx_egress_mode egress, u16 etype) 199156995cbcSAndrew Lunn { 199256995cbcSAndrew Lunn int err; 199356995cbcSAndrew Lunn 19944314557cSVivien Didelot if (!chip->info->ops->port_set_frame_mode) 19954314557cSVivien Didelot return -EOPNOTSUPP; 19964314557cSVivien Didelot 19974314557cSVivien Didelot err = mv88e6xxx_port_set_egress_mode(chip, port, egress); 199856995cbcSAndrew Lunn if (err) 199956995cbcSAndrew Lunn return err; 200056995cbcSAndrew Lunn 20014314557cSVivien Didelot err = chip->info->ops->port_set_frame_mode(chip, port, frame); 20024314557cSVivien Didelot if (err) 20034314557cSVivien Didelot return err; 20044314557cSVivien Didelot 20054314557cSVivien Didelot if (chip->info->ops->port_set_ether_type) 20064314557cSVivien Didelot return chip->info->ops->port_set_ether_type(chip, port, etype); 20074314557cSVivien Didelot 20084314557cSVivien Didelot return 0; 20094314557cSVivien Didelot } 20104314557cSVivien Didelot 20114314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port) 20124314557cSVivien Didelot { 20134314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL, 201431bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 2015b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 20164314557cSVivien Didelot } 20174314557cSVivien Didelot 20184314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port) 20194314557cSVivien Didelot { 20204314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA, 202131bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 2022b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 20234314557cSVivien Didelot } 20244314557cSVivien Didelot 20254314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port) 20264314557cSVivien Didelot { 20274314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, 20284314557cSVivien Didelot MV88E6XXX_FRAME_MODE_ETHERTYPE, 202931bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_ETHERTYPE, 203031bef4e9SVivien Didelot ETH_P_EDSA); 20314314557cSVivien Didelot } 20324314557cSVivien Didelot 20334314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port) 20344314557cSVivien Didelot { 20354314557cSVivien Didelot if (dsa_is_dsa_port(chip->ds, port)) 20364314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 20374314557cSVivien Didelot 20382b3e9891SVivien Didelot if (dsa_is_user_port(chip->ds, port)) 20394314557cSVivien Didelot return mv88e6xxx_set_port_mode_normal(chip, port); 20404314557cSVivien Didelot 20414314557cSVivien Didelot /* Setup CPU port mode depending on its supported tag format */ 20424314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA) 20434314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 20444314557cSVivien Didelot 20454314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA) 20464314557cSVivien Didelot return mv88e6xxx_set_port_mode_edsa(chip, port); 20474314557cSVivien Didelot 20484314557cSVivien Didelot return -EINVAL; 20494314557cSVivien Didelot } 20504314557cSVivien Didelot 2051ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port) 2052ea698f4fSVivien Didelot { 2053ea698f4fSVivien Didelot bool message = dsa_is_dsa_port(chip->ds, port); 2054ea698f4fSVivien Didelot 2055ea698f4fSVivien Didelot return mv88e6xxx_port_set_message_port(chip, port, message); 2056ea698f4fSVivien Didelot } 2057ea698f4fSVivien Didelot 2058601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) 2059601aeed3SVivien Didelot { 20603ee50cbfSVivien Didelot struct dsa_switch *ds = chip->ds; 20613ee50cbfSVivien Didelot bool flood; 2062601aeed3SVivien Didelot 2063601aeed3SVivien Didelot /* Upstream ports flood frames with unknown unicast or multicast DA */ 20643ee50cbfSVivien Didelot flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port); 2065601aeed3SVivien Didelot if (chip->info->ops->port_set_egress_floods) 2066601aeed3SVivien Didelot return chip->info->ops->port_set_egress_floods(chip, port, 2067601aeed3SVivien Didelot flood, flood); 2068601aeed3SVivien Didelot 2069601aeed3SVivien Didelot return 0; 2070601aeed3SVivien Didelot } 2071601aeed3SVivien Didelot 20726d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, 20736d91782fSAndrew Lunn bool on) 20746d91782fSAndrew Lunn { 2075523a8904SVivien Didelot if (chip->info->ops->serdes_power) 2076523a8904SVivien Didelot return chip->info->ops->serdes_power(chip, port, on); 20776d91782fSAndrew Lunn 2078523a8904SVivien Didelot return 0; 20796d91782fSAndrew Lunn } 20806d91782fSAndrew Lunn 2081fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) 2082fa371c80SVivien Didelot { 2083fa371c80SVivien Didelot struct dsa_switch *ds = chip->ds; 2084fa371c80SVivien Didelot int upstream_port; 2085fa371c80SVivien Didelot int err; 2086fa371c80SVivien Didelot 208707073c79SVivien Didelot upstream_port = dsa_upstream_port(ds, port); 2088fa371c80SVivien Didelot if (chip->info->ops->port_set_upstream_port) { 2089fa371c80SVivien Didelot err = chip->info->ops->port_set_upstream_port(chip, port, 2090fa371c80SVivien Didelot upstream_port); 2091fa371c80SVivien Didelot if (err) 2092fa371c80SVivien Didelot return err; 2093fa371c80SVivien Didelot } 2094fa371c80SVivien Didelot 20950ea54ddaSVivien Didelot if (port == upstream_port) { 20960ea54ddaSVivien Didelot if (chip->info->ops->set_cpu_port) { 20970ea54ddaSVivien Didelot err = chip->info->ops->set_cpu_port(chip, 20980ea54ddaSVivien Didelot upstream_port); 20990ea54ddaSVivien Didelot if (err) 21000ea54ddaSVivien Didelot return err; 21010ea54ddaSVivien Didelot } 21020ea54ddaSVivien Didelot 21030ea54ddaSVivien Didelot if (chip->info->ops->set_egress_port) { 21040ea54ddaSVivien Didelot err = chip->info->ops->set_egress_port(chip, 21050ea54ddaSVivien Didelot upstream_port); 21060ea54ddaSVivien Didelot if (err) 21070ea54ddaSVivien Didelot return err; 21080ea54ddaSVivien Didelot } 21090ea54ddaSVivien Didelot } 21100ea54ddaSVivien Didelot 2111fa371c80SVivien Didelot return 0; 2112fa371c80SVivien Didelot } 2113fa371c80SVivien Didelot 2114fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) 2115fad09c73SVivien Didelot { 2116fad09c73SVivien Didelot struct dsa_switch *ds = chip->ds; 21170e7b9925SAndrew Lunn int err; 2118fad09c73SVivien Didelot u16 reg; 2119fad09c73SVivien Didelot 21207b898469SAndrew Lunn chip->ports[port].chip = chip; 21217b898469SAndrew Lunn chip->ports[port].port = port; 21227b898469SAndrew Lunn 2123d78343d2SVivien Didelot /* MAC Forcing register: don't force link, speed, duplex or flow control 2124d78343d2SVivien Didelot * state to any particular values on physical ports, but force the CPU 2125d78343d2SVivien Didelot * port and all DSA ports to their maximum bandwidth and full duplex. 2126fad09c73SVivien Didelot */ 2127d78343d2SVivien Didelot if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) 2128d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP, 2129d78343d2SVivien Didelot SPEED_MAX, DUPLEX_FULL, 213054186b91SAndrew Lunn PAUSE_OFF, 2131d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 2132fad09c73SVivien Didelot else 2133d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, 2134d78343d2SVivien Didelot SPEED_UNFORCED, DUPLEX_UNFORCED, 213554186b91SAndrew Lunn PAUSE_ON, 2136d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 21370e7b9925SAndrew Lunn if (err) 21380e7b9925SAndrew Lunn return err; 2139fad09c73SVivien Didelot 2140fad09c73SVivien Didelot /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, 2141fad09c73SVivien Didelot * disable Header mode, enable IGMP/MLD snooping, disable VLAN 2142fad09c73SVivien Didelot * tunneling, determine priority by looking at 802.1p and IP 2143fad09c73SVivien Didelot * priority fields (IP prio has precedence), and set STP state 2144fad09c73SVivien Didelot * to Forwarding. 2145fad09c73SVivien Didelot * 2146fad09c73SVivien Didelot * If this is the CPU link, use DSA or EDSA tagging depending 2147fad09c73SVivien Didelot * on which tagging mode was configured. 2148fad09c73SVivien Didelot * 2149fad09c73SVivien Didelot * If this is a link to another switch, use DSA tagging mode. 2150fad09c73SVivien Didelot * 2151fad09c73SVivien Didelot * If this is the upstream port for this switch, enable 2152fad09c73SVivien Didelot * forwarding of unknown unicasts and multicasts. 2153fad09c73SVivien Didelot */ 2154a89b433bSVivien Didelot reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP | 2155a89b433bSVivien Didelot MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | 2156a89b433bSVivien Didelot MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 2157a89b433bSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 21580e7b9925SAndrew Lunn if (err) 21590e7b9925SAndrew Lunn return err; 216056995cbcSAndrew Lunn 2161601aeed3SVivien Didelot err = mv88e6xxx_setup_port_mode(chip, port); 216256995cbcSAndrew Lunn if (err) 216356995cbcSAndrew Lunn return err; 2164fad09c73SVivien Didelot 2165601aeed3SVivien Didelot err = mv88e6xxx_setup_egress_floods(chip, port); 21664314557cSVivien Didelot if (err) 21674314557cSVivien Didelot return err; 21684314557cSVivien Didelot 216904aca993SAndrew Lunn /* Enable the SERDES interface for DSA and CPU ports. Normal 217004aca993SAndrew Lunn * ports SERDES are enabled when the port is enabled, thus 217104aca993SAndrew Lunn * saving a bit of power. 2172fad09c73SVivien Didelot */ 217304aca993SAndrew Lunn if ((dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) { 21746d91782fSAndrew Lunn err = mv88e6xxx_serdes_power(chip, port, true); 21750e7b9925SAndrew Lunn if (err) 21760e7b9925SAndrew Lunn return err; 217704aca993SAndrew Lunn } 2178fad09c73SVivien Didelot 2179fad09c73SVivien Didelot /* Port Control 2: don't force a good FCS, set the maximum frame size to 2180fad09c73SVivien Didelot * 10240 bytes, disable 802.1q tags checking, don't discard tagged or 2181fad09c73SVivien Didelot * untagged frames on this port, do a destination address lookup on all 2182fad09c73SVivien Didelot * received packets as usual, disable ARP mirroring and don't send a 2183fad09c73SVivien Didelot * copy of all transmitted/received frames on this port to the CPU. 2184fad09c73SVivien Didelot */ 2185a23b2961SAndrew Lunn err = mv88e6xxx_port_set_map_da(chip, port); 2186a23b2961SAndrew Lunn if (err) 2187a23b2961SAndrew Lunn return err; 2188a23b2961SAndrew Lunn 2189fa371c80SVivien Didelot err = mv88e6xxx_setup_upstream_port(chip, port); 21900e7b9925SAndrew Lunn if (err) 21910e7b9925SAndrew Lunn return err; 2192fad09c73SVivien Didelot 2193a23b2961SAndrew Lunn err = mv88e6xxx_port_set_8021q_mode(chip, port, 219481c6edb2SVivien Didelot MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED); 2195a23b2961SAndrew Lunn if (err) 2196a23b2961SAndrew Lunn return err; 2197a23b2961SAndrew Lunn 2198cd782656SVivien Didelot if (chip->info->ops->port_set_jumbo_size) { 2199cd782656SVivien Didelot err = chip->info->ops->port_set_jumbo_size(chip, port, 10240); 22005f436666SAndrew Lunn if (err) 22015f436666SAndrew Lunn return err; 22025f436666SAndrew Lunn } 22035f436666SAndrew Lunn 2204fad09c73SVivien Didelot /* Port Association Vector: when learning source addresses 2205fad09c73SVivien Didelot * of packets, add the address to the address database using 2206fad09c73SVivien Didelot * a port bitmap that has only the bit for this port set and 2207fad09c73SVivien Didelot * the other bits clear. 2208fad09c73SVivien Didelot */ 2209fad09c73SVivien Didelot reg = 1 << port; 2210fad09c73SVivien Didelot /* Disable learning for CPU port */ 2211fad09c73SVivien Didelot if (dsa_is_cpu_port(ds, port)) 2212fad09c73SVivien Didelot reg = 0; 2213fad09c73SVivien Didelot 22142a4614e4SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, 22152a4614e4SVivien Didelot reg); 22160e7b9925SAndrew Lunn if (err) 22170e7b9925SAndrew Lunn return err; 2218fad09c73SVivien Didelot 2219fad09c73SVivien Didelot /* Egress rate control 2: disable egress rate control. */ 22202cb8cb14SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2, 22212cb8cb14SVivien Didelot 0x0000); 22220e7b9925SAndrew Lunn if (err) 22230e7b9925SAndrew Lunn return err; 2224fad09c73SVivien Didelot 22250898432cSVivien Didelot if (chip->info->ops->port_pause_limit) { 22260898432cSVivien Didelot err = chip->info->ops->port_pause_limit(chip, port, 0, 0); 2227b35d322aSAndrew Lunn if (err) 2228b35d322aSAndrew Lunn return err; 2229b35d322aSAndrew Lunn } 2230b35d322aSAndrew Lunn 2231c8c94891SVivien Didelot if (chip->info->ops->port_disable_learn_limit) { 2232c8c94891SVivien Didelot err = chip->info->ops->port_disable_learn_limit(chip, port); 2233c8c94891SVivien Didelot if (err) 2234c8c94891SVivien Didelot return err; 2235c8c94891SVivien Didelot } 2236c8c94891SVivien Didelot 22379dbfb4e1SVivien Didelot if (chip->info->ops->port_disable_pri_override) { 22389dbfb4e1SVivien Didelot err = chip->info->ops->port_disable_pri_override(chip, port); 22390e7b9925SAndrew Lunn if (err) 22400e7b9925SAndrew Lunn return err; 2241ef0a7318SAndrew Lunn } 22422bbb33beSAndrew Lunn 2243ef0a7318SAndrew Lunn if (chip->info->ops->port_tag_remap) { 2244ef0a7318SAndrew Lunn err = chip->info->ops->port_tag_remap(chip, port); 22450e7b9925SAndrew Lunn if (err) 22460e7b9925SAndrew Lunn return err; 2247fad09c73SVivien Didelot } 2248fad09c73SVivien Didelot 2249ef70b111SAndrew Lunn if (chip->info->ops->port_egress_rate_limiting) { 2250ef70b111SAndrew Lunn err = chip->info->ops->port_egress_rate_limiting(chip, port); 22510e7b9925SAndrew Lunn if (err) 22520e7b9925SAndrew Lunn return err; 2253fad09c73SVivien Didelot } 2254fad09c73SVivien Didelot 2255ea698f4fSVivien Didelot err = mv88e6xxx_setup_message_port(chip, port); 22560e7b9925SAndrew Lunn if (err) 22570e7b9925SAndrew Lunn return err; 2258fad09c73SVivien Didelot 2259fad09c73SVivien Didelot /* Port based VLAN map: give each port the same default address 2260fad09c73SVivien Didelot * database, and allow bidirectional communication between the 2261fad09c73SVivien Didelot * CPU and DSA port(s), and the other ports. 2262fad09c73SVivien Didelot */ 2263b4e48c50SVivien Didelot err = mv88e6xxx_port_set_fid(chip, port, 0); 22640e7b9925SAndrew Lunn if (err) 22650e7b9925SAndrew Lunn return err; 2266fad09c73SVivien Didelot 2267240ea3efSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, port); 22680e7b9925SAndrew Lunn if (err) 22690e7b9925SAndrew Lunn return err; 2270fad09c73SVivien Didelot 2271fad09c73SVivien Didelot /* Default VLAN ID and priority: don't set a default VLAN 2272fad09c73SVivien Didelot * ID, and set the default packet priority to zero. 2273fad09c73SVivien Didelot */ 2274b7929fb3SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0); 2275fad09c73SVivien Didelot } 2276fad09c73SVivien Didelot 227704aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port, 227804aca993SAndrew Lunn struct phy_device *phydev) 227904aca993SAndrew Lunn { 228004aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 2281523a8904SVivien Didelot int err; 228204aca993SAndrew Lunn 228304aca993SAndrew Lunn mutex_lock(&chip->reg_lock); 2284efd1ba6aSAndrew Lunn 2285523a8904SVivien Didelot err = mv88e6xxx_serdes_power(chip, port, true); 2286efd1ba6aSAndrew Lunn 2287efd1ba6aSAndrew Lunn if (!err && chip->info->ops->serdes_irq_setup) 2288efd1ba6aSAndrew Lunn err = chip->info->ops->serdes_irq_setup(chip, port); 2289efd1ba6aSAndrew Lunn 229004aca993SAndrew Lunn mutex_unlock(&chip->reg_lock); 229104aca993SAndrew Lunn 229204aca993SAndrew Lunn return err; 229304aca993SAndrew Lunn } 229404aca993SAndrew Lunn 229575104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port) 229604aca993SAndrew Lunn { 229704aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 229804aca993SAndrew Lunn 229904aca993SAndrew Lunn mutex_lock(&chip->reg_lock); 2300efd1ba6aSAndrew Lunn 23014a0eb731SAndrew Lunn if (mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED)) 23024a0eb731SAndrew Lunn dev_err(chip->dev, "failed to disable port\n"); 23034a0eb731SAndrew Lunn 2304efd1ba6aSAndrew Lunn if (chip->info->ops->serdes_irq_free) 2305efd1ba6aSAndrew Lunn chip->info->ops->serdes_irq_free(chip, port); 2306efd1ba6aSAndrew Lunn 2307523a8904SVivien Didelot if (mv88e6xxx_serdes_power(chip, port, false)) 2308523a8904SVivien Didelot dev_err(chip->dev, "failed to power off SERDES\n"); 2309efd1ba6aSAndrew Lunn 231004aca993SAndrew Lunn mutex_unlock(&chip->reg_lock); 231104aca993SAndrew Lunn } 231204aca993SAndrew Lunn 23132cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, 23142cfcd964SVivien Didelot unsigned int ageing_time) 23152cfcd964SVivien Didelot { 231604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 23172cfcd964SVivien Didelot int err; 23182cfcd964SVivien Didelot 23192cfcd964SVivien Didelot mutex_lock(&chip->reg_lock); 2320720c6343SVivien Didelot err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time); 23212cfcd964SVivien Didelot mutex_unlock(&chip->reg_lock); 23222cfcd964SVivien Didelot 23232cfcd964SVivien Didelot return err; 23242cfcd964SVivien Didelot } 23252cfcd964SVivien Didelot 2326447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip) 2327fad09c73SVivien Didelot { 2328fad09c73SVivien Didelot int err; 2329fad09c73SVivien Didelot 2330de227387SAndrew Lunn /* Initialize the statistics unit */ 2331447b1bb8SVivien Didelot if (chip->info->ops->stats_set_histogram) { 2332447b1bb8SVivien Didelot err = chip->info->ops->stats_set_histogram(chip); 2333de227387SAndrew Lunn if (err) 2334de227387SAndrew Lunn return err; 2335447b1bb8SVivien Didelot } 2336de227387SAndrew Lunn 233740cff8fcSAndrew Lunn return mv88e6xxx_g1_stats_clear(chip); 23389729934cSVivien Didelot } 23399729934cSVivien Didelot 2340ea89098eSAndrew Lunn /* The mv88e6390 has some hidden registers used for debug and 2341ea89098eSAndrew Lunn * development. The errata also makes use of them. 2342ea89098eSAndrew Lunn */ 2343ea89098eSAndrew Lunn static int mv88e6390_hidden_write(struct mv88e6xxx_chip *chip, int port, 2344ea89098eSAndrew Lunn int reg, u16 val) 2345ea89098eSAndrew Lunn { 2346ea89098eSAndrew Lunn u16 ctrl; 2347ea89098eSAndrew Lunn int err; 2348ea89098eSAndrew Lunn 2349ea89098eSAndrew Lunn err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_DATA_PORT, 2350ea89098eSAndrew Lunn PORT_RESERVED_1A, val); 2351ea89098eSAndrew Lunn if (err) 2352ea89098eSAndrew Lunn return err; 2353ea89098eSAndrew Lunn 2354ea89098eSAndrew Lunn ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_WRITE | 2355ea89098eSAndrew Lunn PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT | 2356ea89098eSAndrew Lunn reg; 2357ea89098eSAndrew Lunn 2358ea89098eSAndrew Lunn return mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT, 2359ea89098eSAndrew Lunn PORT_RESERVED_1A, ctrl); 2360ea89098eSAndrew Lunn } 2361ea89098eSAndrew Lunn 2362ea89098eSAndrew Lunn static int mv88e6390_hidden_wait(struct mv88e6xxx_chip *chip) 2363ea89098eSAndrew Lunn { 2364ea89098eSAndrew Lunn return mv88e6xxx_wait(chip, PORT_RESERVED_1A_CTRL_PORT, 2365ea89098eSAndrew Lunn PORT_RESERVED_1A, PORT_RESERVED_1A_BUSY); 2366ea89098eSAndrew Lunn } 2367ea89098eSAndrew Lunn 2368ea89098eSAndrew Lunn 2369ea89098eSAndrew Lunn static int mv88e6390_hidden_read(struct mv88e6xxx_chip *chip, int port, 2370ea89098eSAndrew Lunn int reg, u16 *val) 2371ea89098eSAndrew Lunn { 2372ea89098eSAndrew Lunn u16 ctrl; 2373ea89098eSAndrew Lunn int err; 2374ea89098eSAndrew Lunn 2375ea89098eSAndrew Lunn ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_READ | 2376ea89098eSAndrew Lunn PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT | 2377ea89098eSAndrew Lunn reg; 2378ea89098eSAndrew Lunn 2379ea89098eSAndrew Lunn err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT, 2380ea89098eSAndrew Lunn PORT_RESERVED_1A, ctrl); 2381ea89098eSAndrew Lunn if (err) 2382ea89098eSAndrew Lunn return err; 2383ea89098eSAndrew Lunn 2384ea89098eSAndrew Lunn err = mv88e6390_hidden_wait(chip); 2385ea89098eSAndrew Lunn if (err) 2386ea89098eSAndrew Lunn return err; 2387ea89098eSAndrew Lunn 2388ea89098eSAndrew Lunn return mv88e6xxx_port_read(chip, PORT_RESERVED_1A_DATA_PORT, 2389ea89098eSAndrew Lunn PORT_RESERVED_1A, val); 2390ea89098eSAndrew Lunn } 2391ea89098eSAndrew Lunn 2392ea89098eSAndrew Lunn /* Check if the errata has already been applied. */ 2393ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip) 2394ea89098eSAndrew Lunn { 2395ea89098eSAndrew Lunn int port; 2396ea89098eSAndrew Lunn int err; 2397ea89098eSAndrew Lunn u16 val; 2398ea89098eSAndrew Lunn 2399ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 2400ea89098eSAndrew Lunn err = mv88e6390_hidden_read(chip, port, 0, &val); 2401ea89098eSAndrew Lunn if (err) { 2402ea89098eSAndrew Lunn dev_err(chip->dev, 2403ea89098eSAndrew Lunn "Error reading hidden register: %d\n", err); 2404ea89098eSAndrew Lunn return false; 2405ea89098eSAndrew Lunn } 2406ea89098eSAndrew Lunn if (val != 0x01c0) 2407ea89098eSAndrew Lunn return false; 2408ea89098eSAndrew Lunn } 2409ea89098eSAndrew Lunn 2410ea89098eSAndrew Lunn return true; 2411ea89098eSAndrew Lunn } 2412ea89098eSAndrew Lunn 2413ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic 2414ea89098eSAndrew Lunn * values into undocumented hidden registers and then performing a 2415ea89098eSAndrew Lunn * software reset. 2416ea89098eSAndrew Lunn */ 2417ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) 2418ea89098eSAndrew Lunn { 2419ea89098eSAndrew Lunn int port; 2420ea89098eSAndrew Lunn int err; 2421ea89098eSAndrew Lunn 2422ea89098eSAndrew Lunn if (mv88e6390_setup_errata_applied(chip)) 2423ea89098eSAndrew Lunn return 0; 2424ea89098eSAndrew Lunn 2425ea89098eSAndrew Lunn /* Set the ports into blocking mode */ 2426ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 2427ea89098eSAndrew Lunn err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED); 2428ea89098eSAndrew Lunn if (err) 2429ea89098eSAndrew Lunn return err; 2430ea89098eSAndrew Lunn } 2431ea89098eSAndrew Lunn 2432ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 2433ea89098eSAndrew Lunn err = mv88e6390_hidden_write(chip, port, 0, 0x01c0); 2434ea89098eSAndrew Lunn if (err) 2435ea89098eSAndrew Lunn return err; 2436ea89098eSAndrew Lunn } 2437ea89098eSAndrew Lunn 2438ea89098eSAndrew Lunn return mv88e6xxx_software_reset(chip); 2439ea89098eSAndrew Lunn } 2440ea89098eSAndrew Lunn 2441fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds) 2442fad09c73SVivien Didelot { 244304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 24442d2e1dd2SAndrew Lunn u8 cmode; 2445fad09c73SVivien Didelot int err; 2446fad09c73SVivien Didelot int i; 2447fad09c73SVivien Didelot 2448fad09c73SVivien Didelot chip->ds = ds; 2449a3c53be5SAndrew Lunn ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); 2450fad09c73SVivien Didelot 2451fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 2452fad09c73SVivien Didelot 2453ea89098eSAndrew Lunn if (chip->info->ops->setup_errata) { 2454ea89098eSAndrew Lunn err = chip->info->ops->setup_errata(chip); 2455ea89098eSAndrew Lunn if (err) 2456ea89098eSAndrew Lunn goto unlock; 2457ea89098eSAndrew Lunn } 2458ea89098eSAndrew Lunn 24592d2e1dd2SAndrew Lunn /* Cache the cmode of each port. */ 24602d2e1dd2SAndrew Lunn for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 24612d2e1dd2SAndrew Lunn if (chip->info->ops->port_get_cmode) { 24622d2e1dd2SAndrew Lunn err = chip->info->ops->port_get_cmode(chip, i, &cmode); 24632d2e1dd2SAndrew Lunn if (err) 2464e29129fcSDan Carpenter goto unlock; 24652d2e1dd2SAndrew Lunn 24662d2e1dd2SAndrew Lunn chip->ports[i].cmode = cmode; 24672d2e1dd2SAndrew Lunn } 24682d2e1dd2SAndrew Lunn } 24692d2e1dd2SAndrew Lunn 24709729934cSVivien Didelot /* Setup Switch Port Registers */ 2471370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 2472100a9b9dSAndrew Lunn if (dsa_is_unused_port(ds, i)) { 2473100a9b9dSAndrew Lunn err = mv88e6xxx_port_set_state(chip, i, 2474100a9b9dSAndrew Lunn BR_STATE_DISABLED); 2475100a9b9dSAndrew Lunn if (err) 2476100a9b9dSAndrew Lunn goto unlock; 2477100a9b9dSAndrew Lunn 2478100a9b9dSAndrew Lunn err = mv88e6xxx_serdes_power(chip, i, false); 2479100a9b9dSAndrew Lunn if (err) 2480100a9b9dSAndrew Lunn goto unlock; 2481100a9b9dSAndrew Lunn 248291dee144SVivien Didelot continue; 2483100a9b9dSAndrew Lunn } 248491dee144SVivien Didelot 24859729934cSVivien Didelot err = mv88e6xxx_setup_port(chip, i); 24869729934cSVivien Didelot if (err) 24879729934cSVivien Didelot goto unlock; 24889729934cSVivien Didelot } 24899729934cSVivien Didelot 2490cd8da8bbSVivien Didelot err = mv88e6xxx_irl_setup(chip); 2491cd8da8bbSVivien Didelot if (err) 2492cd8da8bbSVivien Didelot goto unlock; 2493cd8da8bbSVivien Didelot 249404a69a17SVivien Didelot err = mv88e6xxx_mac_setup(chip); 249504a69a17SVivien Didelot if (err) 249604a69a17SVivien Didelot goto unlock; 249704a69a17SVivien Didelot 24981b17aedfSVivien Didelot err = mv88e6xxx_phy_setup(chip); 24991b17aedfSVivien Didelot if (err) 25001b17aedfSVivien Didelot goto unlock; 25011b17aedfSVivien Didelot 2502b486d7c9SVivien Didelot err = mv88e6xxx_vtu_setup(chip); 2503b486d7c9SVivien Didelot if (err) 2504b486d7c9SVivien Didelot goto unlock; 2505b486d7c9SVivien Didelot 250681228996SVivien Didelot err = mv88e6xxx_pvt_setup(chip); 250781228996SVivien Didelot if (err) 250881228996SVivien Didelot goto unlock; 250981228996SVivien Didelot 2510a2ac29d2SVivien Didelot err = mv88e6xxx_atu_setup(chip); 2511a2ac29d2SVivien Didelot if (err) 2512a2ac29d2SVivien Didelot goto unlock; 2513a2ac29d2SVivien Didelot 251487fa886eSAndrew Lunn err = mv88e6xxx_broadcast_setup(chip, 0); 251587fa886eSAndrew Lunn if (err) 251687fa886eSAndrew Lunn goto unlock; 251787fa886eSAndrew Lunn 25189e907d73SVivien Didelot err = mv88e6xxx_pot_setup(chip); 25199e907d73SVivien Didelot if (err) 25209e907d73SVivien Didelot goto unlock; 25219e907d73SVivien Didelot 25229e5baf9bSVivien Didelot err = mv88e6xxx_rmu_setup(chip); 25239e5baf9bSVivien Didelot if (err) 25249e5baf9bSVivien Didelot goto unlock; 25259e5baf9bSVivien Didelot 252651c901a7SVivien Didelot err = mv88e6xxx_rsvd2cpu_setup(chip); 25276e55f698SAndrew Lunn if (err) 25286e55f698SAndrew Lunn goto unlock; 25296e55f698SAndrew Lunn 2530b28f872dSVivien Didelot err = mv88e6xxx_trunk_setup(chip); 2531b28f872dSVivien Didelot if (err) 2532b28f872dSVivien Didelot goto unlock; 2533b28f872dSVivien Didelot 2534c7f047b6SVivien Didelot err = mv88e6xxx_devmap_setup(chip); 2535c7f047b6SVivien Didelot if (err) 2536c7f047b6SVivien Didelot goto unlock; 2537c7f047b6SVivien Didelot 253893e18d61SVivien Didelot err = mv88e6xxx_pri_setup(chip); 253993e18d61SVivien Didelot if (err) 254093e18d61SVivien Didelot goto unlock; 254193e18d61SVivien Didelot 2542c6fe0ad2SBrandon Streiff /* Setup PTP Hardware Clock and timestamping */ 25432fa8d3afSBrandon Streiff if (chip->info->ptp_support) { 25442fa8d3afSBrandon Streiff err = mv88e6xxx_ptp_setup(chip); 25452fa8d3afSBrandon Streiff if (err) 25462fa8d3afSBrandon Streiff goto unlock; 2547c6fe0ad2SBrandon Streiff 2548c6fe0ad2SBrandon Streiff err = mv88e6xxx_hwtstamp_setup(chip); 2549c6fe0ad2SBrandon Streiff if (err) 2550c6fe0ad2SBrandon Streiff goto unlock; 25512fa8d3afSBrandon Streiff } 25522fa8d3afSBrandon Streiff 2553447b1bb8SVivien Didelot err = mv88e6xxx_stats_setup(chip); 2554447b1bb8SVivien Didelot if (err) 2555447b1bb8SVivien Didelot goto unlock; 2556447b1bb8SVivien Didelot 2557fad09c73SVivien Didelot unlock: 2558fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 2559fad09c73SVivien Didelot 2560fad09c73SVivien Didelot return err; 2561fad09c73SVivien Didelot } 2562fad09c73SVivien Didelot 2563e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) 2564fad09c73SVivien Didelot { 25650dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 25660dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 2567e57e5e77SVivien Didelot u16 val; 2568e57e5e77SVivien Didelot int err; 2569fad09c73SVivien Didelot 2570ee26a228SAndrew Lunn if (!chip->info->ops->phy_read) 2571ee26a228SAndrew Lunn return -EOPNOTSUPP; 2572ee26a228SAndrew Lunn 2573fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 2574ee26a228SAndrew Lunn err = chip->info->ops->phy_read(chip, bus, phy, reg, &val); 2575fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 2576e57e5e77SVivien Didelot 2577da9f3301SAndrew Lunn if (reg == MII_PHYSID2) { 2578ddc49acbSAndrew Lunn /* Some internal PHYs don't have a model number. */ 2579ddc49acbSAndrew Lunn if (chip->info->family != MV88E6XXX_FAMILY_6165) 2580ddc49acbSAndrew Lunn /* Then there is the 6165 family. It gets is 2581ddc49acbSAndrew Lunn * PHYs correct. But it can also have two 2582ddc49acbSAndrew Lunn * SERDES interfaces in the PHY address 2583ddc49acbSAndrew Lunn * space. And these don't have a model 2584ddc49acbSAndrew Lunn * number. But they are not PHYs, so we don't 2585ddc49acbSAndrew Lunn * want to give them something a PHY driver 2586ddc49acbSAndrew Lunn * will recognise. 2587ddc49acbSAndrew Lunn * 2588ddc49acbSAndrew Lunn * Use the mv88e6390 family model number 2589ddc49acbSAndrew Lunn * instead, for anything which really could be 2590ddc49acbSAndrew Lunn * a PHY, 2591da9f3301SAndrew Lunn */ 2592da9f3301SAndrew Lunn if (!(val & 0x3f0)) 2593107fcc10SVivien Didelot val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4; 2594da9f3301SAndrew Lunn } 2595da9f3301SAndrew Lunn 2596e57e5e77SVivien Didelot return err ? err : val; 2597fad09c73SVivien Didelot } 2598fad09c73SVivien Didelot 2599e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 2600fad09c73SVivien Didelot { 26010dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 26020dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 2603e57e5e77SVivien Didelot int err; 2604fad09c73SVivien Didelot 2605ee26a228SAndrew Lunn if (!chip->info->ops->phy_write) 2606ee26a228SAndrew Lunn return -EOPNOTSUPP; 2607ee26a228SAndrew Lunn 2608fad09c73SVivien Didelot mutex_lock(&chip->reg_lock); 2609ee26a228SAndrew Lunn err = chip->info->ops->phy_write(chip, bus, phy, reg, val); 2610fad09c73SVivien Didelot mutex_unlock(&chip->reg_lock); 2611e57e5e77SVivien Didelot 2612e57e5e77SVivien Didelot return err; 2613fad09c73SVivien Didelot } 2614fad09c73SVivien Didelot 2615fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, 2616a3c53be5SAndrew Lunn struct device_node *np, 2617a3c53be5SAndrew Lunn bool external) 2618fad09c73SVivien Didelot { 2619fad09c73SVivien Didelot static int index; 26200dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 2621fad09c73SVivien Didelot struct mii_bus *bus; 2622fad09c73SVivien Didelot int err; 2623fad09c73SVivien Didelot 26242510babcSAndrew Lunn if (external) { 26252510babcSAndrew Lunn mutex_lock(&chip->reg_lock); 26262510babcSAndrew Lunn err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true); 26272510babcSAndrew Lunn mutex_unlock(&chip->reg_lock); 26282510babcSAndrew Lunn 26292510babcSAndrew Lunn if (err) 26302510babcSAndrew Lunn return err; 26312510babcSAndrew Lunn } 26322510babcSAndrew Lunn 26330dd12d54SAndrew Lunn bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus)); 2634fad09c73SVivien Didelot if (!bus) 2635fad09c73SVivien Didelot return -ENOMEM; 2636fad09c73SVivien Didelot 26370dd12d54SAndrew Lunn mdio_bus = bus->priv; 2638a3c53be5SAndrew Lunn mdio_bus->bus = bus; 26390dd12d54SAndrew Lunn mdio_bus->chip = chip; 2640a3c53be5SAndrew Lunn INIT_LIST_HEAD(&mdio_bus->list); 2641a3c53be5SAndrew Lunn mdio_bus->external = external; 26420dd12d54SAndrew Lunn 2643fad09c73SVivien Didelot if (np) { 2644fad09c73SVivien Didelot bus->name = np->full_name; 2645f7ce9103SRob Herring snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np); 2646fad09c73SVivien Didelot } else { 2647fad09c73SVivien Didelot bus->name = "mv88e6xxx SMI"; 2648fad09c73SVivien Didelot snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++); 2649fad09c73SVivien Didelot } 2650fad09c73SVivien Didelot 2651fad09c73SVivien Didelot bus->read = mv88e6xxx_mdio_read; 2652fad09c73SVivien Didelot bus->write = mv88e6xxx_mdio_write; 2653fad09c73SVivien Didelot bus->parent = chip->dev; 2654fad09c73SVivien Didelot 26556f88284fSAndrew Lunn if (!external) { 26566f88284fSAndrew Lunn err = mv88e6xxx_g2_irq_mdio_setup(chip, bus); 26576f88284fSAndrew Lunn if (err) 26586f88284fSAndrew Lunn return err; 26596f88284fSAndrew Lunn } 26606f88284fSAndrew Lunn 2661a3c53be5SAndrew Lunn err = of_mdiobus_register(bus, np); 2662fad09c73SVivien Didelot if (err) { 2663fad09c73SVivien Didelot dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err); 26646f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 2665fad09c73SVivien Didelot return err; 2666fad09c73SVivien Didelot } 2667fad09c73SVivien Didelot 2668a3c53be5SAndrew Lunn if (external) 2669a3c53be5SAndrew Lunn list_add_tail(&mdio_bus->list, &chip->mdios); 2670a3c53be5SAndrew Lunn else 2671a3c53be5SAndrew Lunn list_add(&mdio_bus->list, &chip->mdios); 2672a3c53be5SAndrew Lunn 2673a3c53be5SAndrew Lunn return 0; 2674a3c53be5SAndrew Lunn } 2675a3c53be5SAndrew Lunn 2676a3c53be5SAndrew Lunn static const struct of_device_id mv88e6xxx_mdio_external_match[] = { 2677a3c53be5SAndrew Lunn { .compatible = "marvell,mv88e6xxx-mdio-external", 2678a3c53be5SAndrew Lunn .data = (void *)true }, 2679a3c53be5SAndrew Lunn { }, 2680a3c53be5SAndrew Lunn }; 2681a3c53be5SAndrew Lunn 26823126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) 26833126aeecSAndrew Lunn 26843126aeecSAndrew Lunn { 26853126aeecSAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 26863126aeecSAndrew Lunn struct mii_bus *bus; 26873126aeecSAndrew Lunn 26883126aeecSAndrew Lunn list_for_each_entry(mdio_bus, &chip->mdios, list) { 26893126aeecSAndrew Lunn bus = mdio_bus->bus; 26903126aeecSAndrew Lunn 26916f88284fSAndrew Lunn if (!mdio_bus->external) 26926f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 26936f88284fSAndrew Lunn 26943126aeecSAndrew Lunn mdiobus_unregister(bus); 26953126aeecSAndrew Lunn } 26963126aeecSAndrew Lunn } 26973126aeecSAndrew Lunn 2698a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, 2699a3c53be5SAndrew Lunn struct device_node *np) 2700a3c53be5SAndrew Lunn { 2701a3c53be5SAndrew Lunn const struct of_device_id *match; 2702a3c53be5SAndrew Lunn struct device_node *child; 2703a3c53be5SAndrew Lunn int err; 2704a3c53be5SAndrew Lunn 2705a3c53be5SAndrew Lunn /* Always register one mdio bus for the internal/default mdio 2706a3c53be5SAndrew Lunn * bus. This maybe represented in the device tree, but is 2707a3c53be5SAndrew Lunn * optional. 2708a3c53be5SAndrew Lunn */ 2709a3c53be5SAndrew Lunn child = of_get_child_by_name(np, "mdio"); 2710a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, false); 2711a3c53be5SAndrew Lunn if (err) 2712a3c53be5SAndrew Lunn return err; 2713a3c53be5SAndrew Lunn 2714a3c53be5SAndrew Lunn /* Walk the device tree, and see if there are any other nodes 2715a3c53be5SAndrew Lunn * which say they are compatible with the external mdio 2716a3c53be5SAndrew Lunn * bus. 2717a3c53be5SAndrew Lunn */ 2718a3c53be5SAndrew Lunn for_each_available_child_of_node(np, child) { 2719a3c53be5SAndrew Lunn match = of_match_node(mv88e6xxx_mdio_external_match, child); 2720a3c53be5SAndrew Lunn if (match) { 2721a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, true); 27223126aeecSAndrew Lunn if (err) { 27233126aeecSAndrew Lunn mv88e6xxx_mdios_unregister(chip); 2724a3c53be5SAndrew Lunn return err; 2725a3c53be5SAndrew Lunn } 2726a3c53be5SAndrew Lunn } 27273126aeecSAndrew Lunn } 2728a3c53be5SAndrew Lunn 2729a3c53be5SAndrew Lunn return 0; 2730a3c53be5SAndrew Lunn } 2731a3c53be5SAndrew Lunn 2732855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) 2733855b1932SVivien Didelot { 273404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2735855b1932SVivien Didelot 2736855b1932SVivien Didelot return chip->eeprom_len; 2737855b1932SVivien Didelot } 2738855b1932SVivien Didelot 2739855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds, 2740855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 2741855b1932SVivien Didelot { 274204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2743855b1932SVivien Didelot int err; 2744855b1932SVivien Didelot 2745ee4dc2e7SVivien Didelot if (!chip->info->ops->get_eeprom) 2746ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 2747ee4dc2e7SVivien Didelot 2748855b1932SVivien Didelot mutex_lock(&chip->reg_lock); 2749ee4dc2e7SVivien Didelot err = chip->info->ops->get_eeprom(chip, eeprom, data); 2750855b1932SVivien Didelot mutex_unlock(&chip->reg_lock); 2751855b1932SVivien Didelot 2752855b1932SVivien Didelot if (err) 2753855b1932SVivien Didelot return err; 2754855b1932SVivien Didelot 2755855b1932SVivien Didelot eeprom->magic = 0xc3ec4951; 2756855b1932SVivien Didelot 2757855b1932SVivien Didelot return 0; 2758855b1932SVivien Didelot } 2759855b1932SVivien Didelot 2760855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, 2761855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 2762855b1932SVivien Didelot { 276304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2764855b1932SVivien Didelot int err; 2765855b1932SVivien Didelot 2766ee4dc2e7SVivien Didelot if (!chip->info->ops->set_eeprom) 2767ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 2768ee4dc2e7SVivien Didelot 2769855b1932SVivien Didelot if (eeprom->magic != 0xc3ec4951) 2770855b1932SVivien Didelot return -EINVAL; 2771855b1932SVivien Didelot 2772855b1932SVivien Didelot mutex_lock(&chip->reg_lock); 2773ee4dc2e7SVivien Didelot err = chip->info->ops->set_eeprom(chip, eeprom, data); 2774855b1932SVivien Didelot mutex_unlock(&chip->reg_lock); 2775855b1932SVivien Didelot 2776855b1932SVivien Didelot return err; 2777855b1932SVivien Didelot } 2778855b1932SVivien Didelot 2779b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = { 27804b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6097 */ 278193e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 278293e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 2783cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 2784b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 27857e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 27867e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 278708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 27887f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 278996a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2790ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 279156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2792601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 279356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2794ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 27950898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2796c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 27979dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 27986c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 27992d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 2800a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 280140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 2802dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2803dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2804052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2805fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2806fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2807fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 280851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 28099e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 2810a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 2811a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 281217e708baSVivien Didelot .reset = mv88e6185_g1_reset, 28139e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 2814f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 28150ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 28166c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 2817b3469dd8SVivien Didelot }; 2818b3469dd8SVivien Didelot 2819b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = { 28204b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6095 */ 282193e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 282293e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 2823b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 28247e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 28257e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 282608ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 28277f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 282896a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 282956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 2830601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 2831a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 28326c422e34SRussell King .port_link_state = mv88e6185_port_link_state, 28332d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 2834a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 283540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 2836dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2837dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2838052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 283951c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 2840a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 2841a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 284217e708baSVivien Didelot .reset = mv88e6185_g1_reset, 2843f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 28440ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 28456c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 2846b3469dd8SVivien Didelot }; 2847b3469dd8SVivien Didelot 28487d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = { 284915da3cc8SStefan Eichenberger /* MV88E6XXX_FAMILY_6097 */ 285093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 285193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 2852cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 28537d381a02SStefan Eichenberger .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 28547d381a02SStefan Eichenberger .phy_read = mv88e6xxx_g2_smi_phy_read, 28557d381a02SStefan Eichenberger .phy_write = mv88e6xxx_g2_smi_phy_write, 28567d381a02SStefan Eichenberger .port_set_link = mv88e6xxx_port_set_link, 28577d381a02SStefan Eichenberger .port_set_duplex = mv88e6xxx_port_set_duplex, 28587d381a02SStefan Eichenberger .port_set_speed = mv88e6185_port_set_speed, 2859ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 286056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2861601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 286256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2863cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2864ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 28650898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2866c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 28679dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 28686c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 28692d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 28707d381a02SStefan Eichenberger .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 287140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 28727d381a02SStefan Eichenberger .stats_get_sset_count = mv88e6095_stats_get_sset_count, 28737d381a02SStefan Eichenberger .stats_get_strings = mv88e6095_stats_get_strings, 28747d381a02SStefan Eichenberger .stats_get_stats = mv88e6095_stats_get_stats, 2875fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2876fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 287791eaa475SVolodymyr Bendiuga .watchdog_ops = &mv88e6097_watchdog_ops, 287851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 28799e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 288017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 28819e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 2882f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 28830ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 28846c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 28857d381a02SStefan Eichenberger }; 28867d381a02SStefan Eichenberger 2887b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = { 28884b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 288993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 289093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 2891cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 2892b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2893ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 2894ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 289508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 28967f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 289796a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 289856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 2899601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 2900c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 29019dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 29026c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 29032d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 29040ac64c39SAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 290540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 2906dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2907dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2908052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2909fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2910fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2911fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 291251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 29139e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 291417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 2915f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 29160ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 29176c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 2918b3469dd8SVivien Didelot }; 2919b3469dd8SVivien Didelot 2920b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = { 29214b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 292293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 292393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 2924b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 29257e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 29267e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 292708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 29287f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 292996a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 2930ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 293156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2932601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 293356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 2934a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 2935cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2936ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 29370898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 293854186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 29396c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 29402d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 2941a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 294240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 2943dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 2944dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 2945052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 2946fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 2947fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 2948fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 294951c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 2950a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 295102317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 2952a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 295317e708baSVivien Didelot .reset = mv88e6185_g1_reset, 2954f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 29550ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 29566c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 2957b3469dd8SVivien Didelot }; 2958b3469dd8SVivien Didelot 2959990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = { 2960990e27b0SVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 296193e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 296293e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 2963cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 2964990e27b0SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 2965990e27b0SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 2966990e27b0SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 2967990e27b0SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 2968990e27b0SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 2969990e27b0SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 2970990e27b0SVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 2971990e27b0SVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 297226422340SMarek Behún .port_set_speed = mv88e6341_port_set_speed, 29737cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6341_port_max_speed_mode, 2974990e27b0SVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 2975990e27b0SVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 2976990e27b0SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 2977990e27b0SVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 2978cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 2979990e27b0SVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 29800898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 2981990e27b0SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 2982990e27b0SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 29836c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 29842d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 2985990e27b0SVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 298640cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 2987990e27b0SVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 2988990e27b0SVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 2989990e27b0SVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 2990fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 2991fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 2992990e27b0SVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 2993990e27b0SVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 29949e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 2995990e27b0SVivien Didelot .reset = mv88e6352_g1_reset, 2996f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 29970ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 29986751e7c6SAndrew Lunn .serdes_power = mv88e6341_serdes_power, 2999a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 3000e3af71a3SMarek Behún .phylink_validate = mv88e6341_phylink_validate, 3001990e27b0SVivien Didelot }; 3002990e27b0SVivien Didelot 3003b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = { 30044b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 300593e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 300693e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3007cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3008b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3009ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 3010ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 301108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 30127f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 301396a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3014ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 301556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3016601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 301756995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3018cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3019ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 30200898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3021c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 30229dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 30236c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 30242d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3025a6da21bbSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 302640cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3027dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3028dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3029052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3030fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3031fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3032fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 303351c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 30349e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 303517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3036f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 30370ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3038a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 3039dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 30406c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3041b3469dd8SVivien Didelot }; 3042b3469dd8SVivien Didelot 3043b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = { 30444b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 304593e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 304693e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3047cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3048b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3049efb3e74dSAndrew Lunn .phy_read = mv88e6165_phy_read, 3050efb3e74dSAndrew Lunn .phy_write = mv88e6165_phy_write, 305108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 30527f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 305396a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3054c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 30559dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 30566c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 30572d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3058a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 305940cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3060dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3061dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3062052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3063fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3064fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3065fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 306651c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 30679e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 306817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3069f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 30700ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3071a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 3072dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 30736c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3074b3469dd8SVivien Didelot }; 3075b3469dd8SVivien Didelot 3076b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = { 30774b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 307893e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 307993e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3080cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3081b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3082b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3083b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 308408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 30857f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 308694d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 308796a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3088ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 308956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3090601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 309156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3092cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3093ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 30940898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3095c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 30969dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 30976c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 30982d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3099a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 310040cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3101dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3102dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3103052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3104fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3105fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3106fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 310751c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 31089e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 310917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3110f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 31110ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 31126c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3113b3469dd8SVivien Didelot }; 3114b3469dd8SVivien Didelot 3115b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = { 31164b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 311793e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 311893e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3119cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3120ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3121ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3122b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3123b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3124b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 312508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 31267f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3127a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 312896a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 3129ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 313056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3131601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 313256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3133cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3134ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 31350898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3136c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 31379dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 31386c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 31392d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3140a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 314140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3142dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3143dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3144052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3145fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3146fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3147fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 314851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 31499e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 315017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 31519e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 3152f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 31530ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 31546d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 3155a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 31566c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3157b3469dd8SVivien Didelot }; 3158b3469dd8SVivien Didelot 3159b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = { 31604b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 316193e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 316293e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3163cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3164b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3165b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3166b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 316708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 31687f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 316994d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 317096a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3171ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 317256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3173601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 317456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3175cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3176ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 31770898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3178c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 31799dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 31806c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 31812d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3182a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 318340cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3184dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3185dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3186052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3187fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3188fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3189fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 319051c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 31919e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 319217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3193f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 31940ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 31956c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3196b3469dd8SVivien Didelot }; 3197b3469dd8SVivien Didelot 3198b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = { 31994b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 320093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 320193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3202cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3203ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3204ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3205b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3206b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3207b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 320808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 32097f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3210a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 321196a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 3212ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 321356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3214601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 321556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3216cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3217ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 32180898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3219c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 32209dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 32216c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 32222d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3223a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 322440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3225dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3226dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3227052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3228fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3229fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3230fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 323151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 32329e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 323317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 32349e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 3235f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 32360ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 32376d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 32384382172fSAndrew Lunn .serdes_irq_setup = mv88e6352_serdes_irq_setup, 32394382172fSAndrew Lunn .serdes_irq_free = mv88e6352_serdes_irq_free, 3240a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 32416c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3242b3469dd8SVivien Didelot }; 3243b3469dd8SVivien Didelot 3244b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = { 32454b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 324693e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 324793e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3248b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 32497e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 32507e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 325108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 32527f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 325396a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 325456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 3255601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 3256ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 3257a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 325854186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 32596c422e34SRussell King .port_link_state = mv88e6185_port_link_state, 32602d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3261a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 326240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3263dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3264dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3265052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3266fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3267fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3268fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 326951c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 327002317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 3271a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 3272a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 327317e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3274f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 32750ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 32766c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3277b3469dd8SVivien Didelot }; 3278b3469dd8SVivien Didelot 32791a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = { 32804b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3281ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3282cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 328398fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 328498fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 32851a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 32861a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 32871a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 32881a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 32891a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 32901a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 32911a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 32927cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 3293ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 329456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3295601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 329656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 32970898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3298c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 32999dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 33006c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 33012d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3302fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 330379523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3304de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3305dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3306dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3307e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3308fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3309fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 331061303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 33116e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 33129e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 331317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 33149e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 3315931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3316931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 33176335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 3318efd1ba6aSAndrew Lunn .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3319efd1ba6aSAndrew Lunn .serdes_irq_free = mv88e6390_serdes_irq_free, 3320a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 33216c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 33221a3b39ecSAndrew Lunn }; 33231a3b39ecSAndrew Lunn 33241a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = { 33254b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3326ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3327cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 332898fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 332998fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 33301a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 33311a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 33321a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 33331a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 33341a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 33351a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 33361a3b39ecSAndrew Lunn .port_set_speed = mv88e6390x_port_set_speed, 33377cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 3338ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 333956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3340601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 334156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 33420898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3343c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 33449dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 33456c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 33462d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3347fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 334879523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3349de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3350dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3351dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3352e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3353fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3354fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 335561303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 33566e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 33579e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 335817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 33599e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 3360931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3361931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 336207ffbd74SAndrew Lunn .serdes_power = mv88e6390x_serdes_power, 33632defda1fSAndrew Lunn .serdes_irq_setup = mv88e6390x_serdes_irq_setup, 33642defda1fSAndrew Lunn .serdes_irq_free = mv88e6390x_serdes_irq_free, 3365a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 33666c422e34SRussell King .phylink_validate = mv88e6390x_phylink_validate, 33671a3b39ecSAndrew Lunn }; 33681a3b39ecSAndrew Lunn 33691a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = { 33704b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3371ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3372cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 337398fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 337498fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 33751a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 33761a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 33771a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 33781a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 33791a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 33801a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 33811a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 33827cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 3383ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 338456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3385601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 338656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 33870898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3388c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 33899dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 33906c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 33912d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3392fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 339379523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3394de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3395dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3396dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3397e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3398fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3399fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 340061303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 34016e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 34029e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 340317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 34049e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 3405931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3406931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 34076335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 3408efd1ba6aSAndrew Lunn .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3409efd1ba6aSAndrew Lunn .serdes_irq_free = mv88e6390_serdes_irq_free, 34106d2ac8eeSAndrew Lunn .avb_ops = &mv88e6390_avb_ops, 34116d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 34126c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 34131a3b39ecSAndrew Lunn }; 34141a3b39ecSAndrew Lunn 3415b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = { 34164b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 341793e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 341893e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3419cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3420ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3421ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3422b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3423b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3424b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 342508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 34267f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3427a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 342896a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 3429ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 343056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3431601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 343256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3433cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3434ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 34350898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3436c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 34379dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 34386c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 34392d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3440a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 344140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3442dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3443dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3444052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3445fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3446fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3447fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 344851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 34499e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 345017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 34519e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 3452f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 34530ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 34546d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 34554382172fSAndrew Lunn .serdes_irq_setup = mv88e6352_serdes_irq_setup, 34564382172fSAndrew Lunn .serdes_irq_free = mv88e6352_serdes_irq_free, 3457a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 34580d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 34596d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 34606c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3461b3469dd8SVivien Didelot }; 3462b3469dd8SVivien Didelot 34631f71836fSRasmus Villemoes static const struct mv88e6xxx_ops mv88e6250_ops = { 34641f71836fSRasmus Villemoes /* MV88E6XXX_FAMILY_6250 */ 34651f71836fSRasmus Villemoes .ieee_pri_map = mv88e6250_g1_ieee_pri_map, 34661f71836fSRasmus Villemoes .ip_pri_map = mv88e6085_g1_ip_pri_map, 34671f71836fSRasmus Villemoes .irl_init_all = mv88e6352_g2_irl_init_all, 34681f71836fSRasmus Villemoes .get_eeprom = mv88e6xxx_g2_get_eeprom16, 34691f71836fSRasmus Villemoes .set_eeprom = mv88e6xxx_g2_set_eeprom16, 34701f71836fSRasmus Villemoes .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 34711f71836fSRasmus Villemoes .phy_read = mv88e6xxx_g2_smi_phy_read, 34721f71836fSRasmus Villemoes .phy_write = mv88e6xxx_g2_smi_phy_write, 34731f71836fSRasmus Villemoes .port_set_link = mv88e6xxx_port_set_link, 34741f71836fSRasmus Villemoes .port_set_duplex = mv88e6xxx_port_set_duplex, 34751f71836fSRasmus Villemoes .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 34761f71836fSRasmus Villemoes .port_set_speed = mv88e6250_port_set_speed, 34771f71836fSRasmus Villemoes .port_tag_remap = mv88e6095_port_tag_remap, 34781f71836fSRasmus Villemoes .port_set_frame_mode = mv88e6351_port_set_frame_mode, 34791f71836fSRasmus Villemoes .port_set_egress_floods = mv88e6352_port_set_egress_floods, 34801f71836fSRasmus Villemoes .port_set_ether_type = mv88e6351_port_set_ether_type, 34811f71836fSRasmus Villemoes .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 34821f71836fSRasmus Villemoes .port_pause_limit = mv88e6097_port_pause_limit, 34831f71836fSRasmus Villemoes .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 34841f71836fSRasmus Villemoes .port_link_state = mv88e6250_port_link_state, 34851f71836fSRasmus Villemoes .stats_snapshot = mv88e6320_g1_stats_snapshot, 34861f71836fSRasmus Villemoes .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 34871f71836fSRasmus Villemoes .stats_get_sset_count = mv88e6250_stats_get_sset_count, 34881f71836fSRasmus Villemoes .stats_get_strings = mv88e6250_stats_get_strings, 34891f71836fSRasmus Villemoes .stats_get_stats = mv88e6250_stats_get_stats, 34901f71836fSRasmus Villemoes .set_cpu_port = mv88e6095_g1_set_cpu_port, 34911f71836fSRasmus Villemoes .set_egress_port = mv88e6095_g1_set_egress_port, 34921f71836fSRasmus Villemoes .watchdog_ops = &mv88e6250_watchdog_ops, 34931f71836fSRasmus Villemoes .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 34941f71836fSRasmus Villemoes .pot_clear = mv88e6xxx_g2_pot_clear, 34951f71836fSRasmus Villemoes .reset = mv88e6250_g1_reset, 34961f71836fSRasmus Villemoes .vtu_getnext = mv88e6250_g1_vtu_getnext, 34971f71836fSRasmus Villemoes .vtu_loadpurge = mv88e6250_g1_vtu_loadpurge, 34981f71836fSRasmus Villemoes .phylink_validate = mv88e6065_phylink_validate, 34991f71836fSRasmus Villemoes }; 35001f71836fSRasmus Villemoes 35011a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = { 35024b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3503ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3504cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 350598fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 350698fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 35071a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 35081a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 35091a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 35101a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 35111a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 35121a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 35131a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 35147cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 3515ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 351656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3517601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 351856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 35190898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3520c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 35219dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 35226c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 35232d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3524fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 352579523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3526de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3527dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3528dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3529e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3530fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3531fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 353261303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 35336e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 35349e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 353517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 35369e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 3537931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3538931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 35396335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 3540efd1ba6aSAndrew Lunn .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3541efd1ba6aSAndrew Lunn .serdes_irq_free = mv88e6390_serdes_irq_free, 3542a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 35430d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 35446d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 35456c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 35461a3b39ecSAndrew Lunn }; 35471a3b39ecSAndrew Lunn 3548b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = { 35494b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6320 */ 355093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 355193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3552cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3553ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3554ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3555b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3556b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3557b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 355808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 35597f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 356096a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3561ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 356256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3563601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 356456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3565cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3566ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 35670898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3568c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 35699dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 35706c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 35712d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3572a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 357340cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3574dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3575dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3576052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 3577fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3578fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 35799c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 358051c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 35819e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 358217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3583f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 35840ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 3585a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 35860d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 35876d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 35886c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3589b3469dd8SVivien Didelot }; 3590b3469dd8SVivien Didelot 3591b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = { 3592bd807204SVivien Didelot /* MV88E6XXX_FAMILY_6320 */ 359393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 359493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3595cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3596ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3597ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3598b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3599b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3600b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 360108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 36027f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 360396a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3604ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 360556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3606601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 360756995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3608cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3609ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 36100898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3611c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 36129dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 36136c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 36142d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3615a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 361640cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3617dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3618dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3619052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 3620fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3621fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 36229c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 362317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3624f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 36250ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 3626a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 36270d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 36286d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 36296c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3630b3469dd8SVivien Didelot }; 3631b3469dd8SVivien Didelot 363216e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = { 363316e329aeSVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 363493e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 363593e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3636cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 363716e329aeSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 363816e329aeSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 363916e329aeSVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 364016e329aeSVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 364116e329aeSVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 364216e329aeSVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 364316e329aeSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 364416e329aeSVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 364526422340SMarek Behún .port_set_speed = mv88e6341_port_set_speed, 36467cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6341_port_max_speed_mode, 364716e329aeSVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 364816e329aeSVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 364916e329aeSVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 365016e329aeSVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 3651cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 365216e329aeSVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 36530898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 365416e329aeSVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 365516e329aeSVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 36566c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 36572d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 365816e329aeSVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 365940cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 366016e329aeSVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 366116e329aeSVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 366216e329aeSVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 3663fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3664fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 366516e329aeSVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 366616e329aeSVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 36679e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 366816e329aeSVivien Didelot .reset = mv88e6352_g1_reset, 3669f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 36700ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 36716751e7c6SAndrew Lunn .serdes_power = mv88e6341_serdes_power, 3672a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 36730d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 36746d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 3675e3af71a3SMarek Behún .phylink_validate = mv88e6341_phylink_validate, 367616e329aeSVivien Didelot }; 367716e329aeSVivien Didelot 3678b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = { 36794b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 368093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 368193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3682cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3683b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3684b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3685b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 368608ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 36877f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 368894d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 368996a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3690ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 369156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3692601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 369356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3694cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3695ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 36960898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3697c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 36989dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 36996c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 37002d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3701a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 370240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3703dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3704dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3705052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3706fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3707fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3708fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 370951c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 37109e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 371117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3712f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 37130ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 37146c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3715b3469dd8SVivien Didelot }; 3716b3469dd8SVivien Didelot 3717b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = { 37184b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 371993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 372093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3721cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3722b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3723b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3724b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 372508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 37267f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 372794d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 372896a2b40cSVivien Didelot .port_set_speed = mv88e6185_port_set_speed, 3729ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 373056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3731601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 373256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3733cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3734ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 37350898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3736c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 37379dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 37386c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 37392d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3740a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 374140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3742dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3743dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3744052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3745fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3746fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3747fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 374851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 37499e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 375017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 3751f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 37520ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 37530d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 37546d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 37556c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3756b3469dd8SVivien Didelot }; 3757b3469dd8SVivien Didelot 3758b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = { 37594b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 376093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 376193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3762cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3763ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3764ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3765b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3766b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3767b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 376808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 37697f1ae07bSVivien Didelot .port_set_duplex = mv88e6xxx_port_set_duplex, 3770a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 377196a2b40cSVivien Didelot .port_set_speed = mv88e6352_port_set_speed, 3772ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 377356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3774601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 377556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3776cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3777ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 37780898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3779c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 37809dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 37816c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 37822d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3783a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 378440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3785dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3786dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3787052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3788fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3789fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3790fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 379151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 37929e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 379317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 37949e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 3795f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 37960ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 37976d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 37984382172fSAndrew Lunn .serdes_irq_setup = mv88e6352_serdes_irq_setup, 37994382172fSAndrew Lunn .serdes_irq_free = mv88e6352_serdes_irq_free, 3800a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 38010d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 38026d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 3803cda9f4aaSAndrew Lunn .serdes_get_sset_count = mv88e6352_serdes_get_sset_count, 3804cda9f4aaSAndrew Lunn .serdes_get_strings = mv88e6352_serdes_get_strings, 3805cda9f4aaSAndrew Lunn .serdes_get_stats = mv88e6352_serdes_get_stats, 38066c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3807b3469dd8SVivien Didelot }; 3808b3469dd8SVivien Didelot 38091a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = { 38104b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3811ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3812cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 381398fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 381498fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 38151a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 38161a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 38171a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 38181a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 38191a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 38201a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 38211a3b39ecSAndrew Lunn .port_set_speed = mv88e6390_port_set_speed, 38227cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 3823ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 382456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3825601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 382656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3827cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3828ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 38290898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3830c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 38319dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 38326c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 38332d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3834fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 383579523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3836de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3837dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3838dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3839e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3840fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3841fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 384261303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 38436e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 38449e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 384517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 38469e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 3847931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3848931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 38496335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 3850efd1ba6aSAndrew Lunn .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3851efd1ba6aSAndrew Lunn .serdes_irq_free = mv88e6390_serdes_irq_free, 3852a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 38530d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 38546d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 38556c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 38561a3b39ecSAndrew Lunn }; 38571a3b39ecSAndrew Lunn 38581a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = { 38594b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3860ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3861cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 386298fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 386398fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 38641a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 38651a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 38661a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 38671a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 38681a3b39ecSAndrew Lunn .port_set_duplex = mv88e6xxx_port_set_duplex, 38691a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 38701a3b39ecSAndrew Lunn .port_set_speed = mv88e6390x_port_set_speed, 38717cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 3872ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 387356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3874601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 387556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3876cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3877ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 38780898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3879c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 38809dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 38816c422e34SRussell King .port_link_state = mv88e6352_port_link_state, 38822d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3883b3dce4daSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 388479523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3885de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3886dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3887dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3888e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3889fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3890fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 389161303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 38926e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 38939e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 389417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 38959e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 3896931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3897931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 389807ffbd74SAndrew Lunn .serdes_power = mv88e6390x_serdes_power, 38992defda1fSAndrew Lunn .serdes_irq_setup = mv88e6390x_serdes_irq_setup, 39002defda1fSAndrew Lunn .serdes_irq_free = mv88e6390x_serdes_irq_free, 3901a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 39020d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 39036d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 39046c422e34SRussell King .phylink_validate = mv88e6390x_phylink_validate, 39051a3b39ecSAndrew Lunn }; 39061a3b39ecSAndrew Lunn 3907fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = { 3908fad09c73SVivien Didelot [MV88E6085] = { 3909107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085, 3910fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6097, 3911fad09c73SVivien Didelot .name = "Marvell 88E6085", 3912fad09c73SVivien Didelot .num_databases = 4096, 3913fad09c73SVivien Didelot .num_ports = 10, 3914bc393155SAndrew Lunn .num_internal_phys = 5, 39153cf3c846SVivien Didelot .max_vid = 4095, 3916fad09c73SVivien Didelot .port_base_addr = 0x10, 39179255bacdSAndrew Lunn .phy_base_addr = 0x0, 3918a935c052SVivien Didelot .global1_addr = 0x1b, 39199069c13aSVivien Didelot .global2_addr = 0x1c, 3920acddbd21SVivien Didelot .age_time_coeff = 15000, 3921dc30c35bSAndrew Lunn .g1_irqs = 8, 3922d6c5e6afSVivien Didelot .g2_irqs = 10, 3923e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3924f3645652SVivien Didelot .pvt = true, 3925b3e05aa1SVivien Didelot .multi_chip = true, 3926443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3927b3469dd8SVivien Didelot .ops = &mv88e6085_ops, 3928fad09c73SVivien Didelot }, 3929fad09c73SVivien Didelot 3930fad09c73SVivien Didelot [MV88E6095] = { 3931107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095, 3932fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6095, 3933fad09c73SVivien Didelot .name = "Marvell 88E6095/88E6095F", 3934fad09c73SVivien Didelot .num_databases = 256, 3935fad09c73SVivien Didelot .num_ports = 11, 3936bc393155SAndrew Lunn .num_internal_phys = 0, 39373cf3c846SVivien Didelot .max_vid = 4095, 3938fad09c73SVivien Didelot .port_base_addr = 0x10, 39399255bacdSAndrew Lunn .phy_base_addr = 0x0, 3940a935c052SVivien Didelot .global1_addr = 0x1b, 39419069c13aSVivien Didelot .global2_addr = 0x1c, 3942acddbd21SVivien Didelot .age_time_coeff = 15000, 3943dc30c35bSAndrew Lunn .g1_irqs = 8, 3944e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3945b3e05aa1SVivien Didelot .multi_chip = true, 3946443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 3947b3469dd8SVivien Didelot .ops = &mv88e6095_ops, 3948fad09c73SVivien Didelot }, 3949fad09c73SVivien Didelot 39507d381a02SStefan Eichenberger [MV88E6097] = { 3951107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097, 39527d381a02SStefan Eichenberger .family = MV88E6XXX_FAMILY_6097, 39537d381a02SStefan Eichenberger .name = "Marvell 88E6097/88E6097F", 39547d381a02SStefan Eichenberger .num_databases = 4096, 39557d381a02SStefan Eichenberger .num_ports = 11, 3956bc393155SAndrew Lunn .num_internal_phys = 8, 39573cf3c846SVivien Didelot .max_vid = 4095, 39587d381a02SStefan Eichenberger .port_base_addr = 0x10, 39599255bacdSAndrew Lunn .phy_base_addr = 0x0, 39607d381a02SStefan Eichenberger .global1_addr = 0x1b, 39619069c13aSVivien Didelot .global2_addr = 0x1c, 39627d381a02SStefan Eichenberger .age_time_coeff = 15000, 3963c534178bSStefan Eichenberger .g1_irqs = 8, 3964d6c5e6afSVivien Didelot .g2_irqs = 10, 3965e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3966f3645652SVivien Didelot .pvt = true, 3967b3e05aa1SVivien Didelot .multi_chip = true, 39682bfcfcd3SStefan Eichenberger .tag_protocol = DSA_TAG_PROTO_EDSA, 39697d381a02SStefan Eichenberger .ops = &mv88e6097_ops, 39707d381a02SStefan Eichenberger }, 39717d381a02SStefan Eichenberger 3972fad09c73SVivien Didelot [MV88E6123] = { 3973107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123, 3974fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 3975fad09c73SVivien Didelot .name = "Marvell 88E6123", 3976fad09c73SVivien Didelot .num_databases = 4096, 3977fad09c73SVivien Didelot .num_ports = 3, 3978bc393155SAndrew Lunn .num_internal_phys = 5, 39793cf3c846SVivien Didelot .max_vid = 4095, 3980fad09c73SVivien Didelot .port_base_addr = 0x10, 39819255bacdSAndrew Lunn .phy_base_addr = 0x0, 3982a935c052SVivien Didelot .global1_addr = 0x1b, 39839069c13aSVivien Didelot .global2_addr = 0x1c, 3984acddbd21SVivien Didelot .age_time_coeff = 15000, 3985dc30c35bSAndrew Lunn .g1_irqs = 9, 3986d6c5e6afSVivien Didelot .g2_irqs = 10, 3987e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 3988f3645652SVivien Didelot .pvt = true, 3989b3e05aa1SVivien Didelot .multi_chip = true, 39905ebe31d7SAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 3991b3469dd8SVivien Didelot .ops = &mv88e6123_ops, 3992fad09c73SVivien Didelot }, 3993fad09c73SVivien Didelot 3994fad09c73SVivien Didelot [MV88E6131] = { 3995107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131, 3996fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 3997fad09c73SVivien Didelot .name = "Marvell 88E6131", 3998fad09c73SVivien Didelot .num_databases = 256, 3999fad09c73SVivien Didelot .num_ports = 8, 4000bc393155SAndrew Lunn .num_internal_phys = 0, 40013cf3c846SVivien Didelot .max_vid = 4095, 4002fad09c73SVivien Didelot .port_base_addr = 0x10, 40039255bacdSAndrew Lunn .phy_base_addr = 0x0, 4004a935c052SVivien Didelot .global1_addr = 0x1b, 40059069c13aSVivien Didelot .global2_addr = 0x1c, 4006acddbd21SVivien Didelot .age_time_coeff = 15000, 4007dc30c35bSAndrew Lunn .g1_irqs = 9, 4008e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4009b3e05aa1SVivien Didelot .multi_chip = true, 4010443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4011b3469dd8SVivien Didelot .ops = &mv88e6131_ops, 4012fad09c73SVivien Didelot }, 4013fad09c73SVivien Didelot 4014990e27b0SVivien Didelot [MV88E6141] = { 4015107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141, 4016990e27b0SVivien Didelot .family = MV88E6XXX_FAMILY_6341, 401779a68b26SUwe Kleine-König .name = "Marvell 88E6141", 4018990e27b0SVivien Didelot .num_databases = 4096, 4019990e27b0SVivien Didelot .num_ports = 6, 4020bc393155SAndrew Lunn .num_internal_phys = 5, 4021a73ccd61SBrandon Streiff .num_gpio = 11, 40223cf3c846SVivien Didelot .max_vid = 4095, 4023990e27b0SVivien Didelot .port_base_addr = 0x10, 40249255bacdSAndrew Lunn .phy_base_addr = 0x10, 4025990e27b0SVivien Didelot .global1_addr = 0x1b, 40269069c13aSVivien Didelot .global2_addr = 0x1c, 4027990e27b0SVivien Didelot .age_time_coeff = 3750, 4028990e27b0SVivien Didelot .atu_move_port_mask = 0x1f, 4029adfccf11SAndrew Lunn .g1_irqs = 9, 4030d6c5e6afSVivien Didelot .g2_irqs = 10, 4031f3645652SVivien Didelot .pvt = true, 4032b3e05aa1SVivien Didelot .multi_chip = true, 4033990e27b0SVivien Didelot .tag_protocol = DSA_TAG_PROTO_EDSA, 4034990e27b0SVivien Didelot .ops = &mv88e6141_ops, 4035990e27b0SVivien Didelot }, 4036990e27b0SVivien Didelot 4037fad09c73SVivien Didelot [MV88E6161] = { 4038107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161, 4039fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4040fad09c73SVivien Didelot .name = "Marvell 88E6161", 4041fad09c73SVivien Didelot .num_databases = 4096, 4042fad09c73SVivien Didelot .num_ports = 6, 4043bc393155SAndrew Lunn .num_internal_phys = 5, 40443cf3c846SVivien Didelot .max_vid = 4095, 4045fad09c73SVivien Didelot .port_base_addr = 0x10, 40469255bacdSAndrew Lunn .phy_base_addr = 0x0, 4047a935c052SVivien Didelot .global1_addr = 0x1b, 40489069c13aSVivien Didelot .global2_addr = 0x1c, 4049acddbd21SVivien Didelot .age_time_coeff = 15000, 4050dc30c35bSAndrew Lunn .g1_irqs = 9, 4051d6c5e6afSVivien Didelot .g2_irqs = 10, 4052e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4053f3645652SVivien Didelot .pvt = true, 4054b3e05aa1SVivien Didelot .multi_chip = true, 40555ebe31d7SAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4056dfa54348SAndrew Lunn .ptp_support = true, 4057b3469dd8SVivien Didelot .ops = &mv88e6161_ops, 4058fad09c73SVivien Didelot }, 4059fad09c73SVivien Didelot 4060fad09c73SVivien Didelot [MV88E6165] = { 4061107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165, 4062fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4063fad09c73SVivien Didelot .name = "Marvell 88E6165", 4064fad09c73SVivien Didelot .num_databases = 4096, 4065fad09c73SVivien Didelot .num_ports = 6, 4066bc393155SAndrew Lunn .num_internal_phys = 0, 40673cf3c846SVivien Didelot .max_vid = 4095, 4068fad09c73SVivien Didelot .port_base_addr = 0x10, 40699255bacdSAndrew Lunn .phy_base_addr = 0x0, 4070a935c052SVivien Didelot .global1_addr = 0x1b, 40719069c13aSVivien Didelot .global2_addr = 0x1c, 4072acddbd21SVivien Didelot .age_time_coeff = 15000, 4073dc30c35bSAndrew Lunn .g1_irqs = 9, 4074d6c5e6afSVivien Didelot .g2_irqs = 10, 4075e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4076f3645652SVivien Didelot .pvt = true, 4077b3e05aa1SVivien Didelot .multi_chip = true, 4078443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4079dfa54348SAndrew Lunn .ptp_support = true, 4080b3469dd8SVivien Didelot .ops = &mv88e6165_ops, 4081fad09c73SVivien Didelot }, 4082fad09c73SVivien Didelot 4083fad09c73SVivien Didelot [MV88E6171] = { 4084107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171, 4085fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4086fad09c73SVivien Didelot .name = "Marvell 88E6171", 4087fad09c73SVivien Didelot .num_databases = 4096, 4088fad09c73SVivien Didelot .num_ports = 7, 4089bc393155SAndrew Lunn .num_internal_phys = 5, 40903cf3c846SVivien Didelot .max_vid = 4095, 4091fad09c73SVivien Didelot .port_base_addr = 0x10, 40929255bacdSAndrew Lunn .phy_base_addr = 0x0, 4093a935c052SVivien Didelot .global1_addr = 0x1b, 40949069c13aSVivien Didelot .global2_addr = 0x1c, 4095acddbd21SVivien Didelot .age_time_coeff = 15000, 4096dc30c35bSAndrew Lunn .g1_irqs = 9, 4097d6c5e6afSVivien Didelot .g2_irqs = 10, 4098e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4099f3645652SVivien Didelot .pvt = true, 4100b3e05aa1SVivien Didelot .multi_chip = true, 4101443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4102b3469dd8SVivien Didelot .ops = &mv88e6171_ops, 4103fad09c73SVivien Didelot }, 4104fad09c73SVivien Didelot 4105fad09c73SVivien Didelot [MV88E6172] = { 4106107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172, 4107fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4108fad09c73SVivien Didelot .name = "Marvell 88E6172", 4109fad09c73SVivien Didelot .num_databases = 4096, 4110fad09c73SVivien Didelot .num_ports = 7, 4111bc393155SAndrew Lunn .num_internal_phys = 5, 4112a73ccd61SBrandon Streiff .num_gpio = 15, 41133cf3c846SVivien Didelot .max_vid = 4095, 4114fad09c73SVivien Didelot .port_base_addr = 0x10, 41159255bacdSAndrew Lunn .phy_base_addr = 0x0, 4116a935c052SVivien Didelot .global1_addr = 0x1b, 41179069c13aSVivien Didelot .global2_addr = 0x1c, 4118acddbd21SVivien Didelot .age_time_coeff = 15000, 4119dc30c35bSAndrew Lunn .g1_irqs = 9, 4120d6c5e6afSVivien Didelot .g2_irqs = 10, 4121e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4122f3645652SVivien Didelot .pvt = true, 4123b3e05aa1SVivien Didelot .multi_chip = true, 4124443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4125b3469dd8SVivien Didelot .ops = &mv88e6172_ops, 4126fad09c73SVivien Didelot }, 4127fad09c73SVivien Didelot 4128fad09c73SVivien Didelot [MV88E6175] = { 4129107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175, 4130fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4131fad09c73SVivien Didelot .name = "Marvell 88E6175", 4132fad09c73SVivien Didelot .num_databases = 4096, 4133fad09c73SVivien Didelot .num_ports = 7, 4134bc393155SAndrew Lunn .num_internal_phys = 5, 41353cf3c846SVivien Didelot .max_vid = 4095, 4136fad09c73SVivien Didelot .port_base_addr = 0x10, 41379255bacdSAndrew Lunn .phy_base_addr = 0x0, 4138a935c052SVivien Didelot .global1_addr = 0x1b, 41399069c13aSVivien Didelot .global2_addr = 0x1c, 4140acddbd21SVivien Didelot .age_time_coeff = 15000, 4141dc30c35bSAndrew Lunn .g1_irqs = 9, 4142d6c5e6afSVivien Didelot .g2_irqs = 10, 4143e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4144f3645652SVivien Didelot .pvt = true, 4145b3e05aa1SVivien Didelot .multi_chip = true, 4146443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4147b3469dd8SVivien Didelot .ops = &mv88e6175_ops, 4148fad09c73SVivien Didelot }, 4149fad09c73SVivien Didelot 4150fad09c73SVivien Didelot [MV88E6176] = { 4151107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176, 4152fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4153fad09c73SVivien Didelot .name = "Marvell 88E6176", 4154fad09c73SVivien Didelot .num_databases = 4096, 4155fad09c73SVivien Didelot .num_ports = 7, 4156bc393155SAndrew Lunn .num_internal_phys = 5, 4157a73ccd61SBrandon Streiff .num_gpio = 15, 41583cf3c846SVivien Didelot .max_vid = 4095, 4159fad09c73SVivien Didelot .port_base_addr = 0x10, 41609255bacdSAndrew Lunn .phy_base_addr = 0x0, 4161a935c052SVivien Didelot .global1_addr = 0x1b, 41629069c13aSVivien Didelot .global2_addr = 0x1c, 4163acddbd21SVivien Didelot .age_time_coeff = 15000, 4164dc30c35bSAndrew Lunn .g1_irqs = 9, 4165d6c5e6afSVivien Didelot .g2_irqs = 10, 4166e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4167f3645652SVivien Didelot .pvt = true, 4168b3e05aa1SVivien Didelot .multi_chip = true, 4169443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4170b3469dd8SVivien Didelot .ops = &mv88e6176_ops, 4171fad09c73SVivien Didelot }, 4172fad09c73SVivien Didelot 4173fad09c73SVivien Didelot [MV88E6185] = { 4174107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185, 4175fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 4176fad09c73SVivien Didelot .name = "Marvell 88E6185", 4177fad09c73SVivien Didelot .num_databases = 256, 4178fad09c73SVivien Didelot .num_ports = 10, 4179bc393155SAndrew Lunn .num_internal_phys = 0, 41803cf3c846SVivien Didelot .max_vid = 4095, 4181fad09c73SVivien Didelot .port_base_addr = 0x10, 41829255bacdSAndrew Lunn .phy_base_addr = 0x0, 4183a935c052SVivien Didelot .global1_addr = 0x1b, 41849069c13aSVivien Didelot .global2_addr = 0x1c, 4185acddbd21SVivien Didelot .age_time_coeff = 15000, 4186dc30c35bSAndrew Lunn .g1_irqs = 8, 4187e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4188b3e05aa1SVivien Didelot .multi_chip = true, 4189443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4190b3469dd8SVivien Didelot .ops = &mv88e6185_ops, 4191fad09c73SVivien Didelot }, 4192fad09c73SVivien Didelot 41931a3b39ecSAndrew Lunn [MV88E6190] = { 4194107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190, 41951a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 41961a3b39ecSAndrew Lunn .name = "Marvell 88E6190", 41971a3b39ecSAndrew Lunn .num_databases = 4096, 41981a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 419995150f29SHeiner Kallweit .num_internal_phys = 9, 4200a73ccd61SBrandon Streiff .num_gpio = 16, 4201931d1822SVivien Didelot .max_vid = 8191, 42021a3b39ecSAndrew Lunn .port_base_addr = 0x0, 42039255bacdSAndrew Lunn .phy_base_addr = 0x0, 42041a3b39ecSAndrew Lunn .global1_addr = 0x1b, 42059069c13aSVivien Didelot .global2_addr = 0x1c, 4206443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4207b91e055cSAndrew Lunn .age_time_coeff = 3750, 42081a3b39ecSAndrew Lunn .g1_irqs = 9, 4209d6c5e6afSVivien Didelot .g2_irqs = 14, 4210f3645652SVivien Didelot .pvt = true, 4211b3e05aa1SVivien Didelot .multi_chip = true, 4212e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 42131a3b39ecSAndrew Lunn .ops = &mv88e6190_ops, 42141a3b39ecSAndrew Lunn }, 42151a3b39ecSAndrew Lunn 42161a3b39ecSAndrew Lunn [MV88E6190X] = { 4217107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X, 42181a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 42191a3b39ecSAndrew Lunn .name = "Marvell 88E6190X", 42201a3b39ecSAndrew Lunn .num_databases = 4096, 42211a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 422295150f29SHeiner Kallweit .num_internal_phys = 9, 4223a73ccd61SBrandon Streiff .num_gpio = 16, 4224931d1822SVivien Didelot .max_vid = 8191, 42251a3b39ecSAndrew Lunn .port_base_addr = 0x0, 42269255bacdSAndrew Lunn .phy_base_addr = 0x0, 42271a3b39ecSAndrew Lunn .global1_addr = 0x1b, 42289069c13aSVivien Didelot .global2_addr = 0x1c, 4229b91e055cSAndrew Lunn .age_time_coeff = 3750, 42301a3b39ecSAndrew Lunn .g1_irqs = 9, 4231d6c5e6afSVivien Didelot .g2_irqs = 14, 4232e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4233f3645652SVivien Didelot .pvt = true, 4234b3e05aa1SVivien Didelot .multi_chip = true, 4235443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 42361a3b39ecSAndrew Lunn .ops = &mv88e6190x_ops, 42371a3b39ecSAndrew Lunn }, 42381a3b39ecSAndrew Lunn 42391a3b39ecSAndrew Lunn [MV88E6191] = { 4240107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191, 42411a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 42421a3b39ecSAndrew Lunn .name = "Marvell 88E6191", 42431a3b39ecSAndrew Lunn .num_databases = 4096, 42441a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 424595150f29SHeiner Kallweit .num_internal_phys = 9, 4246931d1822SVivien Didelot .max_vid = 8191, 42471a3b39ecSAndrew Lunn .port_base_addr = 0x0, 42489255bacdSAndrew Lunn .phy_base_addr = 0x0, 42491a3b39ecSAndrew Lunn .global1_addr = 0x1b, 42509069c13aSVivien Didelot .global2_addr = 0x1c, 4251b91e055cSAndrew Lunn .age_time_coeff = 3750, 4252443d5a1bSAndrew Lunn .g1_irqs = 9, 4253d6c5e6afSVivien Didelot .g2_irqs = 14, 4254e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4255f3645652SVivien Didelot .pvt = true, 4256b3e05aa1SVivien Didelot .multi_chip = true, 4257443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 42582fa8d3afSBrandon Streiff .ptp_support = true, 42592cf4cefbSVivien Didelot .ops = &mv88e6191_ops, 42601a3b39ecSAndrew Lunn }, 42611a3b39ecSAndrew Lunn 4262fad09c73SVivien Didelot [MV88E6240] = { 4263107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240, 4264fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4265fad09c73SVivien Didelot .name = "Marvell 88E6240", 4266fad09c73SVivien Didelot .num_databases = 4096, 4267fad09c73SVivien Didelot .num_ports = 7, 4268bc393155SAndrew Lunn .num_internal_phys = 5, 4269a73ccd61SBrandon Streiff .num_gpio = 15, 42703cf3c846SVivien Didelot .max_vid = 4095, 4271fad09c73SVivien Didelot .port_base_addr = 0x10, 42729255bacdSAndrew Lunn .phy_base_addr = 0x0, 4273a935c052SVivien Didelot .global1_addr = 0x1b, 42749069c13aSVivien Didelot .global2_addr = 0x1c, 4275acddbd21SVivien Didelot .age_time_coeff = 15000, 4276dc30c35bSAndrew Lunn .g1_irqs = 9, 4277d6c5e6afSVivien Didelot .g2_irqs = 10, 4278e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4279f3645652SVivien Didelot .pvt = true, 4280b3e05aa1SVivien Didelot .multi_chip = true, 4281443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 42822fa8d3afSBrandon Streiff .ptp_support = true, 4283b3469dd8SVivien Didelot .ops = &mv88e6240_ops, 4284fad09c73SVivien Didelot }, 4285fad09c73SVivien Didelot 42861f71836fSRasmus Villemoes [MV88E6250] = { 42871f71836fSRasmus Villemoes .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250, 42881f71836fSRasmus Villemoes .family = MV88E6XXX_FAMILY_6250, 42891f71836fSRasmus Villemoes .name = "Marvell 88E6250", 42901f71836fSRasmus Villemoes .num_databases = 64, 42911f71836fSRasmus Villemoes .num_ports = 7, 42921f71836fSRasmus Villemoes .num_internal_phys = 5, 42931f71836fSRasmus Villemoes .max_vid = 4095, 42941f71836fSRasmus Villemoes .port_base_addr = 0x08, 42951f71836fSRasmus Villemoes .phy_base_addr = 0x00, 42961f71836fSRasmus Villemoes .global1_addr = 0x0f, 42971f71836fSRasmus Villemoes .global2_addr = 0x07, 42981f71836fSRasmus Villemoes .age_time_coeff = 15000, 42991f71836fSRasmus Villemoes .g1_irqs = 9, 43001f71836fSRasmus Villemoes .g2_irqs = 10, 43011f71836fSRasmus Villemoes .atu_move_port_mask = 0xf, 43021f71836fSRasmus Villemoes .dual_chip = true, 43031f71836fSRasmus Villemoes .tag_protocol = DSA_TAG_PROTO_DSA, 43041f71836fSRasmus Villemoes .ops = &mv88e6250_ops, 43051f71836fSRasmus Villemoes }, 43061f71836fSRasmus Villemoes 43071a3b39ecSAndrew Lunn [MV88E6290] = { 4308107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290, 43091a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 43101a3b39ecSAndrew Lunn .name = "Marvell 88E6290", 43111a3b39ecSAndrew Lunn .num_databases = 4096, 43121a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 431395150f29SHeiner Kallweit .num_internal_phys = 9, 4314a73ccd61SBrandon Streiff .num_gpio = 16, 4315931d1822SVivien Didelot .max_vid = 8191, 43161a3b39ecSAndrew Lunn .port_base_addr = 0x0, 43179255bacdSAndrew Lunn .phy_base_addr = 0x0, 43181a3b39ecSAndrew Lunn .global1_addr = 0x1b, 43199069c13aSVivien Didelot .global2_addr = 0x1c, 4320b91e055cSAndrew Lunn .age_time_coeff = 3750, 43211a3b39ecSAndrew Lunn .g1_irqs = 9, 4322d6c5e6afSVivien Didelot .g2_irqs = 14, 4323e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4324f3645652SVivien Didelot .pvt = true, 4325b3e05aa1SVivien Didelot .multi_chip = true, 4326443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 43272fa8d3afSBrandon Streiff .ptp_support = true, 43281a3b39ecSAndrew Lunn .ops = &mv88e6290_ops, 43291a3b39ecSAndrew Lunn }, 43301a3b39ecSAndrew Lunn 4331fad09c73SVivien Didelot [MV88E6320] = { 4332107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320, 4333fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 4334fad09c73SVivien Didelot .name = "Marvell 88E6320", 4335fad09c73SVivien Didelot .num_databases = 4096, 4336fad09c73SVivien Didelot .num_ports = 7, 4337bc393155SAndrew Lunn .num_internal_phys = 5, 4338a73ccd61SBrandon Streiff .num_gpio = 15, 43393cf3c846SVivien Didelot .max_vid = 4095, 4340fad09c73SVivien Didelot .port_base_addr = 0x10, 43419255bacdSAndrew Lunn .phy_base_addr = 0x0, 4342a935c052SVivien Didelot .global1_addr = 0x1b, 43439069c13aSVivien Didelot .global2_addr = 0x1c, 4344acddbd21SVivien Didelot .age_time_coeff = 15000, 4345dc30c35bSAndrew Lunn .g1_irqs = 8, 4346bc393155SAndrew Lunn .g2_irqs = 10, 4347e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4348f3645652SVivien Didelot .pvt = true, 4349b3e05aa1SVivien Didelot .multi_chip = true, 4350443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 43512fa8d3afSBrandon Streiff .ptp_support = true, 4352b3469dd8SVivien Didelot .ops = &mv88e6320_ops, 4353fad09c73SVivien Didelot }, 4354fad09c73SVivien Didelot 4355fad09c73SVivien Didelot [MV88E6321] = { 4356107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321, 4357fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 4358fad09c73SVivien Didelot .name = "Marvell 88E6321", 4359fad09c73SVivien Didelot .num_databases = 4096, 4360fad09c73SVivien Didelot .num_ports = 7, 4361bc393155SAndrew Lunn .num_internal_phys = 5, 4362a73ccd61SBrandon Streiff .num_gpio = 15, 43633cf3c846SVivien Didelot .max_vid = 4095, 4364fad09c73SVivien Didelot .port_base_addr = 0x10, 43659255bacdSAndrew Lunn .phy_base_addr = 0x0, 4366a935c052SVivien Didelot .global1_addr = 0x1b, 43679069c13aSVivien Didelot .global2_addr = 0x1c, 4368acddbd21SVivien Didelot .age_time_coeff = 15000, 4369dc30c35bSAndrew Lunn .g1_irqs = 8, 4370bc393155SAndrew Lunn .g2_irqs = 10, 4371e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4372b3e05aa1SVivien Didelot .multi_chip = true, 4373443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 43742fa8d3afSBrandon Streiff .ptp_support = true, 4375b3469dd8SVivien Didelot .ops = &mv88e6321_ops, 4376fad09c73SVivien Didelot }, 4377fad09c73SVivien Didelot 4378a75961d0SGregory CLEMENT [MV88E6341] = { 4379107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, 4380a75961d0SGregory CLEMENT .family = MV88E6XXX_FAMILY_6341, 4381a75961d0SGregory CLEMENT .name = "Marvell 88E6341", 4382a75961d0SGregory CLEMENT .num_databases = 4096, 4383bc393155SAndrew Lunn .num_internal_phys = 5, 4384a75961d0SGregory CLEMENT .num_ports = 6, 4385a73ccd61SBrandon Streiff .num_gpio = 11, 43863cf3c846SVivien Didelot .max_vid = 4095, 4387a75961d0SGregory CLEMENT .port_base_addr = 0x10, 43889255bacdSAndrew Lunn .phy_base_addr = 0x10, 4389a75961d0SGregory CLEMENT .global1_addr = 0x1b, 43909069c13aSVivien Didelot .global2_addr = 0x1c, 4391a75961d0SGregory CLEMENT .age_time_coeff = 3750, 4392e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4393adfccf11SAndrew Lunn .g1_irqs = 9, 4394d6c5e6afSVivien Didelot .g2_irqs = 10, 4395f3645652SVivien Didelot .pvt = true, 4396b3e05aa1SVivien Didelot .multi_chip = true, 4397a75961d0SGregory CLEMENT .tag_protocol = DSA_TAG_PROTO_EDSA, 43982fa8d3afSBrandon Streiff .ptp_support = true, 4399a75961d0SGregory CLEMENT .ops = &mv88e6341_ops, 4400a75961d0SGregory CLEMENT }, 4401a75961d0SGregory CLEMENT 4402fad09c73SVivien Didelot [MV88E6350] = { 4403107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350, 4404fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4405fad09c73SVivien Didelot .name = "Marvell 88E6350", 4406fad09c73SVivien Didelot .num_databases = 4096, 4407fad09c73SVivien Didelot .num_ports = 7, 4408bc393155SAndrew Lunn .num_internal_phys = 5, 44093cf3c846SVivien Didelot .max_vid = 4095, 4410fad09c73SVivien Didelot .port_base_addr = 0x10, 44119255bacdSAndrew Lunn .phy_base_addr = 0x0, 4412a935c052SVivien Didelot .global1_addr = 0x1b, 44139069c13aSVivien Didelot .global2_addr = 0x1c, 4414acddbd21SVivien Didelot .age_time_coeff = 15000, 4415dc30c35bSAndrew Lunn .g1_irqs = 9, 4416d6c5e6afSVivien Didelot .g2_irqs = 10, 4417e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4418f3645652SVivien Didelot .pvt = true, 4419b3e05aa1SVivien Didelot .multi_chip = true, 4420443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4421b3469dd8SVivien Didelot .ops = &mv88e6350_ops, 4422fad09c73SVivien Didelot }, 4423fad09c73SVivien Didelot 4424fad09c73SVivien Didelot [MV88E6351] = { 4425107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351, 4426fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4427fad09c73SVivien Didelot .name = "Marvell 88E6351", 4428fad09c73SVivien Didelot .num_databases = 4096, 4429fad09c73SVivien Didelot .num_ports = 7, 4430bc393155SAndrew Lunn .num_internal_phys = 5, 44313cf3c846SVivien Didelot .max_vid = 4095, 4432fad09c73SVivien Didelot .port_base_addr = 0x10, 44339255bacdSAndrew Lunn .phy_base_addr = 0x0, 4434a935c052SVivien Didelot .global1_addr = 0x1b, 44359069c13aSVivien Didelot .global2_addr = 0x1c, 4436acddbd21SVivien Didelot .age_time_coeff = 15000, 4437dc30c35bSAndrew Lunn .g1_irqs = 9, 4438d6c5e6afSVivien Didelot .g2_irqs = 10, 4439e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4440f3645652SVivien Didelot .pvt = true, 4441b3e05aa1SVivien Didelot .multi_chip = true, 4442443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4443b3469dd8SVivien Didelot .ops = &mv88e6351_ops, 4444fad09c73SVivien Didelot }, 4445fad09c73SVivien Didelot 4446fad09c73SVivien Didelot [MV88E6352] = { 4447107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352, 4448fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4449fad09c73SVivien Didelot .name = "Marvell 88E6352", 4450fad09c73SVivien Didelot .num_databases = 4096, 4451fad09c73SVivien Didelot .num_ports = 7, 4452bc393155SAndrew Lunn .num_internal_phys = 5, 4453a73ccd61SBrandon Streiff .num_gpio = 15, 44543cf3c846SVivien Didelot .max_vid = 4095, 4455fad09c73SVivien Didelot .port_base_addr = 0x10, 44569255bacdSAndrew Lunn .phy_base_addr = 0x0, 4457a935c052SVivien Didelot .global1_addr = 0x1b, 44589069c13aSVivien Didelot .global2_addr = 0x1c, 4459acddbd21SVivien Didelot .age_time_coeff = 15000, 4460dc30c35bSAndrew Lunn .g1_irqs = 9, 4461d6c5e6afSVivien Didelot .g2_irqs = 10, 4462e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4463f3645652SVivien Didelot .pvt = true, 4464b3e05aa1SVivien Didelot .multi_chip = true, 4465443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 44662fa8d3afSBrandon Streiff .ptp_support = true, 4467b3469dd8SVivien Didelot .ops = &mv88e6352_ops, 4468fad09c73SVivien Didelot }, 44691a3b39ecSAndrew Lunn [MV88E6390] = { 4470107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, 44711a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 44721a3b39ecSAndrew Lunn .name = "Marvell 88E6390", 44731a3b39ecSAndrew Lunn .num_databases = 4096, 44741a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 447595150f29SHeiner Kallweit .num_internal_phys = 9, 4476a73ccd61SBrandon Streiff .num_gpio = 16, 4477931d1822SVivien Didelot .max_vid = 8191, 44781a3b39ecSAndrew Lunn .port_base_addr = 0x0, 44799255bacdSAndrew Lunn .phy_base_addr = 0x0, 44801a3b39ecSAndrew Lunn .global1_addr = 0x1b, 44819069c13aSVivien Didelot .global2_addr = 0x1c, 4482b91e055cSAndrew Lunn .age_time_coeff = 3750, 44831a3b39ecSAndrew Lunn .g1_irqs = 9, 4484d6c5e6afSVivien Didelot .g2_irqs = 14, 4485e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4486f3645652SVivien Didelot .pvt = true, 4487b3e05aa1SVivien Didelot .multi_chip = true, 4488443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 44892fa8d3afSBrandon Streiff .ptp_support = true, 44901a3b39ecSAndrew Lunn .ops = &mv88e6390_ops, 44911a3b39ecSAndrew Lunn }, 44921a3b39ecSAndrew Lunn [MV88E6390X] = { 4493107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X, 44941a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 44951a3b39ecSAndrew Lunn .name = "Marvell 88E6390X", 44961a3b39ecSAndrew Lunn .num_databases = 4096, 44971a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 449895150f29SHeiner Kallweit .num_internal_phys = 9, 4499a73ccd61SBrandon Streiff .num_gpio = 16, 4500931d1822SVivien Didelot .max_vid = 8191, 45011a3b39ecSAndrew Lunn .port_base_addr = 0x0, 45029255bacdSAndrew Lunn .phy_base_addr = 0x0, 45031a3b39ecSAndrew Lunn .global1_addr = 0x1b, 45049069c13aSVivien Didelot .global2_addr = 0x1c, 4505b91e055cSAndrew Lunn .age_time_coeff = 3750, 45061a3b39ecSAndrew Lunn .g1_irqs = 9, 4507d6c5e6afSVivien Didelot .g2_irqs = 14, 4508e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4509f3645652SVivien Didelot .pvt = true, 4510b3e05aa1SVivien Didelot .multi_chip = true, 4511443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 45122fa8d3afSBrandon Streiff .ptp_support = true, 45131a3b39ecSAndrew Lunn .ops = &mv88e6390x_ops, 45141a3b39ecSAndrew Lunn }, 4515fad09c73SVivien Didelot }; 4516fad09c73SVivien Didelot 4517fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) 4518fad09c73SVivien Didelot { 4519fad09c73SVivien Didelot int i; 4520fad09c73SVivien Didelot 4521fad09c73SVivien Didelot for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i) 4522fad09c73SVivien Didelot if (mv88e6xxx_table[i].prod_num == prod_num) 4523fad09c73SVivien Didelot return &mv88e6xxx_table[i]; 4524fad09c73SVivien Didelot 4525fad09c73SVivien Didelot return NULL; 4526fad09c73SVivien Didelot } 4527fad09c73SVivien Didelot 4528fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip) 4529fad09c73SVivien Didelot { 4530fad09c73SVivien Didelot const struct mv88e6xxx_info *info; 45318f6345b2SVivien Didelot unsigned int prod_num, rev; 45328f6345b2SVivien Didelot u16 id; 45338f6345b2SVivien Didelot int err; 4534fad09c73SVivien Didelot 45358f6345b2SVivien Didelot mutex_lock(&chip->reg_lock); 4536107fcc10SVivien Didelot err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id); 45378f6345b2SVivien Didelot mutex_unlock(&chip->reg_lock); 45388f6345b2SVivien Didelot if (err) 45398f6345b2SVivien Didelot return err; 4540fad09c73SVivien Didelot 4541107fcc10SVivien Didelot prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK; 4542107fcc10SVivien Didelot rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK; 4543fad09c73SVivien Didelot 4544fad09c73SVivien Didelot info = mv88e6xxx_lookup_info(prod_num); 4545fad09c73SVivien Didelot if (!info) 4546fad09c73SVivien Didelot return -ENODEV; 4547fad09c73SVivien Didelot 4548fad09c73SVivien Didelot /* Update the compatible info with the probed one */ 4549fad09c73SVivien Didelot chip->info = info; 4550fad09c73SVivien Didelot 4551ca070c10SVivien Didelot err = mv88e6xxx_g2_require(chip); 4552ca070c10SVivien Didelot if (err) 4553ca070c10SVivien Didelot return err; 4554ca070c10SVivien Didelot 4555fad09c73SVivien Didelot dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n", 4556fad09c73SVivien Didelot chip->info->prod_num, chip->info->name, rev); 4557fad09c73SVivien Didelot 4558fad09c73SVivien Didelot return 0; 4559fad09c73SVivien Didelot } 4560fad09c73SVivien Didelot 4561fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) 4562fad09c73SVivien Didelot { 4563fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 4564fad09c73SVivien Didelot 4565fad09c73SVivien Didelot chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 4566fad09c73SVivien Didelot if (!chip) 4567fad09c73SVivien Didelot return NULL; 4568fad09c73SVivien Didelot 4569fad09c73SVivien Didelot chip->dev = dev; 4570fad09c73SVivien Didelot 4571fad09c73SVivien Didelot mutex_init(&chip->reg_lock); 4572a3c53be5SAndrew Lunn INIT_LIST_HEAD(&chip->mdios); 4573fad09c73SVivien Didelot 4574fad09c73SVivien Didelot return chip; 4575fad09c73SVivien Didelot } 4576fad09c73SVivien Didelot 45775ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds, 45785ed4e3ebSFlorian Fainelli int port) 45797b314362SAndrew Lunn { 458004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 45812bbb33beSAndrew Lunn 4582443d5a1bSAndrew Lunn return chip->info->tag_protocol; 45837b314362SAndrew Lunn } 45847b314362SAndrew Lunn 45857df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port, 45863709aadcSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 45877df8fbddSVivien Didelot { 45887df8fbddSVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 45897df8fbddSVivien Didelot * so skip the prepare phase. 45907df8fbddSVivien Didelot */ 45917df8fbddSVivien Didelot 45927df8fbddSVivien Didelot return 0; 45937df8fbddSVivien Didelot } 45947df8fbddSVivien Didelot 45957df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port, 45963709aadcSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 45977df8fbddSVivien Didelot { 459804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 45997df8fbddSVivien Didelot 46007df8fbddSVivien Didelot mutex_lock(&chip->reg_lock); 46017df8fbddSVivien Didelot if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 460227c0e600SVivien Didelot MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC)) 4603774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to load multicast MAC address\n", 4604774439e5SVivien Didelot port); 46057df8fbddSVivien Didelot mutex_unlock(&chip->reg_lock); 46067df8fbddSVivien Didelot } 46077df8fbddSVivien Didelot 46087df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, 46097df8fbddSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 46107df8fbddSVivien Didelot { 461104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 46127df8fbddSVivien Didelot int err; 46137df8fbddSVivien Didelot 46147df8fbddSVivien Didelot mutex_lock(&chip->reg_lock); 46157df8fbddSVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 461627c0e600SVivien Didelot MV88E6XXX_G1_ATU_DATA_STATE_UNUSED); 46177df8fbddSVivien Didelot mutex_unlock(&chip->reg_lock); 46187df8fbddSVivien Didelot 46197df8fbddSVivien Didelot return err; 46207df8fbddSVivien Didelot } 46217df8fbddSVivien Didelot 46224f85901fSRussell King static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port, 46234f85901fSRussell King bool unicast, bool multicast) 46244f85901fSRussell King { 46254f85901fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 46264f85901fSRussell King int err = -EOPNOTSUPP; 46274f85901fSRussell King 46284f85901fSRussell King mutex_lock(&chip->reg_lock); 46294f85901fSRussell King if (chip->info->ops->port_set_egress_floods) 46304f85901fSRussell King err = chip->info->ops->port_set_egress_floods(chip, port, 46314f85901fSRussell King unicast, 46324f85901fSRussell King multicast); 46334f85901fSRussell King mutex_unlock(&chip->reg_lock); 46344f85901fSRussell King 46354f85901fSRussell King return err; 46364f85901fSRussell King } 46374f85901fSRussell King 4638a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = { 46397b314362SAndrew Lunn .get_tag_protocol = mv88e6xxx_get_tag_protocol, 4640fad09c73SVivien Didelot .setup = mv88e6xxx_setup, 4641fad09c73SVivien Didelot .adjust_link = mv88e6xxx_adjust_link, 4642c9a2356fSRussell King .phylink_validate = mv88e6xxx_validate, 4643c9a2356fSRussell King .phylink_mac_link_state = mv88e6xxx_link_state, 4644c9a2356fSRussell King .phylink_mac_config = mv88e6xxx_mac_config, 4645c9a2356fSRussell King .phylink_mac_link_down = mv88e6xxx_mac_link_down, 4646c9a2356fSRussell King .phylink_mac_link_up = mv88e6xxx_mac_link_up, 4647fad09c73SVivien Didelot .get_strings = mv88e6xxx_get_strings, 4648fad09c73SVivien Didelot .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, 4649fad09c73SVivien Didelot .get_sset_count = mv88e6xxx_get_sset_count, 465004aca993SAndrew Lunn .port_enable = mv88e6xxx_port_enable, 465104aca993SAndrew Lunn .port_disable = mv88e6xxx_port_disable, 465208f50061SVivien Didelot .get_mac_eee = mv88e6xxx_get_mac_eee, 465308f50061SVivien Didelot .set_mac_eee = mv88e6xxx_set_mac_eee, 4654fad09c73SVivien Didelot .get_eeprom_len = mv88e6xxx_get_eeprom_len, 4655fad09c73SVivien Didelot .get_eeprom = mv88e6xxx_get_eeprom, 4656fad09c73SVivien Didelot .set_eeprom = mv88e6xxx_set_eeprom, 4657fad09c73SVivien Didelot .get_regs_len = mv88e6xxx_get_regs_len, 4658fad09c73SVivien Didelot .get_regs = mv88e6xxx_get_regs, 46592cfcd964SVivien Didelot .set_ageing_time = mv88e6xxx_set_ageing_time, 4660fad09c73SVivien Didelot .port_bridge_join = mv88e6xxx_port_bridge_join, 4661fad09c73SVivien Didelot .port_bridge_leave = mv88e6xxx_port_bridge_leave, 46624f85901fSRussell King .port_egress_floods = mv88e6xxx_port_egress_floods, 4663fad09c73SVivien Didelot .port_stp_state_set = mv88e6xxx_port_stp_state_set, 4664749efcb8SVivien Didelot .port_fast_age = mv88e6xxx_port_fast_age, 4665fad09c73SVivien Didelot .port_vlan_filtering = mv88e6xxx_port_vlan_filtering, 4666fad09c73SVivien Didelot .port_vlan_prepare = mv88e6xxx_port_vlan_prepare, 4667fad09c73SVivien Didelot .port_vlan_add = mv88e6xxx_port_vlan_add, 4668fad09c73SVivien Didelot .port_vlan_del = mv88e6xxx_port_vlan_del, 4669fad09c73SVivien Didelot .port_fdb_add = mv88e6xxx_port_fdb_add, 4670fad09c73SVivien Didelot .port_fdb_del = mv88e6xxx_port_fdb_del, 4671fad09c73SVivien Didelot .port_fdb_dump = mv88e6xxx_port_fdb_dump, 46727df8fbddSVivien Didelot .port_mdb_prepare = mv88e6xxx_port_mdb_prepare, 46737df8fbddSVivien Didelot .port_mdb_add = mv88e6xxx_port_mdb_add, 46747df8fbddSVivien Didelot .port_mdb_del = mv88e6xxx_port_mdb_del, 4675aec5ac88SVivien Didelot .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join, 4676aec5ac88SVivien Didelot .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave, 4677c6fe0ad2SBrandon Streiff .port_hwtstamp_set = mv88e6xxx_port_hwtstamp_set, 4678c6fe0ad2SBrandon Streiff .port_hwtstamp_get = mv88e6xxx_port_hwtstamp_get, 4679c6fe0ad2SBrandon Streiff .port_txtstamp = mv88e6xxx_port_txtstamp, 4680c6fe0ad2SBrandon Streiff .port_rxtstamp = mv88e6xxx_port_rxtstamp, 4681c6fe0ad2SBrandon Streiff .get_ts_info = mv88e6xxx_get_ts_info, 4682fad09c73SVivien Didelot }; 4683fad09c73SVivien Didelot 468455ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) 4685fad09c73SVivien Didelot { 4686fad09c73SVivien Didelot struct device *dev = chip->dev; 4687fad09c73SVivien Didelot struct dsa_switch *ds; 4688fad09c73SVivien Didelot 468973b1204dSVivien Didelot ds = dsa_switch_alloc(dev, mv88e6xxx_num_ports(chip)); 4690fad09c73SVivien Didelot if (!ds) 4691fad09c73SVivien Didelot return -ENOMEM; 4692fad09c73SVivien Didelot 4693fad09c73SVivien Didelot ds->priv = chip; 4694877b7cb0SAndrew Lunn ds->dev = dev; 46959d490b4eSVivien Didelot ds->ops = &mv88e6xxx_switch_ops; 46969ff74f24SVivien Didelot ds->ageing_time_min = chip->info->age_time_coeff; 46979ff74f24SVivien Didelot ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; 4698fad09c73SVivien Didelot 4699fad09c73SVivien Didelot dev_set_drvdata(dev, ds); 4700fad09c73SVivien Didelot 470123c9ee49SVivien Didelot return dsa_register_switch(ds); 4702fad09c73SVivien Didelot } 4703fad09c73SVivien Didelot 4704fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip) 4705fad09c73SVivien Didelot { 4706fad09c73SVivien Didelot dsa_unregister_switch(chip->ds); 4707fad09c73SVivien Didelot } 4708fad09c73SVivien Didelot 4709877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev) 4710877b7cb0SAndrew Lunn { 4711877b7cb0SAndrew Lunn const struct of_device_id *matches = dev->driver->of_match_table; 4712877b7cb0SAndrew Lunn const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data; 4713877b7cb0SAndrew Lunn 4714877b7cb0SAndrew Lunn for (; matches->name[0] || matches->type[0] || matches->compatible[0]; 4715877b7cb0SAndrew Lunn matches++) { 4716877b7cb0SAndrew Lunn if (!strcmp(pdata->compatible, matches->compatible)) 4717877b7cb0SAndrew Lunn return matches->data; 4718877b7cb0SAndrew Lunn } 4719877b7cb0SAndrew Lunn return NULL; 4720877b7cb0SAndrew Lunn } 4721877b7cb0SAndrew Lunn 4722bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration 4723bcd3d9d9SMiquel Raynal * would be lost after a power cycle so prevent it to be suspended. 4724bcd3d9d9SMiquel Raynal */ 4725bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev) 4726bcd3d9d9SMiquel Raynal { 4727bcd3d9d9SMiquel Raynal return -EOPNOTSUPP; 4728bcd3d9d9SMiquel Raynal } 4729bcd3d9d9SMiquel Raynal 4730bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev) 4731bcd3d9d9SMiquel Raynal { 4732bcd3d9d9SMiquel Raynal return 0; 4733bcd3d9d9SMiquel Raynal } 4734bcd3d9d9SMiquel Raynal 4735bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume); 4736bcd3d9d9SMiquel Raynal 4737fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev) 4738fad09c73SVivien Didelot { 4739877b7cb0SAndrew Lunn struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data; 47407ddae24fSDavid S. Miller const struct mv88e6xxx_info *compat_info = NULL; 4741fad09c73SVivien Didelot struct device *dev = &mdiodev->dev; 4742fad09c73SVivien Didelot struct device_node *np = dev->of_node; 4743fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 4744877b7cb0SAndrew Lunn int port; 4745fad09c73SVivien Didelot int err; 4746fad09c73SVivien Didelot 47477bb8c996SAndrew Lunn if (!np && !pdata) 47487bb8c996SAndrew Lunn return -EINVAL; 47497bb8c996SAndrew Lunn 4750877b7cb0SAndrew Lunn if (np) 4751fad09c73SVivien Didelot compat_info = of_device_get_match_data(dev); 4752877b7cb0SAndrew Lunn 4753877b7cb0SAndrew Lunn if (pdata) { 4754877b7cb0SAndrew Lunn compat_info = pdata_device_get_match_data(dev); 4755877b7cb0SAndrew Lunn 4756877b7cb0SAndrew Lunn if (!pdata->netdev) 4757877b7cb0SAndrew Lunn return -EINVAL; 4758877b7cb0SAndrew Lunn 4759877b7cb0SAndrew Lunn for (port = 0; port < DSA_MAX_PORTS; port++) { 4760877b7cb0SAndrew Lunn if (!(pdata->enabled_ports & (1 << port))) 4761877b7cb0SAndrew Lunn continue; 4762877b7cb0SAndrew Lunn if (strcmp(pdata->cd.port_names[port], "cpu")) 4763877b7cb0SAndrew Lunn continue; 4764877b7cb0SAndrew Lunn pdata->cd.netdev[port] = &pdata->netdev->dev; 4765877b7cb0SAndrew Lunn break; 4766877b7cb0SAndrew Lunn } 4767877b7cb0SAndrew Lunn } 4768877b7cb0SAndrew Lunn 4769fad09c73SVivien Didelot if (!compat_info) 4770fad09c73SVivien Didelot return -EINVAL; 4771fad09c73SVivien Didelot 4772fad09c73SVivien Didelot chip = mv88e6xxx_alloc_chip(dev); 4773877b7cb0SAndrew Lunn if (!chip) { 4774877b7cb0SAndrew Lunn err = -ENOMEM; 4775877b7cb0SAndrew Lunn goto out; 4776877b7cb0SAndrew Lunn } 4777fad09c73SVivien Didelot 4778fad09c73SVivien Didelot chip->info = compat_info; 4779fad09c73SVivien Didelot 4780fad09c73SVivien Didelot err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr); 4781fad09c73SVivien Didelot if (err) 4782877b7cb0SAndrew Lunn goto out; 4783fad09c73SVivien Didelot 4784b4308f04SAndrew Lunn chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 4785877b7cb0SAndrew Lunn if (IS_ERR(chip->reset)) { 4786877b7cb0SAndrew Lunn err = PTR_ERR(chip->reset); 4787877b7cb0SAndrew Lunn goto out; 4788877b7cb0SAndrew Lunn } 4789b4308f04SAndrew Lunn 4790fad09c73SVivien Didelot err = mv88e6xxx_detect(chip); 4791fad09c73SVivien Didelot if (err) 4792877b7cb0SAndrew Lunn goto out; 4793fad09c73SVivien Didelot 4794e57e5e77SVivien Didelot mv88e6xxx_phy_init(chip); 4795e57e5e77SVivien Didelot 479600baabe5SAndrew Lunn if (chip->info->ops->get_eeprom) { 479700baabe5SAndrew Lunn if (np) 479800baabe5SAndrew Lunn of_property_read_u32(np, "eeprom-length", 479900baabe5SAndrew Lunn &chip->eeprom_len); 480000baabe5SAndrew Lunn else 480100baabe5SAndrew Lunn chip->eeprom_len = pdata->eeprom_len; 480200baabe5SAndrew Lunn } 4803fad09c73SVivien Didelot 4804dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 4805dc30c35bSAndrew Lunn err = mv88e6xxx_switch_reset(chip); 4806dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 4807fad09c73SVivien Didelot if (err) 4808dc30c35bSAndrew Lunn goto out; 4809fad09c73SVivien Didelot 4810a27415deSAndrew Lunn if (np) { 4811dc30c35bSAndrew Lunn chip->irq = of_irq_get(np, 0); 4812dc30c35bSAndrew Lunn if (chip->irq == -EPROBE_DEFER) { 4813dc30c35bSAndrew Lunn err = chip->irq; 4814dc30c35bSAndrew Lunn goto out; 4815fad09c73SVivien Didelot } 4816a27415deSAndrew Lunn } 4817a27415deSAndrew Lunn 4818a27415deSAndrew Lunn if (pdata) 4819a27415deSAndrew Lunn chip->irq = pdata->irq; 4820fad09c73SVivien Didelot 4821294d711eSAndrew Lunn /* Has to be performed before the MDIO bus is created, because 4822a708767eSUwe Kleine-König * the PHYs will link their interrupts to these interrupt 4823294d711eSAndrew Lunn * controllers 4824dc30c35bSAndrew Lunn */ 4825dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 4826294d711eSAndrew Lunn if (chip->irq > 0) 4827dc30c35bSAndrew Lunn err = mv88e6xxx_g1_irq_setup(chip); 4828294d711eSAndrew Lunn else 4829294d711eSAndrew Lunn err = mv88e6xxx_irq_poll_setup(chip); 4830dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 4831dc30c35bSAndrew Lunn 4832dc30c35bSAndrew Lunn if (err) 4833dc30c35bSAndrew Lunn goto out; 4834dc30c35bSAndrew Lunn 4835d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) { 4836dc30c35bSAndrew Lunn err = mv88e6xxx_g2_irq_setup(chip); 4837dc30c35bSAndrew Lunn if (err) 4838dc30c35bSAndrew Lunn goto out_g1_irq; 4839dc30c35bSAndrew Lunn } 48400977644cSAndrew Lunn 48410977644cSAndrew Lunn err = mv88e6xxx_g1_atu_prob_irq_setup(chip); 48420977644cSAndrew Lunn if (err) 48430977644cSAndrew Lunn goto out_g2_irq; 484462eb1162SAndrew Lunn 484562eb1162SAndrew Lunn err = mv88e6xxx_g1_vtu_prob_irq_setup(chip); 484662eb1162SAndrew Lunn if (err) 484762eb1162SAndrew Lunn goto out_g1_atu_prob_irq; 4848dc30c35bSAndrew Lunn 4849a3c53be5SAndrew Lunn err = mv88e6xxx_mdios_register(chip, np); 4850dc30c35bSAndrew Lunn if (err) 485162eb1162SAndrew Lunn goto out_g1_vtu_prob_irq; 4852dc30c35bSAndrew Lunn 485355ed0ce0SFlorian Fainelli err = mv88e6xxx_register_switch(chip); 4854dc30c35bSAndrew Lunn if (err) 4855dc30c35bSAndrew Lunn goto out_mdio; 4856dc30c35bSAndrew Lunn 4857fad09c73SVivien Didelot return 0; 4858dc30c35bSAndrew Lunn 4859dc30c35bSAndrew Lunn out_mdio: 4860a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 486162eb1162SAndrew Lunn out_g1_vtu_prob_irq: 486262eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 48630977644cSAndrew Lunn out_g1_atu_prob_irq: 48640977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 4865dc30c35bSAndrew Lunn out_g2_irq: 4866294d711eSAndrew Lunn if (chip->info->g2_irqs > 0) 4867dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 4868dc30c35bSAndrew Lunn out_g1_irq: 4869294d711eSAndrew Lunn if (chip->irq > 0) 4870dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 4871294d711eSAndrew Lunn else 4872294d711eSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 4873dc30c35bSAndrew Lunn out: 4874877b7cb0SAndrew Lunn if (pdata) 4875877b7cb0SAndrew Lunn dev_put(pdata->netdev); 4876877b7cb0SAndrew Lunn 4877dc30c35bSAndrew Lunn return err; 4878fad09c73SVivien Didelot } 4879fad09c73SVivien Didelot 4880fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev) 4881fad09c73SVivien Didelot { 4882fad09c73SVivien Didelot struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 488304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 4884fad09c73SVivien Didelot 4885c6fe0ad2SBrandon Streiff if (chip->info->ptp_support) { 4886c6fe0ad2SBrandon Streiff mv88e6xxx_hwtstamp_free(chip); 48872fa8d3afSBrandon Streiff mv88e6xxx_ptp_free(chip); 4888c6fe0ad2SBrandon Streiff } 48892fa8d3afSBrandon Streiff 4890930188ceSAndrew Lunn mv88e6xxx_phy_destroy(chip); 4891fad09c73SVivien Didelot mv88e6xxx_unregister_switch(chip); 4892a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 4893dc30c35bSAndrew Lunn 489462eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 48950977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 489676f38f1fSAndrew Lunn 4897d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) 4898dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 489976f38f1fSAndrew Lunn 490076f38f1fSAndrew Lunn if (chip->irq > 0) 4901dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 490276f38f1fSAndrew Lunn else 490376f38f1fSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 4904fad09c73SVivien Didelot } 4905fad09c73SVivien Didelot 4906fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = { 4907fad09c73SVivien Didelot { 4908fad09c73SVivien Didelot .compatible = "marvell,mv88e6085", 4909fad09c73SVivien Didelot .data = &mv88e6xxx_table[MV88E6085], 4910fad09c73SVivien Didelot }, 49111a3b39ecSAndrew Lunn { 49121a3b39ecSAndrew Lunn .compatible = "marvell,mv88e6190", 49131a3b39ecSAndrew Lunn .data = &mv88e6xxx_table[MV88E6190], 49141a3b39ecSAndrew Lunn }, 49151f71836fSRasmus Villemoes { 49161f71836fSRasmus Villemoes .compatible = "marvell,mv88e6250", 49171f71836fSRasmus Villemoes .data = &mv88e6xxx_table[MV88E6250], 49181f71836fSRasmus Villemoes }, 4919fad09c73SVivien Didelot { /* sentinel */ }, 4920fad09c73SVivien Didelot }; 4921fad09c73SVivien Didelot 4922fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match); 4923fad09c73SVivien Didelot 4924fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = { 4925fad09c73SVivien Didelot .probe = mv88e6xxx_probe, 4926fad09c73SVivien Didelot .remove = mv88e6xxx_remove, 4927fad09c73SVivien Didelot .mdiodrv.driver = { 4928fad09c73SVivien Didelot .name = "mv88e6085", 4929fad09c73SVivien Didelot .of_match_table = mv88e6xxx_of_match, 4930bcd3d9d9SMiquel Raynal .pm = &mv88e6xxx_pm_ops, 4931fad09c73SVivien Didelot }, 4932fad09c73SVivien Didelot }; 4933fad09c73SVivien Didelot 49347324d50eSAndrew Lunn mdio_module_driver(mv88e6xxx_driver); 4935fad09c73SVivien Didelot 4936fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); 4937fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips"); 4938fad09c73SVivien Didelot MODULE_LICENSE("GPL"); 4939