]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/net/dsa/mv88e6xxx/chip.c
net: dsa: mv88e6xxx: program the PVT with all ones
[mirror_ubuntu-bionic-kernel.git] / drivers / net / dsa / mv88e6xxx / chip.c
CommitLineData
91da11f8 1/*
0d3cd4b6
VD
2 * Marvell 88e6xxx Ethernet switch single-chip support
3 *
91da11f8
LB
4 * Copyright (c) 2008 Marvell Semiconductor
5 *
b8fee957
VD
6 * Copyright (c) 2015 CMC Electronics, Inc.
7 * Added support for VLAN Table Unit operations
8 *
14c7b3c3
AL
9 * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
10 *
4333d619
VD
11 * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
12 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
13 *
91da11f8
LB
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 */
19
19b2f97e 20#include <linux/delay.h>
defb05b9 21#include <linux/etherdevice.h>
dea87024 22#include <linux/ethtool.h>
facd95b2 23#include <linux/if_bridge.h>
dc30c35b
AL
24#include <linux/interrupt.h>
25#include <linux/irq.h>
26#include <linux/irqdomain.h>
19b2f97e 27#include <linux/jiffies.h>
91da11f8 28#include <linux/list.h>
14c7b3c3 29#include <linux/mdio.h>
2bbba277 30#include <linux/module.h>
caac8545 31#include <linux/of_device.h>
dc30c35b 32#include <linux/of_irq.h>
b516d453 33#include <linux/of_mdio.h>
91da11f8 34#include <linux/netdevice.h>
c8c1b39a 35#include <linux/gpio/consumer.h>
91da11f8 36#include <linux/phy.h>
c8f0b869 37#include <net/dsa.h>
1f36faf2 38#include <net/switchdev.h>
ec561276 39
91da11f8 40#include "mv88e6xxx.h"
a935c052 41#include "global1.h"
ec561276 42#include "global2.h"
18abed21 43#include "port.h"
91da11f8 44
fad09c73 45static void assert_reg_lock(struct mv88e6xxx_chip *chip)
3996a4ff 46{
fad09c73
VD
47 if (unlikely(!mutex_is_locked(&chip->reg_lock))) {
48 dev_err(chip->dev, "Switch registers lock not held!\n");
3996a4ff
VD
49 dump_stack();
50 }
51}
52
914b32f6
VD
53/* The switch ADDR[4:1] configuration pins define the chip SMI device address
54 * (ADDR[0] is always zero, thus only even SMI addresses can be strapped).
55 *
56 * When ADDR is all zero, the chip uses Single-chip Addressing Mode, assuming it
57 * is the only device connected to the SMI master. In this mode it responds to
58 * all 32 possible SMI addresses, and thus maps directly the internal devices.
59 *
60 * When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing
61 * multiple devices to share the SMI interface. In this mode it responds to only
62 * 2 registers, used to indirectly access the internal SMI devices.
91da11f8 63 */
914b32f6 64
fad09c73 65static int mv88e6xxx_smi_read(struct mv88e6xxx_chip *chip,
914b32f6
VD
66 int addr, int reg, u16 *val)
67{
fad09c73 68 if (!chip->smi_ops)
914b32f6
VD
69 return -EOPNOTSUPP;
70
fad09c73 71 return chip->smi_ops->read(chip, addr, reg, val);
914b32f6
VD
72}
73
fad09c73 74static int mv88e6xxx_smi_write(struct mv88e6xxx_chip *chip,
914b32f6
VD
75 int addr, int reg, u16 val)
76{
fad09c73 77 if (!chip->smi_ops)
914b32f6
VD
78 return -EOPNOTSUPP;
79
fad09c73 80 return chip->smi_ops->write(chip, addr, reg, val);
914b32f6
VD
81}
82
fad09c73 83static int mv88e6xxx_smi_single_chip_read(struct mv88e6xxx_chip *chip,
914b32f6
VD
84 int addr, int reg, u16 *val)
85{
86 int ret;
87
fad09c73 88 ret = mdiobus_read_nested(chip->bus, addr, reg);
914b32f6
VD
89 if (ret < 0)
90 return ret;
91
92 *val = ret & 0xffff;
93
94 return 0;
95}
96
fad09c73 97static int mv88e6xxx_smi_single_chip_write(struct mv88e6xxx_chip *chip,
914b32f6
VD
98 int addr, int reg, u16 val)
99{
100 int ret;
101
fad09c73 102 ret = mdiobus_write_nested(chip->bus, addr, reg, val);
914b32f6
VD
103 if (ret < 0)
104 return ret;
105
106 return 0;
107}
108
c08026ab 109static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_single_chip_ops = {
914b32f6
VD
110 .read = mv88e6xxx_smi_single_chip_read,
111 .write = mv88e6xxx_smi_single_chip_write,
112};
113
fad09c73 114static int mv88e6xxx_smi_multi_chip_wait(struct mv88e6xxx_chip *chip)
91da11f8
LB
115{
116 int ret;
117 int i;
118
119 for (i = 0; i < 16; i++) {
fad09c73 120 ret = mdiobus_read_nested(chip->bus, chip->sw_addr, SMI_CMD);
91da11f8
LB
121 if (ret < 0)
122 return ret;
123
cca8b133 124 if ((ret & SMI_CMD_BUSY) == 0)
91da11f8
LB
125 return 0;
126 }
127
128 return -ETIMEDOUT;
129}
130
fad09c73 131static int mv88e6xxx_smi_multi_chip_read(struct mv88e6xxx_chip *chip,
914b32f6 132 int addr, int reg, u16 *val)
91da11f8
LB
133{
134 int ret;
135
3675c8d7 136 /* Wait for the bus to become free. */
fad09c73 137 ret = mv88e6xxx_smi_multi_chip_wait(chip);
91da11f8
LB
138 if (ret < 0)
139 return ret;
140
3675c8d7 141 /* Transmit the read command. */
fad09c73 142 ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_CMD,
6e899e6c 143 SMI_CMD_OP_22_READ | (addr << 5) | reg);
91da11f8
LB
144 if (ret < 0)
145 return ret;
146
3675c8d7 147 /* Wait for the read command to complete. */
fad09c73 148 ret = mv88e6xxx_smi_multi_chip_wait(chip);
91da11f8
LB
149 if (ret < 0)
150 return ret;
151
3675c8d7 152 /* Read the data. */
fad09c73 153 ret = mdiobus_read_nested(chip->bus, chip->sw_addr, SMI_DATA);
bb92ea5e
VD
154 if (ret < 0)
155 return ret;
156
914b32f6 157 *val = ret & 0xffff;
91da11f8 158
914b32f6 159 return 0;
8d6d09e7
GR
160}
161
fad09c73 162static int mv88e6xxx_smi_multi_chip_write(struct mv88e6xxx_chip *chip,
914b32f6 163 int addr, int reg, u16 val)
91da11f8
LB
164{
165 int ret;
166
3675c8d7 167 /* Wait for the bus to become free. */
fad09c73 168 ret = mv88e6xxx_smi_multi_chip_wait(chip);
91da11f8
LB
169 if (ret < 0)
170 return ret;
171
3675c8d7 172 /* Transmit the data to write. */
fad09c73 173 ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_DATA, val);
91da11f8
LB
174 if (ret < 0)
175 return ret;
176
3675c8d7 177 /* Transmit the write command. */
fad09c73 178 ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_CMD,
6e899e6c 179 SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
91da11f8
LB
180 if (ret < 0)
181 return ret;
182
3675c8d7 183 /* Wait for the write command to complete. */
fad09c73 184 ret = mv88e6xxx_smi_multi_chip_wait(chip);
91da11f8
LB
185 if (ret < 0)
186 return ret;
187
188 return 0;
189}
190
c08026ab 191static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_multi_chip_ops = {
914b32f6
VD
192 .read = mv88e6xxx_smi_multi_chip_read,
193 .write = mv88e6xxx_smi_multi_chip_write,
194};
195
ec561276 196int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
914b32f6
VD
197{
198 int err;
199
fad09c73 200 assert_reg_lock(chip);
914b32f6 201
fad09c73 202 err = mv88e6xxx_smi_read(chip, addr, reg, val);
914b32f6
VD
203 if (err)
204 return err;
205
fad09c73 206 dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
914b32f6
VD
207 addr, reg, *val);
208
209 return 0;
210}
211
ec561276 212int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
91da11f8 213{
914b32f6
VD
214 int err;
215
fad09c73 216 assert_reg_lock(chip);
91da11f8 217
fad09c73 218 err = mv88e6xxx_smi_write(chip, addr, reg, val);
914b32f6
VD
219 if (err)
220 return err;
221
fad09c73 222 dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
bb92ea5e
VD
223 addr, reg, val);
224
914b32f6
VD
225 return 0;
226}
227
ee26a228
AL
228static int mv88e6165_phy_read(struct mv88e6xxx_chip *chip,
229 struct mii_bus *bus,
230 int addr, int reg, u16 *val)
efb3e74d
AL
231{
232 return mv88e6xxx_read(chip, addr, reg, val);
233}
234
ee26a228
AL
235static int mv88e6165_phy_write(struct mv88e6xxx_chip *chip,
236 struct mii_bus *bus,
237 int addr, int reg, u16 val)
efb3e74d
AL
238{
239 return mv88e6xxx_write(chip, addr, reg, val);
240}
241
a3c53be5
AL
242static struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
243{
244 struct mv88e6xxx_mdio_bus *mdio_bus;
245
246 mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus,
247 list);
248 if (!mdio_bus)
249 return NULL;
250
251 return mdio_bus->bus;
252}
253
e57e5e77
VD
254static int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy,
255 int reg, u16 *val)
256{
257 int addr = phy; /* PHY devices addresses start at 0x0 */
a3c53be5 258 struct mii_bus *bus;
e57e5e77 259
a3c53be5
AL
260 bus = mv88e6xxx_default_mdio_bus(chip);
261 if (!bus)
e57e5e77
VD
262 return -EOPNOTSUPP;
263
a3c53be5 264 if (!chip->info->ops->phy_read)
ee26a228
AL
265 return -EOPNOTSUPP;
266
267 return chip->info->ops->phy_read(chip, bus, addr, reg, val);
e57e5e77
VD
268}
269
270static int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy,
271 int reg, u16 val)
272{
273 int addr = phy; /* PHY devices addresses start at 0x0 */
a3c53be5 274 struct mii_bus *bus;
e57e5e77 275
a3c53be5
AL
276 bus = mv88e6xxx_default_mdio_bus(chip);
277 if (!bus)
e57e5e77
VD
278 return -EOPNOTSUPP;
279
a3c53be5 280 if (!chip->info->ops->phy_write)
ee26a228
AL
281 return -EOPNOTSUPP;
282
283 return chip->info->ops->phy_write(chip, bus, addr, reg, val);
e57e5e77
VD
284}
285
09cb7dfd
VD
286static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page)
287{
288 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_PHY_PAGE))
289 return -EOPNOTSUPP;
290
291 return mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
292}
293
294static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy)
295{
296 int err;
297
298 /* Restore PHY page Copper 0x0 for access via the registered MDIO bus */
299 err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, PHY_PAGE_COPPER);
300 if (unlikely(err)) {
301 dev_err(chip->dev, "failed to restore PHY %d page Copper (%d)\n",
302 phy, err);
303 }
304}
305
306static int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy,
307 u8 page, int reg, u16 *val)
308{
309 int err;
310
311 /* There is no paging for registers 22 */
312 if (reg == PHY_PAGE)
313 return -EINVAL;
314
315 err = mv88e6xxx_phy_page_get(chip, phy, page);
316 if (!err) {
317 err = mv88e6xxx_phy_read(chip, phy, reg, val);
318 mv88e6xxx_phy_page_put(chip, phy);
319 }
320
321 return err;
322}
323
324static int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy,
325 u8 page, int reg, u16 val)
326{
327 int err;
328
329 /* There is no paging for registers 22 */
330 if (reg == PHY_PAGE)
331 return -EINVAL;
332
333 err = mv88e6xxx_phy_page_get(chip, phy, page);
334 if (!err) {
335 err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
336 mv88e6xxx_phy_page_put(chip, phy);
337 }
338
339 return err;
340}
341
342static int mv88e6xxx_serdes_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
343{
344 return mv88e6xxx_phy_page_read(chip, ADDR_SERDES, SERDES_PAGE_FIBER,
345 reg, val);
346}
347
348static int mv88e6xxx_serdes_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
349{
350 return mv88e6xxx_phy_page_write(chip, ADDR_SERDES, SERDES_PAGE_FIBER,
351 reg, val);
352}
353
dc30c35b
AL
354static void mv88e6xxx_g1_irq_mask(struct irq_data *d)
355{
356 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
357 unsigned int n = d->hwirq;
358
359 chip->g1_irq.masked |= (1 << n);
360}
361
362static void mv88e6xxx_g1_irq_unmask(struct irq_data *d)
363{
364 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
365 unsigned int n = d->hwirq;
366
367 chip->g1_irq.masked &= ~(1 << n);
368}
369
370static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
371{
372 struct mv88e6xxx_chip *chip = dev_id;
373 unsigned int nhandled = 0;
374 unsigned int sub_irq;
375 unsigned int n;
376 u16 reg;
377 int err;
378
379 mutex_lock(&chip->reg_lock);
380 err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &reg);
381 mutex_unlock(&chip->reg_lock);
382
383 if (err)
384 goto out;
385
386 for (n = 0; n < chip->g1_irq.nirqs; ++n) {
387 if (reg & (1 << n)) {
388 sub_irq = irq_find_mapping(chip->g1_irq.domain, n);
389 handle_nested_irq(sub_irq);
390 ++nhandled;
391 }
392 }
393out:
394 return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
395}
396
397static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
398{
399 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
400
401 mutex_lock(&chip->reg_lock);
402}
403
404static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
405{
406 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
407 u16 mask = GENMASK(chip->g1_irq.nirqs, 0);
408 u16 reg;
409 int err;
410
411 err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &reg);
412 if (err)
413 goto out;
414
415 reg &= ~mask;
416 reg |= (~chip->g1_irq.masked & mask);
417
418 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, reg);
419 if (err)
420 goto out;
421
422out:
423 mutex_unlock(&chip->reg_lock);
424}
425
426static struct irq_chip mv88e6xxx_g1_irq_chip = {
427 .name = "mv88e6xxx-g1",
428 .irq_mask = mv88e6xxx_g1_irq_mask,
429 .irq_unmask = mv88e6xxx_g1_irq_unmask,
430 .irq_bus_lock = mv88e6xxx_g1_irq_bus_lock,
431 .irq_bus_sync_unlock = mv88e6xxx_g1_irq_bus_sync_unlock,
432};
433
434static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d,
435 unsigned int irq,
436 irq_hw_number_t hwirq)
437{
438 struct mv88e6xxx_chip *chip = d->host_data;
439
440 irq_set_chip_data(irq, d->host_data);
441 irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq);
442 irq_set_noprobe(irq);
443
444 return 0;
445}
446
447static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = {
448 .map = mv88e6xxx_g1_irq_domain_map,
449 .xlate = irq_domain_xlate_twocell,
450};
451
452static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
453{
454 int irq, virq;
3460a577
AL
455 u16 mask;
456
457 mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &mask);
458 mask |= GENMASK(chip->g1_irq.nirqs, 0);
459 mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask);
460
461 free_irq(chip->irq, chip);
dc30c35b 462
5edef2f2 463 for (irq = 0; irq < chip->g1_irq.nirqs; irq++) {
a3db3d3a 464 virq = irq_find_mapping(chip->g1_irq.domain, irq);
dc30c35b
AL
465 irq_dispose_mapping(virq);
466 }
467
a3db3d3a 468 irq_domain_remove(chip->g1_irq.domain);
dc30c35b
AL
469}
470
471static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
472{
3dd0ef05
AL
473 int err, irq, virq;
474 u16 reg, mask;
dc30c35b
AL
475
476 chip->g1_irq.nirqs = chip->info->g1_irqs;
477 chip->g1_irq.domain = irq_domain_add_simple(
478 NULL, chip->g1_irq.nirqs, 0,
479 &mv88e6xxx_g1_irq_domain_ops, chip);
480 if (!chip->g1_irq.domain)
481 return -ENOMEM;
482
483 for (irq = 0; irq < chip->g1_irq.nirqs; irq++)
484 irq_create_mapping(chip->g1_irq.domain, irq);
485
486 chip->g1_irq.chip = mv88e6xxx_g1_irq_chip;
487 chip->g1_irq.masked = ~0;
488
3dd0ef05 489 err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &mask);
dc30c35b 490 if (err)
3dd0ef05 491 goto out_mapping;
dc30c35b 492
3dd0ef05 493 mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
dc30c35b 494
3dd0ef05 495 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask);
dc30c35b 496 if (err)
3dd0ef05 497 goto out_disable;
dc30c35b
AL
498
499 /* Reading the interrupt status clears (most of) them */
500 err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &reg);
501 if (err)
3dd0ef05 502 goto out_disable;
dc30c35b
AL
503
504 err = request_threaded_irq(chip->irq, NULL,
505 mv88e6xxx_g1_irq_thread_fn,
506 IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
507 dev_name(chip->dev), chip);
508 if (err)
3dd0ef05 509 goto out_disable;
dc30c35b
AL
510
511 return 0;
512
3dd0ef05
AL
513out_disable:
514 mask |= GENMASK(chip->g1_irq.nirqs, 0);
515 mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask);
516
517out_mapping:
518 for (irq = 0; irq < 16; irq++) {
519 virq = irq_find_mapping(chip->g1_irq.domain, irq);
520 irq_dispose_mapping(virq);
521 }
522
523 irq_domain_remove(chip->g1_irq.domain);
dc30c35b
AL
524
525 return err;
526}
527
ec561276 528int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask)
2d79af6e 529{
6441e669 530 int i;
2d79af6e 531
6441e669 532 for (i = 0; i < 16; i++) {
2d79af6e
VD
533 u16 val;
534 int err;
535
536 err = mv88e6xxx_read(chip, addr, reg, &val);
537 if (err)
538 return err;
539
540 if (!(val & mask))
541 return 0;
542
543 usleep_range(1000, 2000);
544 }
545
30853553 546 dev_err(chip->dev, "Timeout while waiting for switch\n");
2d79af6e
VD
547 return -ETIMEDOUT;
548}
549
f22ab641 550/* Indirect write to single pointer-data register with an Update bit */
ec561276 551int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update)
f22ab641
VD
552{
553 u16 val;
0f02b4f7 554 int err;
f22ab641
VD
555
556 /* Wait until the previous operation is completed */
0f02b4f7
AL
557 err = mv88e6xxx_wait(chip, addr, reg, BIT(15));
558 if (err)
559 return err;
f22ab641
VD
560
561 /* Set the Update bit to trigger a write operation */
562 val = BIT(15) | update;
563
564 return mv88e6xxx_write(chip, addr, reg, val);
565}
566
a935c052 567static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip)
914b32f6 568{
a199d8b6
VD
569 if (!chip->info->ops->ppu_disable)
570 return 0;
2e5f0320 571
a199d8b6 572 return chip->info->ops->ppu_disable(chip);
2e5f0320
LB
573}
574
fad09c73 575static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip)
2e5f0320 576{
a199d8b6
VD
577 if (!chip->info->ops->ppu_enable)
578 return 0;
2e5f0320 579
a199d8b6 580 return chip->info->ops->ppu_enable(chip);
2e5f0320
LB
581}
582
583static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
584{
fad09c73 585 struct mv88e6xxx_chip *chip;
2e5f0320 586
fad09c73 587 chip = container_of(ugly, struct mv88e6xxx_chip, ppu_work);
762eb67b 588
fad09c73 589 mutex_lock(&chip->reg_lock);
762eb67b 590
fad09c73
VD
591 if (mutex_trylock(&chip->ppu_mutex)) {
592 if (mv88e6xxx_ppu_enable(chip) == 0)
593 chip->ppu_disabled = 0;
594 mutex_unlock(&chip->ppu_mutex);
2e5f0320 595 }
762eb67b 596
fad09c73 597 mutex_unlock(&chip->reg_lock);
2e5f0320
LB
598}
599
600static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
601{
fad09c73 602 struct mv88e6xxx_chip *chip = (void *)_ps;
2e5f0320 603
fad09c73 604 schedule_work(&chip->ppu_work);
2e5f0320
LB
605}
606
fad09c73 607static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip *chip)
2e5f0320 608{
2e5f0320
LB
609 int ret;
610
fad09c73 611 mutex_lock(&chip->ppu_mutex);
2e5f0320 612
3675c8d7 613 /* If the PHY polling unit is enabled, disable it so that
2e5f0320
LB
614 * we can access the PHY registers. If it was already
615 * disabled, cancel the timer that is going to re-enable
616 * it.
617 */
fad09c73
VD
618 if (!chip->ppu_disabled) {
619 ret = mv88e6xxx_ppu_disable(chip);
85686581 620 if (ret < 0) {
fad09c73 621 mutex_unlock(&chip->ppu_mutex);
85686581
BG
622 return ret;
623 }
fad09c73 624 chip->ppu_disabled = 1;
2e5f0320 625 } else {
fad09c73 626 del_timer(&chip->ppu_timer);
85686581 627 ret = 0;
2e5f0320
LB
628 }
629
630 return ret;
631}
632
fad09c73 633static void mv88e6xxx_ppu_access_put(struct mv88e6xxx_chip *chip)
2e5f0320 634{
3675c8d7 635 /* Schedule a timer to re-enable the PHY polling unit. */
fad09c73
VD
636 mod_timer(&chip->ppu_timer, jiffies + msecs_to_jiffies(10));
637 mutex_unlock(&chip->ppu_mutex);
2e5f0320
LB
638}
639
fad09c73 640static void mv88e6xxx_ppu_state_init(struct mv88e6xxx_chip *chip)
2e5f0320 641{
fad09c73
VD
642 mutex_init(&chip->ppu_mutex);
643 INIT_WORK(&chip->ppu_work, mv88e6xxx_ppu_reenable_work);
68497a87
WY
644 setup_timer(&chip->ppu_timer, mv88e6xxx_ppu_reenable_timer,
645 (unsigned long)chip);
2e5f0320
LB
646}
647
930188ce
AL
648static void mv88e6xxx_ppu_state_destroy(struct mv88e6xxx_chip *chip)
649{
650 del_timer_sync(&chip->ppu_timer);
651}
652
ee26a228
AL
653static int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip,
654 struct mii_bus *bus,
655 int addr, int reg, u16 *val)
2e5f0320 656{
e57e5e77 657 int err;
2e5f0320 658
e57e5e77
VD
659 err = mv88e6xxx_ppu_access_get(chip);
660 if (!err) {
661 err = mv88e6xxx_read(chip, addr, reg, val);
fad09c73 662 mv88e6xxx_ppu_access_put(chip);
2e5f0320
LB
663 }
664
e57e5e77 665 return err;
2e5f0320
LB
666}
667
ee26a228
AL
668static int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip,
669 struct mii_bus *bus,
670 int addr, int reg, u16 val)
2e5f0320 671{
e57e5e77 672 int err;
2e5f0320 673
e57e5e77
VD
674 err = mv88e6xxx_ppu_access_get(chip);
675 if (!err) {
676 err = mv88e6xxx_write(chip, addr, reg, val);
fad09c73 677 mv88e6xxx_ppu_access_put(chip);
2e5f0320
LB
678 }
679
e57e5e77 680 return err;
2e5f0320 681}
2e5f0320 682
fad09c73 683static bool mv88e6xxx_6097_family(struct mv88e6xxx_chip *chip)
54d792f2 684{
fad09c73 685 return chip->info->family == MV88E6XXX_FAMILY_6097;
54d792f2
AL
686}
687
fad09c73 688static bool mv88e6xxx_6165_family(struct mv88e6xxx_chip *chip)
54d792f2 689{
fad09c73 690 return chip->info->family == MV88E6XXX_FAMILY_6165;
54d792f2
AL
691}
692
a75961d0
GC
693static bool mv88e6xxx_6341_family(struct mv88e6xxx_chip *chip)
694{
695 return chip->info->family == MV88E6XXX_FAMILY_6341;
696}
697
fad09c73 698static bool mv88e6xxx_6351_family(struct mv88e6xxx_chip *chip)
54d792f2 699{
fad09c73 700 return chip->info->family == MV88E6XXX_FAMILY_6351;
54d792f2
AL
701}
702
fad09c73 703static bool mv88e6xxx_6352_family(struct mv88e6xxx_chip *chip)
f3a8b6b6 704{
fad09c73 705 return chip->info->family == MV88E6XXX_FAMILY_6352;
f3a8b6b6
AL
706}
707
d78343d2
VD
708static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
709 int link, int speed, int duplex,
710 phy_interface_t mode)
711{
712 int err;
713
714 if (!chip->info->ops->port_set_link)
715 return 0;
716
717 /* Port's MAC control must not be changed unless the link is down */
718 err = chip->info->ops->port_set_link(chip, port, 0);
719 if (err)
720 return err;
721
722 if (chip->info->ops->port_set_speed) {
723 err = chip->info->ops->port_set_speed(chip, port, speed);
724 if (err && err != -EOPNOTSUPP)
725 goto restore_link;
726 }
727
728 if (chip->info->ops->port_set_duplex) {
729 err = chip->info->ops->port_set_duplex(chip, port, duplex);
730 if (err && err != -EOPNOTSUPP)
731 goto restore_link;
732 }
733
734 if (chip->info->ops->port_set_rgmii_delay) {
735 err = chip->info->ops->port_set_rgmii_delay(chip, port, mode);
736 if (err && err != -EOPNOTSUPP)
737 goto restore_link;
738 }
739
f39908d3
AL
740 if (chip->info->ops->port_set_cmode) {
741 err = chip->info->ops->port_set_cmode(chip, port, mode);
742 if (err && err != -EOPNOTSUPP)
743 goto restore_link;
744 }
745
d78343d2
VD
746 err = 0;
747restore_link:
748 if (chip->info->ops->port_set_link(chip, port, link))
749 netdev_err(chip->ds->ports[port].netdev,
750 "failed to restore MAC's link\n");
751
752 return err;
753}
754
dea87024
AL
755/* We expect the switch to perform auto negotiation if there is a real
756 * phy. However, in the case of a fixed link phy, we force the port
757 * settings from the fixed link settings.
758 */
f81ec90f
VD
759static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
760 struct phy_device *phydev)
dea87024 761{
04bed143 762 struct mv88e6xxx_chip *chip = ds->priv;
0e7b9925 763 int err;
dea87024
AL
764
765 if (!phy_is_pseudo_fixed_link(phydev))
766 return;
767
fad09c73 768 mutex_lock(&chip->reg_lock);
d78343d2
VD
769 err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
770 phydev->duplex, phydev->interface);
fad09c73 771 mutex_unlock(&chip->reg_lock);
d78343d2
VD
772
773 if (err && err != -EOPNOTSUPP)
774 netdev_err(ds->ports[port].netdev, "failed to configure MAC\n");
dea87024
AL
775}
776
a605a0fe 777static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
91da11f8 778{
a605a0fe
AL
779 if (!chip->info->ops->stats_snapshot)
780 return -EOPNOTSUPP;
91da11f8 781
a605a0fe 782 return chip->info->ops->stats_snapshot(chip, port);
91da11f8
LB
783}
784
e413e7e1 785static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
dfafe449
AL
786 { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, },
787 { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, },
788 { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, },
789 { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, },
790 { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, },
791 { "in_pause", 4, 0x16, STATS_TYPE_BANK0, },
792 { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, },
793 { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, },
794 { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, },
795 { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, },
796 { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, },
797 { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, },
798 { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, },
799 { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, },
800 { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, },
801 { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, },
802 { "out_pause", 4, 0x15, STATS_TYPE_BANK0, },
803 { "excessive", 4, 0x11, STATS_TYPE_BANK0, },
804 { "collisions", 4, 0x1e, STATS_TYPE_BANK0, },
805 { "deferred", 4, 0x05, STATS_TYPE_BANK0, },
806 { "single", 4, 0x14, STATS_TYPE_BANK0, },
807 { "multiple", 4, 0x17, STATS_TYPE_BANK0, },
808 { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, },
809 { "late", 4, 0x1f, STATS_TYPE_BANK0, },
810 { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, },
811 { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, },
812 { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, },
813 { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, },
814 { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, },
815 { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, },
816 { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, },
817 { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, },
818 { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, },
819 { "in_discards", 4, 0x00, STATS_TYPE_BANK1, },
820 { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, },
821 { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, },
822 { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, },
823 { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, },
824 { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, },
825 { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, },
826 { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, },
827 { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, },
828 { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, },
829 { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, },
830 { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, },
831 { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, },
832 { "in_management", 4, 0x0f, STATS_TYPE_BANK1, },
833 { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, },
834 { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, },
835 { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, },
836 { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, },
837 { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, },
838 { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, },
839 { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, },
840 { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, },
841 { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, },
842 { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, },
843 { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, },
844 { "out_management", 4, 0x1f, STATS_TYPE_BANK1, },
e413e7e1
AL
845};
846
fad09c73 847static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
f5e2ed02 848 struct mv88e6xxx_hw_stat *s,
e0d8b615
AL
849 int port, u16 bank1_select,
850 u16 histogram)
80c4627b 851{
80c4627b
AL
852 u32 low;
853 u32 high = 0;
dfafe449 854 u16 reg = 0;
0e7b9925 855 int err;
80c4627b
AL
856 u64 value;
857
f5e2ed02 858 switch (s->type) {
dfafe449 859 case STATS_TYPE_PORT:
0e7b9925
AL
860 err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
861 if (err)
80c4627b
AL
862 return UINT64_MAX;
863
0e7b9925 864 low = reg;
80c4627b 865 if (s->sizeof_stat == 4) {
0e7b9925
AL
866 err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
867 if (err)
80c4627b 868 return UINT64_MAX;
0e7b9925 869 high = reg;
80c4627b 870 }
f5e2ed02 871 break;
dfafe449 872 case STATS_TYPE_BANK1:
e0d8b615 873 reg = bank1_select;
dfafe449
AL
874 /* fall through */
875 case STATS_TYPE_BANK0:
e0d8b615 876 reg |= s->reg | histogram;
7f9ef3af 877 mv88e6xxx_g1_stats_read(chip, reg, &low);
80c4627b 878 if (s->sizeof_stat == 8)
7f9ef3af 879 mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
80c4627b
AL
880 }
881 value = (((u64)high) << 16) | low;
882 return value;
883}
884
dfafe449
AL
885static void mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
886 uint8_t *data, int types)
91da11f8 887{
f5e2ed02
AL
888 struct mv88e6xxx_hw_stat *stat;
889 int i, j;
91da11f8 890
f5e2ed02
AL
891 for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
892 stat = &mv88e6xxx_hw_stats[i];
dfafe449 893 if (stat->type & types) {
f5e2ed02
AL
894 memcpy(data + j * ETH_GSTRING_LEN, stat->string,
895 ETH_GSTRING_LEN);
896 j++;
897 }
91da11f8 898 }
e413e7e1
AL
899}
900
dfafe449
AL
901static void mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
902 uint8_t *data)
903{
904 mv88e6xxx_stats_get_strings(chip, data,
905 STATS_TYPE_BANK0 | STATS_TYPE_PORT);
906}
907
908static void mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
909 uint8_t *data)
910{
911 mv88e6xxx_stats_get_strings(chip, data,
912 STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
913}
914
915static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
916 uint8_t *data)
e413e7e1 917{
04bed143 918 struct mv88e6xxx_chip *chip = ds->priv;
dfafe449
AL
919
920 if (chip->info->ops->stats_get_strings)
921 chip->info->ops->stats_get_strings(chip, data);
922}
923
924static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
925 int types)
926{
f5e2ed02
AL
927 struct mv88e6xxx_hw_stat *stat;
928 int i, j;
929
930 for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
931 stat = &mv88e6xxx_hw_stats[i];
dfafe449 932 if (stat->type & types)
f5e2ed02
AL
933 j++;
934 }
935 return j;
e413e7e1
AL
936}
937
dfafe449
AL
938static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
939{
940 return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
941 STATS_TYPE_PORT);
942}
943
944static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
945{
946 return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
947 STATS_TYPE_BANK1);
948}
949
950static int mv88e6xxx_get_sset_count(struct dsa_switch *ds)
951{
952 struct mv88e6xxx_chip *chip = ds->priv;
953
954 if (chip->info->ops->stats_get_sset_count)
955 return chip->info->ops->stats_get_sset_count(chip);
956
957 return 0;
958}
959
052f947f 960static void mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
e0d8b615
AL
961 uint64_t *data, int types,
962 u16 bank1_select, u16 histogram)
052f947f
AL
963{
964 struct mv88e6xxx_hw_stat *stat;
965 int i, j;
966
967 for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
968 stat = &mv88e6xxx_hw_stats[i];
969 if (stat->type & types) {
e0d8b615
AL
970 data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
971 bank1_select,
972 histogram);
052f947f
AL
973 j++;
974 }
975 }
976}
977
978static void mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
979 uint64_t *data)
980{
981 return mv88e6xxx_stats_get_stats(chip, port, data,
e0d8b615
AL
982 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
983 0, GLOBAL_STATS_OP_HIST_RX_TX);
052f947f
AL
984}
985
986static void mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
987 uint64_t *data)
988{
989 return mv88e6xxx_stats_get_stats(chip, port, data,
e0d8b615
AL
990 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
991 GLOBAL_STATS_OP_BANK_1_BIT_9,
992 GLOBAL_STATS_OP_HIST_RX_TX);
993}
994
995static void mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
996 uint64_t *data)
997{
998 return mv88e6xxx_stats_get_stats(chip, port, data,
999 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
1000 GLOBAL_STATS_OP_BANK_1_BIT_10, 0);
052f947f
AL
1001}
1002
1003static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
1004 uint64_t *data)
1005{
1006 if (chip->info->ops->stats_get_stats)
1007 chip->info->ops->stats_get_stats(chip, port, data);
1008}
1009
f81ec90f
VD
1010static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
1011 uint64_t *data)
e413e7e1 1012{
04bed143 1013 struct mv88e6xxx_chip *chip = ds->priv;
f5e2ed02 1014 int ret;
f5e2ed02 1015
fad09c73 1016 mutex_lock(&chip->reg_lock);
f5e2ed02 1017
a605a0fe 1018 ret = mv88e6xxx_stats_snapshot(chip, port);
f5e2ed02 1019 if (ret < 0) {
fad09c73 1020 mutex_unlock(&chip->reg_lock);
f5e2ed02
AL
1021 return;
1022 }
052f947f
AL
1023
1024 mv88e6xxx_get_stats(chip, port, data);
f5e2ed02 1025
fad09c73 1026 mutex_unlock(&chip->reg_lock);
e413e7e1
AL
1027}
1028
de227387
AL
1029static int mv88e6xxx_stats_set_histogram(struct mv88e6xxx_chip *chip)
1030{
1031 if (chip->info->ops->stats_set_histogram)
1032 return chip->info->ops->stats_set_histogram(chip);
1033
1034 return 0;
1035}
1036
f81ec90f 1037static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
a1ab91f3
GR
1038{
1039 return 32 * sizeof(u16);
1040}
1041
f81ec90f
VD
1042static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
1043 struct ethtool_regs *regs, void *_p)
a1ab91f3 1044{
04bed143 1045 struct mv88e6xxx_chip *chip = ds->priv;
0e7b9925
AL
1046 int err;
1047 u16 reg;
a1ab91f3
GR
1048 u16 *p = _p;
1049 int i;
1050
1051 regs->version = 0;
1052
1053 memset(p, 0xff, 32 * sizeof(u16));
1054
fad09c73 1055 mutex_lock(&chip->reg_lock);
23062513 1056
a1ab91f3 1057 for (i = 0; i < 32; i++) {
a1ab91f3 1058
0e7b9925
AL
1059 err = mv88e6xxx_port_read(chip, port, i, &reg);
1060 if (!err)
1061 p[i] = reg;
a1ab91f3 1062 }
23062513 1063
fad09c73 1064 mutex_unlock(&chip->reg_lock);
a1ab91f3
GR
1065}
1066
f81ec90f
VD
1067static int mv88e6xxx_get_eee(struct dsa_switch *ds, int port,
1068 struct ethtool_eee *e)
11b3b45d 1069{
04bed143 1070 struct mv88e6xxx_chip *chip = ds->priv;
9c93829c
VD
1071 u16 reg;
1072 int err;
11b3b45d 1073
fad09c73 1074 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEE))
aadbdb8a
VD
1075 return -EOPNOTSUPP;
1076
fad09c73 1077 mutex_lock(&chip->reg_lock);
2f40c698 1078
9c93829c
VD
1079 err = mv88e6xxx_phy_read(chip, port, 16, &reg);
1080 if (err)
2f40c698 1081 goto out;
11b3b45d
GR
1082
1083 e->eee_enabled = !!(reg & 0x0200);
1084 e->tx_lpi_enabled = !!(reg & 0x0100);
1085
0e7b9925 1086 err = mv88e6xxx_port_read(chip, port, PORT_STATUS, &reg);
9c93829c 1087 if (err)
2f40c698 1088 goto out;
11b3b45d 1089
cca8b133 1090 e->eee_active = !!(reg & PORT_STATUS_EEE);
2f40c698 1091out:
fad09c73 1092 mutex_unlock(&chip->reg_lock);
9c93829c
VD
1093
1094 return err;
11b3b45d
GR
1095}
1096
f81ec90f
VD
1097static int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
1098 struct phy_device *phydev, struct ethtool_eee *e)
11b3b45d 1099{
04bed143 1100 struct mv88e6xxx_chip *chip = ds->priv;
9c93829c
VD
1101 u16 reg;
1102 int err;
11b3b45d 1103
fad09c73 1104 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEE))
aadbdb8a
VD
1105 return -EOPNOTSUPP;
1106
fad09c73 1107 mutex_lock(&chip->reg_lock);
11b3b45d 1108
9c93829c
VD
1109 err = mv88e6xxx_phy_read(chip, port, 16, &reg);
1110 if (err)
2f40c698
AL
1111 goto out;
1112
9c93829c 1113 reg &= ~0x0300;
2f40c698
AL
1114 if (e->eee_enabled)
1115 reg |= 0x0200;
1116 if (e->tx_lpi_enabled)
1117 reg |= 0x0100;
1118
9c93829c 1119 err = mv88e6xxx_phy_write(chip, port, 16, reg);
2f40c698 1120out:
fad09c73 1121 mutex_unlock(&chip->reg_lock);
2f40c698 1122
9c93829c 1123 return err;
11b3b45d
GR
1124}
1125
fad09c73 1126static int _mv88e6xxx_port_based_vlan_map(struct mv88e6xxx_chip *chip, int port)
facd95b2 1127{
fad09c73 1128 struct dsa_switch *ds = chip->ds;
fae8a25e 1129 struct net_device *bridge = ds->ports[port].bridge_dev;
b7666efe 1130 u16 output_ports = 0;
b7666efe
VD
1131 int i;
1132
1133 /* allow CPU port or DSA link(s) to send frames to every port */
1134 if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
5a7921f4 1135 output_ports = ~0;
b7666efe 1136 } else {
370b4ffb 1137 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
b7666efe 1138 /* allow sending frames to every group member */
fae8a25e 1139 if (bridge && ds->ports[i].bridge_dev == bridge)
b7666efe
VD
1140 output_ports |= BIT(i);
1141
1142 /* allow sending frames to CPU port and DSA link(s) */
1143 if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
1144 output_ports |= BIT(i);
1145 }
1146 }
1147
1148 /* prevent frames from going back out of the port they came in on */
1149 output_ports &= ~BIT(port);
facd95b2 1150
5a7921f4 1151 return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
facd95b2
GR
1152}
1153
f81ec90f
VD
1154static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
1155 u8 state)
facd95b2 1156{
04bed143 1157 struct mv88e6xxx_chip *chip = ds->priv;
facd95b2 1158 int stp_state;
553eb544 1159 int err;
facd95b2
GR
1160
1161 switch (state) {
1162 case BR_STATE_DISABLED:
cca8b133 1163 stp_state = PORT_CONTROL_STATE_DISABLED;
facd95b2
GR
1164 break;
1165 case BR_STATE_BLOCKING:
1166 case BR_STATE_LISTENING:
cca8b133 1167 stp_state = PORT_CONTROL_STATE_BLOCKING;
facd95b2
GR
1168 break;
1169 case BR_STATE_LEARNING:
cca8b133 1170 stp_state = PORT_CONTROL_STATE_LEARNING;
facd95b2
GR
1171 break;
1172 case BR_STATE_FORWARDING:
1173 default:
cca8b133 1174 stp_state = PORT_CONTROL_STATE_FORWARDING;
facd95b2
GR
1175 break;
1176 }
1177
fad09c73 1178 mutex_lock(&chip->reg_lock);
e28def33 1179 err = mv88e6xxx_port_set_state(chip, port, stp_state);
fad09c73 1180 mutex_unlock(&chip->reg_lock);
553eb544
VD
1181
1182 if (err)
e28def33 1183 netdev_err(ds->ports[port].netdev, "failed to update state\n");
facd95b2
GR
1184}
1185
a2ac29d2
VD
1186static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
1187{
c3a7d4ad
VD
1188 int err;
1189
daefc943
VD
1190 err = mv88e6xxx_g1_atu_flush(chip, 0, true);
1191 if (err)
1192 return err;
1193
c3a7d4ad
VD
1194 err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
1195 if (err)
1196 return err;
1197
a2ac29d2
VD
1198 return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
1199}
1200
17a1594e
VD
1201static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
1202{
1203 u16 pvlan = 0;
1204
1205 if (!mv88e6xxx_has_pvt(chip))
1206 return -EOPNOTSUPP;
1207
1208 /* Skip the local source device, which uses in-chip port VLAN */
1209 if (dev != chip->ds->index)
1210 pvlan = mv88e6xxx_port_mask(chip);
1211
1212 return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
1213}
1214
81228996
VD
1215static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
1216{
17a1594e
VD
1217 int dev, port;
1218 int err;
1219
81228996
VD
1220 if (!mv88e6xxx_has_pvt(chip))
1221 return 0;
1222
1223 /* Clear 5 Bit Port for usage with Marvell Link Street devices:
1224 * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
1225 */
17a1594e
VD
1226 err = mv88e6xxx_g2_misc_4_bit_port(chip);
1227 if (err)
1228 return err;
1229
1230 for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) {
1231 for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) {
1232 err = mv88e6xxx_pvt_map(chip, dev, port);
1233 if (err)
1234 return err;
1235 }
1236 }
1237
1238 return 0;
81228996
VD
1239}
1240
749efcb8
VD
1241static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
1242{
1243 struct mv88e6xxx_chip *chip = ds->priv;
1244 int err;
1245
1246 mutex_lock(&chip->reg_lock);
e606ca36 1247 err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
749efcb8
VD
1248 mutex_unlock(&chip->reg_lock);
1249
1250 if (err)
1251 netdev_err(ds->ports[port].netdev, "failed to flush ATU\n");
1252}
1253
fad09c73 1254static int _mv88e6xxx_vtu_wait(struct mv88e6xxx_chip *chip)
6b17e864 1255{
a935c052 1256 return mv88e6xxx_g1_wait(chip, GLOBAL_VTU_OP, GLOBAL_VTU_OP_BUSY);
6b17e864
VD
1257}
1258
fad09c73 1259static int _mv88e6xxx_vtu_cmd(struct mv88e6xxx_chip *chip, u16 op)
6b17e864 1260{
a935c052 1261 int err;
6b17e864 1262
a935c052
VD
1263 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_OP, op);
1264 if (err)
1265 return err;
6b17e864 1266
fad09c73 1267 return _mv88e6xxx_vtu_wait(chip);
6b17e864
VD
1268}
1269
fad09c73 1270static int _mv88e6xxx_vtu_stu_flush(struct mv88e6xxx_chip *chip)
6b17e864
VD
1271{
1272 int ret;
1273
fad09c73 1274 ret = _mv88e6xxx_vtu_wait(chip);
6b17e864
VD
1275 if (ret < 0)
1276 return ret;
1277
fad09c73 1278 return _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_FLUSH_ALL);
6b17e864
VD
1279}
1280
fad09c73 1281static int _mv88e6xxx_vtu_stu_data_read(struct mv88e6xxx_chip *chip,
b4e47c0f 1282 struct mv88e6xxx_vtu_entry *entry,
b8fee957
VD
1283 unsigned int nibble_offset)
1284{
b8fee957 1285 u16 regs[3];
a935c052 1286 int i, err;
b8fee957
VD
1287
1288 for (i = 0; i < 3; ++i) {
a935c052 1289 u16 *reg = &regs[i];
b8fee957 1290
a935c052
VD
1291 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_DATA_0_3 + i, reg);
1292 if (err)
1293 return err;
b8fee957
VD
1294 }
1295
370b4ffb 1296 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
b8fee957
VD
1297 unsigned int shift = (i % 4) * 4 + nibble_offset;
1298 u16 reg = regs[i / 4];
1299
1300 entry->data[i] = (reg >> shift) & GLOBAL_VTU_STU_DATA_MASK;
1301 }
1302
1303 return 0;
1304}
1305
fad09c73 1306static int mv88e6xxx_vtu_data_read(struct mv88e6xxx_chip *chip,
b4e47c0f 1307 struct mv88e6xxx_vtu_entry *entry)
15d7d7d4 1308{
fad09c73 1309 return _mv88e6xxx_vtu_stu_data_read(chip, entry, 0);
15d7d7d4
VD
1310}
1311
fad09c73 1312static int mv88e6xxx_stu_data_read(struct mv88e6xxx_chip *chip,
b4e47c0f 1313 struct mv88e6xxx_vtu_entry *entry)
15d7d7d4 1314{
fad09c73 1315 return _mv88e6xxx_vtu_stu_data_read(chip, entry, 2);
15d7d7d4
VD
1316}
1317
fad09c73 1318static int _mv88e6xxx_vtu_stu_data_write(struct mv88e6xxx_chip *chip,
b4e47c0f 1319 struct mv88e6xxx_vtu_entry *entry,
7dad08d7
VD
1320 unsigned int nibble_offset)
1321{
7dad08d7 1322 u16 regs[3] = { 0 };
a935c052 1323 int i, err;
7dad08d7 1324
370b4ffb 1325 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
7dad08d7
VD
1326 unsigned int shift = (i % 4) * 4 + nibble_offset;
1327 u8 data = entry->data[i];
1328
1329 regs[i / 4] |= (data & GLOBAL_VTU_STU_DATA_MASK) << shift;
1330 }
1331
1332 for (i = 0; i < 3; ++i) {
a935c052
VD
1333 u16 reg = regs[i];
1334
1335 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_DATA_0_3 + i, reg);
1336 if (err)
1337 return err;
7dad08d7
VD
1338 }
1339
1340 return 0;
1341}
1342
fad09c73 1343static int mv88e6xxx_vtu_data_write(struct mv88e6xxx_chip *chip,
b4e47c0f 1344 struct mv88e6xxx_vtu_entry *entry)
15d7d7d4 1345{
fad09c73 1346 return _mv88e6xxx_vtu_stu_data_write(chip, entry, 0);
15d7d7d4
VD
1347}
1348
fad09c73 1349static int mv88e6xxx_stu_data_write(struct mv88e6xxx_chip *chip,
b4e47c0f 1350 struct mv88e6xxx_vtu_entry *entry)
15d7d7d4 1351{
fad09c73 1352 return _mv88e6xxx_vtu_stu_data_write(chip, entry, 2);
15d7d7d4
VD
1353}
1354
fad09c73 1355static int _mv88e6xxx_vtu_vid_write(struct mv88e6xxx_chip *chip, u16 vid)
36d04ba1 1356{
a935c052
VD
1357 return mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID,
1358 vid & GLOBAL_VTU_VID_MASK);
36d04ba1
VD
1359}
1360
fad09c73 1361static int _mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,
b4e47c0f 1362 struct mv88e6xxx_vtu_entry *entry)
b8fee957 1363{
b4e47c0f 1364 struct mv88e6xxx_vtu_entry next = { 0 };
a935c052
VD
1365 u16 val;
1366 int err;
b8fee957 1367
a935c052
VD
1368 err = _mv88e6xxx_vtu_wait(chip);
1369 if (err)
1370 return err;
b8fee957 1371
a935c052
VD
1372 err = _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_VTU_GET_NEXT);
1373 if (err)
1374 return err;
b8fee957 1375
a935c052
VD
1376 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_VID, &val);
1377 if (err)
1378 return err;
b8fee957 1379
a935c052
VD
1380 next.vid = val & GLOBAL_VTU_VID_MASK;
1381 next.valid = !!(val & GLOBAL_VTU_VID_VALID);
b8fee957
VD
1382
1383 if (next.valid) {
a935c052
VD
1384 err = mv88e6xxx_vtu_data_read(chip, &next);
1385 if (err)
1386 return err;
b8fee957 1387
6dc10bbc 1388 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G1_VTU_FID)) {
a935c052
VD
1389 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_FID, &val);
1390 if (err)
1391 return err;
b8fee957 1392
a935c052 1393 next.fid = val & GLOBAL_VTU_FID_MASK;
fad09c73 1394 } else if (mv88e6xxx_num_databases(chip) == 256) {
11ea809f
VD
1395 /* VTU DBNum[7:4] are located in VTU Operation 11:8, and
1396 * VTU DBNum[3:0] are located in VTU Operation 3:0
1397 */
a935c052
VD
1398 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_OP, &val);
1399 if (err)
1400 return err;
11ea809f 1401
a935c052
VD
1402 next.fid = (val & 0xf00) >> 4;
1403 next.fid |= val & 0xf;
2e7bd5ef 1404 }
b8fee957 1405
fad09c73 1406 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_STU)) {
a935c052
VD
1407 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_SID, &val);
1408 if (err)
1409 return err;
b8fee957 1410
a935c052 1411 next.sid = val & GLOBAL_VTU_SID_MASK;
b8fee957
VD
1412 }
1413 }
1414
1415 *entry = next;
1416 return 0;
1417}
1418
f81ec90f
VD
1419static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
1420 struct switchdev_obj_port_vlan *vlan,
1421 int (*cb)(struct switchdev_obj *obj))
ceff5eff 1422{
04bed143 1423 struct mv88e6xxx_chip *chip = ds->priv;
b4e47c0f 1424 struct mv88e6xxx_vtu_entry next;
ceff5eff
VD
1425 u16 pvid;
1426 int err;
1427
fad09c73 1428 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
54d77b5b
VD
1429 return -EOPNOTSUPP;
1430
fad09c73 1431 mutex_lock(&chip->reg_lock);
ceff5eff 1432
77064f37 1433 err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
ceff5eff
VD
1434 if (err)
1435 goto unlock;
1436
fad09c73 1437 err = _mv88e6xxx_vtu_vid_write(chip, GLOBAL_VTU_VID_MASK);
ceff5eff
VD
1438 if (err)
1439 goto unlock;
1440
1441 do {
fad09c73 1442 err = _mv88e6xxx_vtu_getnext(chip, &next);
ceff5eff
VD
1443 if (err)
1444 break;
1445
1446 if (!next.valid)
1447 break;
1448
1449 if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1450 continue;
1451
1452 /* reinit and dump this VLAN obj */
57d32310
VD
1453 vlan->vid_begin = next.vid;
1454 vlan->vid_end = next.vid;
ceff5eff
VD
1455 vlan->flags = 0;
1456
1457 if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED)
1458 vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
1459
1460 if (next.vid == pvid)
1461 vlan->flags |= BRIDGE_VLAN_INFO_PVID;
1462
1463 err = cb(&vlan->obj);
1464 if (err)
1465 break;
1466 } while (next.vid < GLOBAL_VTU_VID_MASK);
1467
1468unlock:
fad09c73 1469 mutex_unlock(&chip->reg_lock);
ceff5eff
VD
1470
1471 return err;
1472}
1473
fad09c73 1474static int _mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
b4e47c0f 1475 struct mv88e6xxx_vtu_entry *entry)
7dad08d7 1476{
11ea809f 1477 u16 op = GLOBAL_VTU_OP_VTU_LOAD_PURGE;
7dad08d7 1478 u16 reg = 0;
a935c052 1479 int err;
7dad08d7 1480
a935c052
VD
1481 err = _mv88e6xxx_vtu_wait(chip);
1482 if (err)
1483 return err;
7dad08d7
VD
1484
1485 if (!entry->valid)
1486 goto loadpurge;
1487
1488 /* Write port member tags */
a935c052
VD
1489 err = mv88e6xxx_vtu_data_write(chip, entry);
1490 if (err)
1491 return err;
7dad08d7 1492
fad09c73 1493 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_STU)) {
7dad08d7 1494 reg = entry->sid & GLOBAL_VTU_SID_MASK;
a935c052
VD
1495 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID, reg);
1496 if (err)
1497 return err;
b426e5f7 1498 }
7dad08d7 1499
6dc10bbc 1500 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G1_VTU_FID)) {
7dad08d7 1501 reg = entry->fid & GLOBAL_VTU_FID_MASK;
a935c052
VD
1502 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_FID, reg);
1503 if (err)
1504 return err;
fad09c73 1505 } else if (mv88e6xxx_num_databases(chip) == 256) {
11ea809f
VD
1506 /* VTU DBNum[7:4] are located in VTU Operation 11:8, and
1507 * VTU DBNum[3:0] are located in VTU Operation 3:0
1508 */
1509 op |= (entry->fid & 0xf0) << 8;
1510 op |= entry->fid & 0xf;
7dad08d7
VD
1511 }
1512
1513 reg = GLOBAL_VTU_VID_VALID;
1514loadpurge:
1515 reg |= entry->vid & GLOBAL_VTU_VID_MASK;
a935c052
VD
1516 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, reg);
1517 if (err)
1518 return err;
7dad08d7 1519
fad09c73 1520 return _mv88e6xxx_vtu_cmd(chip, op);
7dad08d7
VD
1521}
1522
fad09c73 1523static int _mv88e6xxx_stu_getnext(struct mv88e6xxx_chip *chip, u8 sid,
b4e47c0f 1524 struct mv88e6xxx_vtu_entry *entry)
0d3b33e6 1525{
b4e47c0f 1526 struct mv88e6xxx_vtu_entry next = { 0 };
a935c052
VD
1527 u16 val;
1528 int err;
0d3b33e6 1529
a935c052
VD
1530 err = _mv88e6xxx_vtu_wait(chip);
1531 if (err)
1532 return err;
0d3b33e6 1533
a935c052
VD
1534 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID,
1535 sid & GLOBAL_VTU_SID_MASK);
1536 if (err)
1537 return err;
0d3b33e6 1538
a935c052
VD
1539 err = _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_STU_GET_NEXT);
1540 if (err)
1541 return err;
0d3b33e6 1542
a935c052
VD
1543 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_SID, &val);
1544 if (err)
1545 return err;
0d3b33e6 1546
a935c052 1547 next.sid = val & GLOBAL_VTU_SID_MASK;
0d3b33e6 1548
a935c052
VD
1549 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_VID, &val);
1550 if (err)
1551 return err;
0d3b33e6 1552
a935c052 1553 next.valid = !!(val & GLOBAL_VTU_VID_VALID);
0d3b33e6
VD
1554
1555 if (next.valid) {
a935c052
VD
1556 err = mv88e6xxx_stu_data_read(chip, &next);
1557 if (err)
1558 return err;
0d3b33e6
VD
1559 }
1560
1561 *entry = next;
1562 return 0;
1563}
1564
fad09c73 1565static int _mv88e6xxx_stu_loadpurge(struct mv88e6xxx_chip *chip,
b4e47c0f 1566 struct mv88e6xxx_vtu_entry *entry)
0d3b33e6
VD
1567{
1568 u16 reg = 0;
a935c052 1569 int err;
0d3b33e6 1570
a935c052
VD
1571 err = _mv88e6xxx_vtu_wait(chip);
1572 if (err)
1573 return err;
0d3b33e6
VD
1574
1575 if (!entry->valid)
1576 goto loadpurge;
1577
1578 /* Write port states */
a935c052
VD
1579 err = mv88e6xxx_stu_data_write(chip, entry);
1580 if (err)
1581 return err;
0d3b33e6
VD
1582
1583 reg = GLOBAL_VTU_VID_VALID;
1584loadpurge:
a935c052
VD
1585 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, reg);
1586 if (err)
1587 return err;
0d3b33e6
VD
1588
1589 reg = entry->sid & GLOBAL_VTU_SID_MASK;
a935c052
VD
1590 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID, reg);
1591 if (err)
1592 return err;
0d3b33e6 1593
fad09c73 1594 return _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE);
0d3b33e6
VD
1595}
1596
d7f435f9 1597static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
3285f9e8
VD
1598{
1599 DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
b4e47c0f 1600 struct mv88e6xxx_vtu_entry vlan;
2db9ce1f 1601 int i, err;
3285f9e8
VD
1602
1603 bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
1604
2db9ce1f 1605 /* Set every FID bit used by the (un)bridged ports */
370b4ffb 1606 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
b4e48c50 1607 err = mv88e6xxx_port_get_fid(chip, i, fid);
2db9ce1f
VD
1608 if (err)
1609 return err;
1610
1611 set_bit(*fid, fid_bitmap);
1612 }
1613
3285f9e8 1614 /* Set every FID bit used by the VLAN entries */
fad09c73 1615 err = _mv88e6xxx_vtu_vid_write(chip, GLOBAL_VTU_VID_MASK);
3285f9e8
VD
1616 if (err)
1617 return err;
1618
1619 do {
fad09c73 1620 err = _mv88e6xxx_vtu_getnext(chip, &vlan);
3285f9e8
VD
1621 if (err)
1622 return err;
1623
1624 if (!vlan.valid)
1625 break;
1626
1627 set_bit(vlan.fid, fid_bitmap);
1628 } while (vlan.vid < GLOBAL_VTU_VID_MASK);
1629
1630 /* The reset value 0x000 is used to indicate that multiple address
1631 * databases are not needed. Return the next positive available.
1632 */
1633 *fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1);
fad09c73 1634 if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
3285f9e8
VD
1635 return -ENOSPC;
1636
1637 /* Clear the database */
daefc943 1638 return mv88e6xxx_g1_atu_flush(chip, *fid, true);
3285f9e8
VD
1639}
1640
fad09c73 1641static int _mv88e6xxx_vtu_new(struct mv88e6xxx_chip *chip, u16 vid,
b4e47c0f 1642 struct mv88e6xxx_vtu_entry *entry)
0d3b33e6 1643{
fad09c73 1644 struct dsa_switch *ds = chip->ds;
b4e47c0f 1645 struct mv88e6xxx_vtu_entry vlan = {
0d3b33e6
VD
1646 .valid = true,
1647 .vid = vid,
1648 };
3285f9e8
VD
1649 int i, err;
1650
d7f435f9 1651 err = mv88e6xxx_atu_new(chip, &vlan.fid);
3285f9e8
VD
1652 if (err)
1653 return err;
0d3b33e6 1654
3d131f07 1655 /* exclude all ports except the CPU and DSA ports */
370b4ffb 1656 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
3d131f07
VD
1657 vlan.data[i] = dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i)
1658 ? GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED
1659 : GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
0d3b33e6 1660
fad09c73 1661 if (mv88e6xxx_6097_family(chip) || mv88e6xxx_6165_family(chip) ||
a75961d0
GC
1662 mv88e6xxx_6351_family(chip) || mv88e6xxx_6352_family(chip) ||
1663 mv88e6xxx_6341_family(chip)) {
b4e47c0f 1664 struct mv88e6xxx_vtu_entry vstp;
0d3b33e6
VD
1665
1666 /* Adding a VTU entry requires a valid STU entry. As VSTP is not
1667 * implemented, only one STU entry is needed to cover all VTU
1668 * entries. Thus, validate the SID 0.
1669 */
1670 vlan.sid = 0;
fad09c73 1671 err = _mv88e6xxx_stu_getnext(chip, GLOBAL_VTU_SID_MASK, &vstp);
0d3b33e6
VD
1672 if (err)
1673 return err;
1674
1675 if (vstp.sid != vlan.sid || !vstp.valid) {
1676 memset(&vstp, 0, sizeof(vstp));
1677 vstp.valid = true;
1678 vstp.sid = vlan.sid;
1679
fad09c73 1680 err = _mv88e6xxx_stu_loadpurge(chip, &vstp);
0d3b33e6
VD
1681 if (err)
1682 return err;
1683 }
0d3b33e6
VD
1684 }
1685
1686 *entry = vlan;
1687 return 0;
1688}
1689
fad09c73 1690static int _mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
b4e47c0f 1691 struct mv88e6xxx_vtu_entry *entry, bool creat)
2fb5ef09
VD
1692{
1693 int err;
1694
1695 if (!vid)
1696 return -EINVAL;
1697
fad09c73 1698 err = _mv88e6xxx_vtu_vid_write(chip, vid - 1);
2fb5ef09
VD
1699 if (err)
1700 return err;
1701
fad09c73 1702 err = _mv88e6xxx_vtu_getnext(chip, entry);
2fb5ef09
VD
1703 if (err)
1704 return err;
1705
1706 if (entry->vid != vid || !entry->valid) {
1707 if (!creat)
1708 return -EOPNOTSUPP;
1709 /* -ENOENT would've been more appropriate, but switchdev expects
1710 * -EOPNOTSUPP to inform bridge about an eventual software VLAN.
1711 */
1712
fad09c73 1713 err = _mv88e6xxx_vtu_new(chip, vid, entry);
2fb5ef09
VD
1714 }
1715
1716 return err;
1717}
1718
da9c359e
VD
1719static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
1720 u16 vid_begin, u16 vid_end)
1721{
04bed143 1722 struct mv88e6xxx_chip *chip = ds->priv;
b4e47c0f 1723 struct mv88e6xxx_vtu_entry vlan;
da9c359e
VD
1724 int i, err;
1725
1726 if (!vid_begin)
1727 return -EOPNOTSUPP;
1728
fad09c73 1729 mutex_lock(&chip->reg_lock);
da9c359e 1730
fad09c73 1731 err = _mv88e6xxx_vtu_vid_write(chip, vid_begin - 1);
da9c359e
VD
1732 if (err)
1733 goto unlock;
1734
1735 do {
fad09c73 1736 err = _mv88e6xxx_vtu_getnext(chip, &vlan);
da9c359e
VD
1737 if (err)
1738 goto unlock;
1739
1740 if (!vlan.valid)
1741 break;
1742
1743 if (vlan.vid > vid_end)
1744 break;
1745
370b4ffb 1746 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
da9c359e
VD
1747 if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
1748 continue;
1749
66e2809d
AL
1750 if (!ds->ports[port].netdev)
1751 continue;
1752
da9c359e
VD
1753 if (vlan.data[i] ==
1754 GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1755 continue;
1756
fae8a25e
VD
1757 if (ds->ports[i].bridge_dev ==
1758 ds->ports[port].bridge_dev)
da9c359e
VD
1759 break; /* same bridge, check next VLAN */
1760
fae8a25e 1761 if (!ds->ports[i].bridge_dev)
66e2809d
AL
1762 continue;
1763
c8b09808 1764 netdev_warn(ds->ports[port].netdev,
da9c359e
VD
1765 "hardware VLAN %d already used by %s\n",
1766 vlan.vid,
fae8a25e 1767 netdev_name(ds->ports[i].bridge_dev));
da9c359e
VD
1768 err = -EOPNOTSUPP;
1769 goto unlock;
1770 }
1771 } while (vlan.vid < vid_end);
1772
1773unlock:
fad09c73 1774 mutex_unlock(&chip->reg_lock);
da9c359e
VD
1775
1776 return err;
1777}
1778
f81ec90f
VD
1779static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
1780 bool vlan_filtering)
214cdb99 1781{
04bed143 1782 struct mv88e6xxx_chip *chip = ds->priv;
385a0995 1783 u16 mode = vlan_filtering ? PORT_CONTROL_2_8021Q_SECURE :
214cdb99 1784 PORT_CONTROL_2_8021Q_DISABLED;
0e7b9925 1785 int err;
214cdb99 1786
fad09c73 1787 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
54d77b5b
VD
1788 return -EOPNOTSUPP;
1789
fad09c73 1790 mutex_lock(&chip->reg_lock);
385a0995 1791 err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
fad09c73 1792 mutex_unlock(&chip->reg_lock);
214cdb99 1793
0e7b9925 1794 return err;
214cdb99
VD
1795}
1796
57d32310
VD
1797static int
1798mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
1799 const struct switchdev_obj_port_vlan *vlan,
1800 struct switchdev_trans *trans)
76e398a6 1801{
04bed143 1802 struct mv88e6xxx_chip *chip = ds->priv;
da9c359e
VD
1803 int err;
1804
fad09c73 1805 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
54d77b5b
VD
1806 return -EOPNOTSUPP;
1807
da9c359e
VD
1808 /* If the requested port doesn't belong to the same bridge as the VLAN
1809 * members, do not support it (yet) and fallback to software VLAN.
1810 */
1811 err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
1812 vlan->vid_end);
1813 if (err)
1814 return err;
1815
76e398a6
VD
1816 /* We don't need any dynamic resource from the kernel (yet),
1817 * so skip the prepare phase.
1818 */
1819 return 0;
1820}
1821
fad09c73 1822static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
158bc065 1823 u16 vid, bool untagged)
0d3b33e6 1824{
b4e47c0f 1825 struct mv88e6xxx_vtu_entry vlan;
0d3b33e6
VD
1826 int err;
1827
fad09c73 1828 err = _mv88e6xxx_vtu_get(chip, vid, &vlan, true);
0d3b33e6 1829 if (err)
76e398a6 1830 return err;
0d3b33e6 1831
0d3b33e6
VD
1832 vlan.data[port] = untagged ?
1833 GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED :
1834 GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
1835
fad09c73 1836 return _mv88e6xxx_vtu_loadpurge(chip, &vlan);
76e398a6
VD
1837}
1838
f81ec90f
VD
1839static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
1840 const struct switchdev_obj_port_vlan *vlan,
1841 struct switchdev_trans *trans)
76e398a6 1842{
04bed143 1843 struct mv88e6xxx_chip *chip = ds->priv;
76e398a6
VD
1844 bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1845 bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1846 u16 vid;
76e398a6 1847
fad09c73 1848 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
54d77b5b
VD
1849 return;
1850
fad09c73 1851 mutex_lock(&chip->reg_lock);
76e398a6 1852
4d5770b3 1853 for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
fad09c73 1854 if (_mv88e6xxx_port_vlan_add(chip, port, vid, untagged))
c8b09808
AL
1855 netdev_err(ds->ports[port].netdev,
1856 "failed to add VLAN %d%c\n",
4d5770b3 1857 vid, untagged ? 'u' : 't');
76e398a6 1858
77064f37 1859 if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end))
c8b09808 1860 netdev_err(ds->ports[port].netdev, "failed to set PVID %d\n",
4d5770b3 1861 vlan->vid_end);
0d3b33e6 1862
fad09c73 1863 mutex_unlock(&chip->reg_lock);
0d3b33e6
VD
1864}
1865
fad09c73 1866static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
158bc065 1867 int port, u16 vid)
7dad08d7 1868{
fad09c73 1869 struct dsa_switch *ds = chip->ds;
b4e47c0f 1870 struct mv88e6xxx_vtu_entry vlan;
7dad08d7
VD
1871 int i, err;
1872
fad09c73 1873 err = _mv88e6xxx_vtu_get(chip, vid, &vlan, false);
7dad08d7 1874 if (err)
76e398a6 1875 return err;
7dad08d7 1876
2fb5ef09
VD
1877 /* Tell switchdev if this VLAN is handled in software */
1878 if (vlan.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
3c06f08b 1879 return -EOPNOTSUPP;
7dad08d7
VD
1880
1881 vlan.data[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1882
1883 /* keep the VLAN unless all ports are excluded */
f02bdffc 1884 vlan.valid = false;
370b4ffb 1885 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
3d131f07 1886 if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
7dad08d7
VD
1887 continue;
1888
1889 if (vlan.data[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
f02bdffc 1890 vlan.valid = true;
7dad08d7
VD
1891 break;
1892 }
1893 }
1894
fad09c73 1895 err = _mv88e6xxx_vtu_loadpurge(chip, &vlan);
76e398a6
VD
1896 if (err)
1897 return err;
1898
e606ca36 1899 return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
76e398a6
VD
1900}
1901
f81ec90f
VD
1902static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
1903 const struct switchdev_obj_port_vlan *vlan)
76e398a6 1904{
04bed143 1905 struct mv88e6xxx_chip *chip = ds->priv;
76e398a6
VD
1906 u16 pvid, vid;
1907 int err = 0;
1908
fad09c73 1909 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
54d77b5b
VD
1910 return -EOPNOTSUPP;
1911
fad09c73 1912 mutex_lock(&chip->reg_lock);
76e398a6 1913
77064f37 1914 err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
7dad08d7
VD
1915 if (err)
1916 goto unlock;
1917
76e398a6 1918 for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
fad09c73 1919 err = _mv88e6xxx_port_vlan_del(chip, port, vid);
76e398a6
VD
1920 if (err)
1921 goto unlock;
1922
1923 if (vid == pvid) {
77064f37 1924 err = mv88e6xxx_port_set_pvid(chip, port, 0);
76e398a6
VD
1925 if (err)
1926 goto unlock;
1927 }
1928 }
1929
7dad08d7 1930unlock:
fad09c73 1931 mutex_unlock(&chip->reg_lock);
7dad08d7
VD
1932
1933 return err;
1934}
1935
83dabd1f
VD
1936static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
1937 const unsigned char *addr, u16 vid,
1938 u8 state)
fd231c82 1939{
b4e47c0f 1940 struct mv88e6xxx_vtu_entry vlan;
88472939 1941 struct mv88e6xxx_atu_entry entry;
3285f9e8
VD
1942 int err;
1943
2db9ce1f
VD
1944 /* Null VLAN ID corresponds to the port private database */
1945 if (vid == 0)
b4e48c50 1946 err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
2db9ce1f 1947 else
fad09c73 1948 err = _mv88e6xxx_vtu_get(chip, vid, &vlan, false);
3285f9e8
VD
1949 if (err)
1950 return err;
fd231c82 1951
dabc1a96
VD
1952 entry.state = GLOBAL_ATU_DATA_STATE_UNUSED;
1953 ether_addr_copy(entry.mac, addr);
1954 eth_addr_dec(entry.mac);
1955
1956 err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry);
88472939
VD
1957 if (err)
1958 return err;
1959
dabc1a96
VD
1960 /* Initialize a fresh ATU entry if it isn't found */
1961 if (entry.state == GLOBAL_ATU_DATA_STATE_UNUSED ||
1962 !ether_addr_equal(entry.mac, addr)) {
1963 memset(&entry, 0, sizeof(entry));
1964 ether_addr_copy(entry.mac, addr);
1965 }
1966
88472939
VD
1967 /* Purge the ATU entry only if no port is using it anymore */
1968 if (state == GLOBAL_ATU_DATA_STATE_UNUSED) {
01bd96c8
VD
1969 entry.portvec &= ~BIT(port);
1970 if (!entry.portvec)
88472939
VD
1971 entry.state = GLOBAL_ATU_DATA_STATE_UNUSED;
1972 } else {
01bd96c8 1973 entry.portvec |= BIT(port);
88472939 1974 entry.state = state;
fd231c82
VD
1975 }
1976
9c13c026 1977 return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry);
87820510
VD
1978}
1979
f81ec90f
VD
1980static int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port,
1981 const struct switchdev_obj_port_fdb *fdb,
1982 struct switchdev_trans *trans)
146a3206
VD
1983{
1984 /* We don't need any dynamic resource from the kernel (yet),
1985 * so skip the prepare phase.
1986 */
1987 return 0;
1988}
1989
f81ec90f
VD
1990static void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
1991 const struct switchdev_obj_port_fdb *fdb,
1992 struct switchdev_trans *trans)
87820510 1993{
04bed143 1994 struct mv88e6xxx_chip *chip = ds->priv;
87820510 1995
fad09c73 1996 mutex_lock(&chip->reg_lock);
83dabd1f
VD
1997 if (mv88e6xxx_port_db_load_purge(chip, port, fdb->addr, fdb->vid,
1998 GLOBAL_ATU_DATA_STATE_UC_STATIC))
1999 netdev_err(ds->ports[port].netdev, "failed to load unicast MAC address\n");
fad09c73 2000 mutex_unlock(&chip->reg_lock);
87820510
VD
2001}
2002
f81ec90f
VD
2003static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
2004 const struct switchdev_obj_port_fdb *fdb)
87820510 2005{
04bed143 2006 struct mv88e6xxx_chip *chip = ds->priv;
83dabd1f 2007 int err;
87820510 2008
fad09c73 2009 mutex_lock(&chip->reg_lock);
83dabd1f
VD
2010 err = mv88e6xxx_port_db_load_purge(chip, port, fdb->addr, fdb->vid,
2011 GLOBAL_ATU_DATA_STATE_UNUSED);
fad09c73 2012 mutex_unlock(&chip->reg_lock);
87820510 2013
83dabd1f 2014 return err;
87820510
VD
2015}
2016
83dabd1f
VD
2017static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
2018 u16 fid, u16 vid, int port,
2019 struct switchdev_obj *obj,
2020 int (*cb)(struct switchdev_obj *obj))
74b6ba0d 2021{
dabc1a96 2022 struct mv88e6xxx_atu_entry addr;
74b6ba0d
VD
2023 int err;
2024
dabc1a96
VD
2025 addr.state = GLOBAL_ATU_DATA_STATE_UNUSED;
2026 eth_broadcast_addr(addr.mac);
74b6ba0d
VD
2027
2028 do {
dabc1a96 2029 err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
74b6ba0d 2030 if (err)
83dabd1f 2031 return err;
74b6ba0d
VD
2032
2033 if (addr.state == GLOBAL_ATU_DATA_STATE_UNUSED)
2034 break;
2035
01bd96c8 2036 if (addr.trunk || (addr.portvec & BIT(port)) == 0)
83dabd1f
VD
2037 continue;
2038
2039 if (obj->id == SWITCHDEV_OBJ_ID_PORT_FDB) {
2040 struct switchdev_obj_port_fdb *fdb;
74b6ba0d 2041
83dabd1f
VD
2042 if (!is_unicast_ether_addr(addr.mac))
2043 continue;
2044
2045 fdb = SWITCHDEV_OBJ_PORT_FDB(obj);
74b6ba0d
VD
2046 fdb->vid = vid;
2047 ether_addr_copy(fdb->addr, addr.mac);
83dabd1f
VD
2048 if (addr.state == GLOBAL_ATU_DATA_STATE_UC_STATIC)
2049 fdb->ndm_state = NUD_NOARP;
2050 else
2051 fdb->ndm_state = NUD_REACHABLE;
7df8fbdd
VD
2052 } else if (obj->id == SWITCHDEV_OBJ_ID_PORT_MDB) {
2053 struct switchdev_obj_port_mdb *mdb;
2054
2055 if (!is_multicast_ether_addr(addr.mac))
2056 continue;
2057
2058 mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
2059 mdb->vid = vid;
2060 ether_addr_copy(mdb->addr, addr.mac);
83dabd1f
VD
2061 } else {
2062 return -EOPNOTSUPP;
74b6ba0d 2063 }
83dabd1f
VD
2064
2065 err = cb(obj);
2066 if (err)
2067 return err;
74b6ba0d
VD
2068 } while (!is_broadcast_ether_addr(addr.mac));
2069
2070 return err;
2071}
2072
83dabd1f
VD
2073static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
2074 struct switchdev_obj *obj,
2075 int (*cb)(struct switchdev_obj *obj))
f33475bd 2076{
b4e47c0f 2077 struct mv88e6xxx_vtu_entry vlan = {
f33475bd
VD
2078 .vid = GLOBAL_VTU_VID_MASK, /* all ones */
2079 };
2db9ce1f 2080 u16 fid;
f33475bd
VD
2081 int err;
2082
2db9ce1f 2083 /* Dump port's default Filtering Information Database (VLAN ID 0) */
b4e48c50 2084 err = mv88e6xxx_port_get_fid(chip, port, &fid);
2db9ce1f 2085 if (err)
83dabd1f 2086 return err;
2db9ce1f 2087
83dabd1f 2088 err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, obj, cb);
2db9ce1f 2089 if (err)
83dabd1f 2090 return err;
2db9ce1f 2091
74b6ba0d 2092 /* Dump VLANs' Filtering Information Databases */
fad09c73 2093 err = _mv88e6xxx_vtu_vid_write(chip, vlan.vid);
f33475bd 2094 if (err)
83dabd1f 2095 return err;
f33475bd
VD
2096
2097 do {
fad09c73 2098 err = _mv88e6xxx_vtu_getnext(chip, &vlan);
f33475bd 2099 if (err)
83dabd1f 2100 return err;
f33475bd
VD
2101
2102 if (!vlan.valid)
2103 break;
2104
83dabd1f
VD
2105 err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port,
2106 obj, cb);
f33475bd 2107 if (err)
83dabd1f 2108 return err;
f33475bd
VD
2109 } while (vlan.vid < GLOBAL_VTU_VID_MASK);
2110
83dabd1f
VD
2111 return err;
2112}
2113
2114static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
2115 struct switchdev_obj_port_fdb *fdb,
2116 int (*cb)(struct switchdev_obj *obj))
2117{
04bed143 2118 struct mv88e6xxx_chip *chip = ds->priv;
83dabd1f
VD
2119 int err;
2120
2121 mutex_lock(&chip->reg_lock);
2122 err = mv88e6xxx_port_db_dump(chip, port, &fdb->obj, cb);
fad09c73 2123 mutex_unlock(&chip->reg_lock);
f33475bd
VD
2124
2125 return err;
2126}
2127
f81ec90f 2128static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
fae8a25e 2129 struct net_device *br)
e79a8bcb 2130{
04bed143 2131 struct mv88e6xxx_chip *chip = ds->priv;
1d9619d5 2132 int i, err = 0;
466dfa07 2133
fad09c73 2134 mutex_lock(&chip->reg_lock);
466dfa07 2135
fae8a25e 2136 /* Remap each port's VLANTable */
370b4ffb 2137 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
fae8a25e 2138 if (ds->ports[i].bridge_dev == br) {
fad09c73 2139 err = _mv88e6xxx_port_based_vlan_map(chip, i);
b7666efe
VD
2140 if (err)
2141 break;
2142 }
2143 }
2144
fad09c73 2145 mutex_unlock(&chip->reg_lock);
a6692754 2146
466dfa07 2147 return err;
e79a8bcb
VD
2148}
2149
f123f2fb
VD
2150static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
2151 struct net_device *br)
66d9cd0f 2152{
04bed143 2153 struct mv88e6xxx_chip *chip = ds->priv;
16bfa702 2154 int i;
466dfa07 2155
fad09c73 2156 mutex_lock(&chip->reg_lock);
466dfa07 2157
fae8a25e 2158 /* Remap each port's VLANTable */
370b4ffb 2159 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
fae8a25e 2160 if (i == port || ds->ports[i].bridge_dev == br)
fad09c73 2161 if (_mv88e6xxx_port_based_vlan_map(chip, i))
c8b09808
AL
2162 netdev_warn(ds->ports[i].netdev,
2163 "failed to remap\n");
b7666efe 2164
fad09c73 2165 mutex_unlock(&chip->reg_lock);
66d9cd0f
VD
2166}
2167
17e708ba
VD
2168static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
2169{
2170 if (chip->info->ops->reset)
2171 return chip->info->ops->reset(chip);
2172
2173 return 0;
2174}
2175
309eca6d
VD
2176static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
2177{
2178 struct gpio_desc *gpiod = chip->reset;
2179
2180 /* If there is a GPIO connected to the reset pin, toggle it */
2181 if (gpiod) {
2182 gpiod_set_value_cansleep(gpiod, 1);
2183 usleep_range(10000, 20000);
2184 gpiod_set_value_cansleep(gpiod, 0);
2185 usleep_range(10000, 20000);
2186 }
2187}
2188
4ac4b5a6 2189static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
552238b5 2190{
4ac4b5a6 2191 int i, err;
552238b5 2192
4ac4b5a6 2193 /* Set all ports to the Disabled state */
370b4ffb 2194 for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
e28def33
VD
2195 err = mv88e6xxx_port_set_state(chip, i,
2196 PORT_CONTROL_STATE_DISABLED);
0e7b9925
AL
2197 if (err)
2198 return err;
552238b5
VD
2199 }
2200
4ac4b5a6
VD
2201 /* Wait for transmit queues to drain,
2202 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
2203 */
552238b5
VD
2204 usleep_range(2000, 4000);
2205
4ac4b5a6
VD
2206 return 0;
2207}
2208
2209static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
2210{
4ac4b5a6
VD
2211 int err;
2212
2213 err = mv88e6xxx_disable_ports(chip);
2214 if (err)
2215 return err;
2216
309eca6d 2217 mv88e6xxx_hardware_reset(chip);
552238b5 2218
17e708ba 2219 return mv88e6xxx_software_reset(chip);
552238b5
VD
2220}
2221
09cb7dfd 2222static int mv88e6xxx_serdes_power_on(struct mv88e6xxx_chip *chip)
13a7ebb3 2223{
09cb7dfd
VD
2224 u16 val;
2225 int err;
13a7ebb3 2226
09cb7dfd
VD
2227 /* Clear Power Down bit */
2228 err = mv88e6xxx_serdes_read(chip, MII_BMCR, &val);
2229 if (err)
2230 return err;
13a7ebb3 2231
09cb7dfd
VD
2232 if (val & BMCR_PDOWN) {
2233 val &= ~BMCR_PDOWN;
2234 err = mv88e6xxx_serdes_write(chip, MII_BMCR, val);
13a7ebb3
PU
2235 }
2236
09cb7dfd 2237 return err;
13a7ebb3
PU
2238}
2239
4314557c
VD
2240static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
2241 enum mv88e6xxx_frame_mode frame, u16 egress,
2242 u16 etype)
56995cbc
AL
2243{
2244 int err;
2245
4314557c
VD
2246 if (!chip->info->ops->port_set_frame_mode)
2247 return -EOPNOTSUPP;
2248
2249 err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
56995cbc
AL
2250 if (err)
2251 return err;
2252
4314557c
VD
2253 err = chip->info->ops->port_set_frame_mode(chip, port, frame);
2254 if (err)
2255 return err;
2256
2257 if (chip->info->ops->port_set_ether_type)
2258 return chip->info->ops->port_set_ether_type(chip, port, etype);
2259
2260 return 0;
56995cbc
AL
2261}
2262
4314557c 2263static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
56995cbc 2264{
4314557c
VD
2265 return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
2266 PORT_CONTROL_EGRESS_UNMODIFIED,
2267 PORT_ETH_TYPE_DEFAULT);
2268}
56995cbc 2269
4314557c
VD
2270static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
2271{
2272 return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
2273 PORT_CONTROL_EGRESS_UNMODIFIED,
2274 PORT_ETH_TYPE_DEFAULT);
2275}
56995cbc 2276
4314557c
VD
2277static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
2278{
2279 return mv88e6xxx_set_port_mode(chip, port,
2280 MV88E6XXX_FRAME_MODE_ETHERTYPE,
2281 PORT_CONTROL_EGRESS_ADD_TAG, ETH_P_EDSA);
2282}
56995cbc 2283
4314557c
VD
2284static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port)
2285{
2286 if (dsa_is_dsa_port(chip->ds, port))
2287 return mv88e6xxx_set_port_mode_dsa(chip, port);
56995cbc 2288
4314557c
VD
2289 if (dsa_is_normal_port(chip->ds, port))
2290 return mv88e6xxx_set_port_mode_normal(chip, port);
56995cbc 2291
4314557c
VD
2292 /* Setup CPU port mode depending on its supported tag format */
2293 if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA)
2294 return mv88e6xxx_set_port_mode_dsa(chip, port);
56995cbc 2295
4314557c
VD
2296 if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA)
2297 return mv88e6xxx_set_port_mode_edsa(chip, port);
56995cbc 2298
4314557c 2299 return -EINVAL;
56995cbc
AL
2300}
2301
601aeed3 2302static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
56995cbc 2303{
601aeed3 2304 bool message = dsa_is_dsa_port(chip->ds, port);
56995cbc 2305
601aeed3 2306 return mv88e6xxx_port_set_message_port(chip, port, message);
4314557c 2307}
56995cbc 2308
601aeed3 2309static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
4314557c 2310{
601aeed3 2311 bool flood = port == dsa_upstream_port(chip->ds);
56995cbc 2312
601aeed3
VD
2313 /* Upstream ports flood frames with unknown unicast or multicast DA */
2314 if (chip->info->ops->port_set_egress_floods)
2315 return chip->info->ops->port_set_egress_floods(chip, port,
2316 flood, flood);
ea698f4f 2317
601aeed3 2318 return 0;
ea698f4f
VD
2319}
2320
fad09c73 2321static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
d827e88a 2322{
fad09c73 2323 struct dsa_switch *ds = chip->ds;
0e7b9925 2324 int err;
54d792f2 2325 u16 reg;
d827e88a 2326
d78343d2
VD
2327 /* MAC Forcing register: don't force link, speed, duplex or flow control
2328 * state to any particular values on physical ports, but force the CPU
2329 * port and all DSA ports to their maximum bandwidth and full duplex.
2330 */
2331 if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
2332 err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
2333 SPEED_MAX, DUPLEX_FULL,
2334 PHY_INTERFACE_MODE_NA);
2335 else
2336 err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
2337 SPEED_UNFORCED, DUPLEX_UNFORCED,
2338 PHY_INTERFACE_MODE_NA);
2339 if (err)
2340 return err;
54d792f2
AL
2341
2342 /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
2343 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
2344 * tunneling, determine priority by looking at 802.1p and IP
2345 * priority fields (IP prio has precedence), and set STP state
2346 * to Forwarding.
2347 *
2348 * If this is the CPU link, use DSA or EDSA tagging depending
2349 * on which tagging mode was configured.
2350 *
2351 * If this is a link to another switch, use DSA tagging mode.
2352 *
2353 * If this is the upstream port for this switch, enable
2354 * forwarding of unknown unicasts and multicasts.
2355 */
56995cbc 2356 reg = PORT_CONTROL_IGMP_MLD_SNOOP |
54d792f2
AL
2357 PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP |
2358 PORT_CONTROL_STATE_FORWARDING;
56995cbc
AL
2359 err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
2360 if (err)
2361 return err;
6083ce71 2362
601aeed3 2363 err = mv88e6xxx_setup_port_mode(chip, port);
56995cbc
AL
2364 if (err)
2365 return err;
54d792f2 2366
601aeed3 2367 err = mv88e6xxx_setup_egress_floods(chip, port);
4314557c
VD
2368 if (err)
2369 return err;
2370
13a7ebb3
PU
2371 /* If this port is connected to a SerDes, make sure the SerDes is not
2372 * powered down.
2373 */
09cb7dfd 2374 if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_SERDES)) {
0e7b9925
AL
2375 err = mv88e6xxx_port_read(chip, port, PORT_STATUS, &reg);
2376 if (err)
2377 return err;
2378 reg &= PORT_STATUS_CMODE_MASK;
2379 if ((reg == PORT_STATUS_CMODE_100BASE_X) ||
2380 (reg == PORT_STATUS_CMODE_1000BASE_X) ||
2381 (reg == PORT_STATUS_CMODE_SGMII)) {
2382 err = mv88e6xxx_serdes_power_on(chip);
2383 if (err < 0)
2384 return err;
13a7ebb3
PU
2385 }
2386 }
2387
8efdda4a 2388 /* Port Control 2: don't force a good FCS, set the maximum frame size to
46fbe5e5 2389 * 10240 bytes, disable 802.1q tags checking, don't discard tagged or
8efdda4a
VD
2390 * untagged frames on this port, do a destination address lookup on all
2391 * received packets as usual, disable ARP mirroring and don't send a
2392 * copy of all transmitted/received frames on this port to the CPU.
54d792f2 2393 */
a23b2961
AL
2394 err = mv88e6xxx_port_set_map_da(chip, port);
2395 if (err)
2396 return err;
8efdda4a 2397
a23b2961
AL
2398 reg = 0;
2399 if (chip->info->ops->port_set_upstream_port) {
2400 err = chip->info->ops->port_set_upstream_port(
2401 chip, port, dsa_upstream_port(ds));
0e7b9925
AL
2402 if (err)
2403 return err;
54d792f2
AL
2404 }
2405
a23b2961
AL
2406 err = mv88e6xxx_port_set_8021q_mode(chip, port,
2407 PORT_CONTROL_2_8021Q_DISABLED);
2408 if (err)
2409 return err;
2410
5f436666
AL
2411 if (chip->info->ops->port_jumbo_config) {
2412 err = chip->info->ops->port_jumbo_config(chip, port);
2413 if (err)
2414 return err;
2415 }
2416
54d792f2
AL
2417 /* Port Association Vector: when learning source addresses
2418 * of packets, add the address to the address database using
2419 * a port bitmap that has only the bit for this port set and
2420 * the other bits clear.
2421 */
4c7ea3c0 2422 reg = 1 << port;
996ecb82
VD
2423 /* Disable learning for CPU port */
2424 if (dsa_is_cpu_port(ds, port))
65fa4027 2425 reg = 0;
4c7ea3c0 2426
0e7b9925
AL
2427 err = mv88e6xxx_port_write(chip, port, PORT_ASSOC_VECTOR, reg);
2428 if (err)
2429 return err;
54d792f2
AL
2430
2431 /* Egress rate control 2: disable egress rate control. */
0e7b9925
AL
2432 err = mv88e6xxx_port_write(chip, port, PORT_RATE_CONTROL_2, 0x0000);
2433 if (err)
2434 return err;
54d792f2 2435
b35d322a
AL
2436 if (chip->info->ops->port_pause_config) {
2437 err = chip->info->ops->port_pause_config(chip, port);
0e7b9925
AL
2438 if (err)
2439 return err;
b35d322a 2440 }
54d792f2 2441
c8c94891
VD
2442 if (chip->info->ops->port_disable_learn_limit) {
2443 err = chip->info->ops->port_disable_learn_limit(chip, port);
2444 if (err)
2445 return err;
2446 }
2447
9dbfb4e1
VD
2448 if (chip->info->ops->port_disable_pri_override) {
2449 err = chip->info->ops->port_disable_pri_override(chip, port);
0e7b9925
AL
2450 if (err)
2451 return err;
ef0a7318 2452 }
2bbb33be 2453
ef0a7318
AL
2454 if (chip->info->ops->port_tag_remap) {
2455 err = chip->info->ops->port_tag_remap(chip, port);
0e7b9925
AL
2456 if (err)
2457 return err;
54d792f2
AL
2458 }
2459
ef70b111
AL
2460 if (chip->info->ops->port_egress_rate_limiting) {
2461 err = chip->info->ops->port_egress_rate_limiting(chip, port);
0e7b9925
AL
2462 if (err)
2463 return err;
54d792f2
AL
2464 }
2465
ea698f4f 2466 err = mv88e6xxx_setup_message_port(chip, port);
0e7b9925
AL
2467 if (err)
2468 return err;
d827e88a 2469
207afda1 2470 /* Port based VLAN map: give each port the same default address
b7666efe
VD
2471 * database, and allow bidirectional communication between the
2472 * CPU and DSA port(s), and the other ports.
d827e88a 2473 */
b4e48c50 2474 err = mv88e6xxx_port_set_fid(chip, port, 0);
0e7b9925
AL
2475 if (err)
2476 return err;
2db9ce1f 2477
0e7b9925
AL
2478 err = _mv88e6xxx_port_based_vlan_map(chip, port);
2479 if (err)
2480 return err;
d827e88a
GR
2481
2482 /* Default VLAN ID and priority: don't set a default VLAN
2483 * ID, and set the default packet priority to zero.
2484 */
0e7b9925 2485 return mv88e6xxx_port_write(chip, port, PORT_DEFAULT_VLAN, 0x0000);
dbde9e66
AL
2486}
2487
aa0938c6 2488static int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr)
3b4caa1b
VD
2489{
2490 int err;
2491
a935c052 2492 err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]);
3b4caa1b
VD
2493 if (err)
2494 return err;
2495
a935c052 2496 err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]);
3b4caa1b
VD
2497 if (err)
2498 return err;
2499
a935c052
VD
2500 err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]);
2501 if (err)
2502 return err;
2503
2504 return 0;
3b4caa1b
VD
2505}
2506
2cfcd964
VD
2507static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
2508 unsigned int ageing_time)
2509{
04bed143 2510 struct mv88e6xxx_chip *chip = ds->priv;
2cfcd964
VD
2511 int err;
2512
2513 mutex_lock(&chip->reg_lock);
720c6343 2514 err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
2cfcd964
VD
2515 mutex_unlock(&chip->reg_lock);
2516
2517 return err;
2518}
2519
9729934c 2520static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip)
acdaffcc 2521{
fad09c73 2522 struct dsa_switch *ds = chip->ds;
b0745e87 2523 u32 upstream_port = dsa_upstream_port(ds);
552238b5 2524 int err;
54d792f2 2525
119477bd
VD
2526 /* Enable the PHY Polling Unit if present, don't discard any packets,
2527 * and mask all interrupt sources.
2528 */
a199d8b6 2529 err = mv88e6xxx_ppu_enable(chip);
119477bd
VD
2530 if (err)
2531 return err;
2532
33641994
AL
2533 if (chip->info->ops->g1_set_cpu_port) {
2534 err = chip->info->ops->g1_set_cpu_port(chip, upstream_port);
2535 if (err)
2536 return err;
2537 }
2538
2539 if (chip->info->ops->g1_set_egress_port) {
2540 err = chip->info->ops->g1_set_egress_port(chip, upstream_port);
2541 if (err)
2542 return err;
2543 }
b0745e87 2544
50484ff4 2545 /* Disable remote management, and set the switch's DSA device number. */
a935c052
VD
2546 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2,
2547 GLOBAL_CONTROL_2_MULTIPLE_CASCADE |
2548 (ds->index & 0x1f));
50484ff4
VD
2549 if (err)
2550 return err;
2551
acddbd21
VD
2552 /* Clear all the VTU and STU entries */
2553 err = _mv88e6xxx_vtu_stu_flush(chip);
2554 if (err < 0)
2555 return err;
2556
54d792f2 2557 /* Configure the IP ToS mapping registers. */
a935c052 2558 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_0, 0x0000);
48ace4ef 2559 if (err)
08a01261 2560 return err;
a935c052 2561 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_1, 0x0000);
48ace4ef 2562 if (err)
08a01261 2563 return err;
a935c052 2564 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_2, 0x5555);
48ace4ef 2565 if (err)
08a01261 2566 return err;
a935c052 2567 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_3, 0x5555);
48ace4ef 2568 if (err)
08a01261 2569 return err;
a935c052 2570 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_4, 0xaaaa);
48ace4ef 2571 if (err)
08a01261 2572 return err;
a935c052 2573 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_5, 0xaaaa);
48ace4ef 2574 if (err)
08a01261 2575 return err;
a935c052 2576 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_6, 0xffff);
48ace4ef 2577 if (err)
08a01261 2578 return err;
a935c052 2579 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_7, 0xffff);
48ace4ef 2580 if (err)
08a01261 2581 return err;
54d792f2
AL
2582
2583 /* Configure the IEEE 802.1p priority mapping register. */
a935c052 2584 err = mv88e6xxx_g1_write(chip, GLOBAL_IEEE_PRI, 0xfa41);
48ace4ef 2585 if (err)
08a01261 2586 return err;
54d792f2 2587
de227387
AL
2588 /* Initialize the statistics unit */
2589 err = mv88e6xxx_stats_set_histogram(chip);
2590 if (err)
2591 return err;
2592
9729934c 2593 /* Clear the statistics counters for all ports */
a935c052
VD
2594 err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
2595 GLOBAL_STATS_OP_FLUSH_ALL);
9729934c
VD
2596 if (err)
2597 return err;
2598
2599 /* Wait for the flush to complete. */
7f9ef3af 2600 err = mv88e6xxx_g1_stats_wait(chip);
9729934c
VD
2601 if (err)
2602 return err;
2603
2604 return 0;
2605}
2606
f81ec90f 2607static int mv88e6xxx_setup(struct dsa_switch *ds)
08a01261 2608{
04bed143 2609 struct mv88e6xxx_chip *chip = ds->priv;
08a01261 2610 int err;
a1a6a4d1
VD
2611 int i;
2612
fad09c73 2613 chip->ds = ds;
a3c53be5 2614 ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
08a01261 2615
fad09c73 2616 mutex_lock(&chip->reg_lock);
08a01261 2617
9729934c 2618 /* Setup Switch Port Registers */
370b4ffb 2619 for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
9729934c
VD
2620 err = mv88e6xxx_setup_port(chip, i);
2621 if (err)
2622 goto unlock;
2623 }
2624
2625 /* Setup Switch Global 1 Registers */
2626 err = mv88e6xxx_g1_setup(chip);
a1a6a4d1
VD
2627 if (err)
2628 goto unlock;
2629
9729934c
VD
2630 /* Setup Switch Global 2 Registers */
2631 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_GLOBAL2)) {
2632 err = mv88e6xxx_g2_setup(chip);
a1a6a4d1
VD
2633 if (err)
2634 goto unlock;
2635 }
08a01261 2636
81228996
VD
2637 err = mv88e6xxx_pvt_setup(chip);
2638 if (err)
2639 goto unlock;
2640
a2ac29d2
VD
2641 err = mv88e6xxx_atu_setup(chip);
2642 if (err)
2643 goto unlock;
2644
6e55f698
AL
2645 /* Some generations have the configuration of sending reserved
2646 * management frames to the CPU in global2, others in
2647 * global1. Hence it does not fit the two setup functions
2648 * above.
2649 */
2650 if (chip->info->ops->mgmt_rsvd2cpu) {
2651 err = chip->info->ops->mgmt_rsvd2cpu(chip);
2652 if (err)
2653 goto unlock;
2654 }
2655
6b17e864 2656unlock:
fad09c73 2657 mutex_unlock(&chip->reg_lock);
db687a56 2658
48ace4ef 2659 return err;
54d792f2
AL
2660}
2661
3b4caa1b
VD
2662static int mv88e6xxx_set_addr(struct dsa_switch *ds, u8 *addr)
2663{
04bed143 2664 struct mv88e6xxx_chip *chip = ds->priv;
3b4caa1b
VD
2665 int err;
2666
b073d4e2
VD
2667 if (!chip->info->ops->set_switch_mac)
2668 return -EOPNOTSUPP;
3b4caa1b 2669
b073d4e2
VD
2670 mutex_lock(&chip->reg_lock);
2671 err = chip->info->ops->set_switch_mac(chip, addr);
3b4caa1b
VD
2672 mutex_unlock(&chip->reg_lock);
2673
2674 return err;
2675}
2676
e57e5e77 2677static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
fd3a0ee4 2678{
0dd12d54
AL
2679 struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
2680 struct mv88e6xxx_chip *chip = mdio_bus->chip;
e57e5e77
VD
2681 u16 val;
2682 int err;
fd3a0ee4 2683
ee26a228
AL
2684 if (!chip->info->ops->phy_read)
2685 return -EOPNOTSUPP;
2686
fad09c73 2687 mutex_lock(&chip->reg_lock);
ee26a228 2688 err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
fad09c73 2689 mutex_unlock(&chip->reg_lock);
e57e5e77 2690
da9f3301
AL
2691 if (reg == MII_PHYSID2) {
2692 /* Some internal PHYS don't have a model number. Use
2693 * the mv88e6390 family model number instead.
2694 */
2695 if (!(val & 0x3f0))
2696 val |= PORT_SWITCH_ID_PROD_NUM_6390;
2697 }
2698
e57e5e77 2699 return err ? err : val;
fd3a0ee4
AL
2700}
2701
e57e5e77 2702static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
fd3a0ee4 2703{
0dd12d54
AL
2704 struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
2705 struct mv88e6xxx_chip *chip = mdio_bus->chip;
e57e5e77 2706 int err;
fd3a0ee4 2707
ee26a228
AL
2708 if (!chip->info->ops->phy_write)
2709 return -EOPNOTSUPP;
2710
fad09c73 2711 mutex_lock(&chip->reg_lock);
ee26a228 2712 err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
fad09c73 2713 mutex_unlock(&chip->reg_lock);
e57e5e77
VD
2714
2715 return err;
fd3a0ee4
AL
2716}
2717
fad09c73 2718static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
a3c53be5
AL
2719 struct device_node *np,
2720 bool external)
b516d453
AL
2721{
2722 static int index;
0dd12d54 2723 struct mv88e6xxx_mdio_bus *mdio_bus;
b516d453
AL
2724 struct mii_bus *bus;
2725 int err;
2726
0dd12d54 2727 bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
b516d453
AL
2728 if (!bus)
2729 return -ENOMEM;
2730
0dd12d54 2731 mdio_bus = bus->priv;
a3c53be5 2732 mdio_bus->bus = bus;
0dd12d54 2733 mdio_bus->chip = chip;
a3c53be5
AL
2734 INIT_LIST_HEAD(&mdio_bus->list);
2735 mdio_bus->external = external;
0dd12d54 2736
b516d453
AL
2737 if (np) {
2738 bus->name = np->full_name;
2739 snprintf(bus->id, MII_BUS_ID_SIZE, "%s", np->full_name);
2740 } else {
2741 bus->name = "mv88e6xxx SMI";
2742 snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
2743 }
2744
2745 bus->read = mv88e6xxx_mdio_read;
2746 bus->write = mv88e6xxx_mdio_write;
fad09c73 2747 bus->parent = chip->dev;
b516d453 2748
a3c53be5
AL
2749 if (np)
2750 err = of_mdiobus_register(bus, np);
b516d453
AL
2751 else
2752 err = mdiobus_register(bus);
2753 if (err) {
fad09c73 2754 dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
a3c53be5 2755 return err;
b516d453 2756 }
a3c53be5
AL
2757
2758 if (external)
2759 list_add_tail(&mdio_bus->list, &chip->mdios);
2760 else
2761 list_add(&mdio_bus->list, &chip->mdios);
b516d453
AL
2762
2763 return 0;
a3c53be5 2764}
b516d453 2765
a3c53be5
AL
2766static const struct of_device_id mv88e6xxx_mdio_external_match[] = {
2767 { .compatible = "marvell,mv88e6xxx-mdio-external",
2768 .data = (void *)true },
2769 { },
2770};
b516d453 2771
a3c53be5
AL
2772static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
2773 struct device_node *np)
2774{
2775 const struct of_device_id *match;
2776 struct device_node *child;
2777 int err;
2778
2779 /* Always register one mdio bus for the internal/default mdio
2780 * bus. This maybe represented in the device tree, but is
2781 * optional.
2782 */
2783 child = of_get_child_by_name(np, "mdio");
2784 err = mv88e6xxx_mdio_register(chip, child, false);
2785 if (err)
2786 return err;
2787
2788 /* Walk the device tree, and see if there are any other nodes
2789 * which say they are compatible with the external mdio
2790 * bus.
2791 */
2792 for_each_available_child_of_node(np, child) {
2793 match = of_match_node(mv88e6xxx_mdio_external_match, child);
2794 if (match) {
2795 err = mv88e6xxx_mdio_register(chip, child, true);
2796 if (err)
2797 return err;
2798 }
2799 }
2800
2801 return 0;
b516d453
AL
2802}
2803
a3c53be5 2804static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
b516d453
AL
2805
2806{
a3c53be5
AL
2807 struct mv88e6xxx_mdio_bus *mdio_bus;
2808 struct mii_bus *bus;
b516d453 2809
a3c53be5
AL
2810 list_for_each_entry(mdio_bus, &chip->mdios, list) {
2811 bus = mdio_bus->bus;
b516d453 2812
a3c53be5
AL
2813 mdiobus_unregister(bus);
2814 }
b516d453
AL
2815}
2816
855b1932
VD
2817static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
2818{
04bed143 2819 struct mv88e6xxx_chip *chip = ds->priv;
855b1932
VD
2820
2821 return chip->eeprom_len;
2822}
2823
855b1932
VD
2824static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
2825 struct ethtool_eeprom *eeprom, u8 *data)
2826{
04bed143 2827 struct mv88e6xxx_chip *chip = ds->priv;
855b1932
VD
2828 int err;
2829
ee4dc2e7
VD
2830 if (!chip->info->ops->get_eeprom)
2831 return -EOPNOTSUPP;
855b1932 2832
ee4dc2e7
VD
2833 mutex_lock(&chip->reg_lock);
2834 err = chip->info->ops->get_eeprom(chip, eeprom, data);
855b1932
VD
2835 mutex_unlock(&chip->reg_lock);
2836
2837 if (err)
2838 return err;
2839
2840 eeprom->magic = 0xc3ec4951;
2841
2842 return 0;
2843}
2844
855b1932
VD
2845static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
2846 struct ethtool_eeprom *eeprom, u8 *data)
2847{
04bed143 2848 struct mv88e6xxx_chip *chip = ds->priv;
855b1932
VD
2849 int err;
2850
ee4dc2e7
VD
2851 if (!chip->info->ops->set_eeprom)
2852 return -EOPNOTSUPP;
2853
855b1932
VD
2854 if (eeprom->magic != 0xc3ec4951)
2855 return -EINVAL;
2856
2857 mutex_lock(&chip->reg_lock);
ee4dc2e7 2858 err = chip->info->ops->set_eeprom(chip, eeprom, data);
855b1932
VD
2859 mutex_unlock(&chip->reg_lock);
2860
2861 return err;
2862}
2863
b3469dd8 2864static const struct mv88e6xxx_ops mv88e6085_ops = {
4b325d8c 2865 /* MV88E6XXX_FAMILY_6097 */
b073d4e2 2866 .set_switch_mac = mv88e6xxx_g1_set_switch_mac,
b3469dd8
VD
2867 .phy_read = mv88e6xxx_phy_ppu_read,
2868 .phy_write = mv88e6xxx_phy_ppu_write,
08ef7f10 2869 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 2870 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 2871 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 2872 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 2873 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 2874 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 2875 .port_set_ether_type = mv88e6351_port_set_ether_type,
ef70b111 2876 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 2877 .port_pause_config = mv88e6097_port_pause_config,
c8c94891 2878 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 2879 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 2880 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
2881 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
2882 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 2883 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
2884 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
2885 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 2886 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 2887 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
a199d8b6
VD
2888 .ppu_enable = mv88e6185_g1_ppu_enable,
2889 .ppu_disable = mv88e6185_g1_ppu_disable,
17e708ba 2890 .reset = mv88e6185_g1_reset,
b3469dd8
VD
2891};
2892
2893static const struct mv88e6xxx_ops mv88e6095_ops = {
4b325d8c 2894 /* MV88E6XXX_FAMILY_6095 */
b073d4e2 2895 .set_switch_mac = mv88e6xxx_g1_set_switch_mac,
b3469dd8
VD
2896 .phy_read = mv88e6xxx_phy_ppu_read,
2897 .phy_write = mv88e6xxx_phy_ppu_write,
08ef7f10 2898 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 2899 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 2900 .port_set_speed = mv88e6185_port_set_speed,
56995cbc 2901 .port_set_frame_mode = mv88e6085_port_set_frame_mode,
601aeed3 2902 .port_set_egress_floods = mv88e6185_port_set_egress_floods,
a23b2961 2903 .port_set_upstream_port = mv88e6095_port_set_upstream_port,
a605a0fe 2904 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
2905 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
2906 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 2907 .stats_get_stats = mv88e6095_stats_get_stats,
6e55f698 2908 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
a199d8b6
VD
2909 .ppu_enable = mv88e6185_g1_ppu_enable,
2910 .ppu_disable = mv88e6185_g1_ppu_disable,
17e708ba 2911 .reset = mv88e6185_g1_reset,
b3469dd8
VD
2912};
2913
7d381a02 2914static const struct mv88e6xxx_ops mv88e6097_ops = {
15da3cc8 2915 /* MV88E6XXX_FAMILY_6097 */
7d381a02
SE
2916 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2917 .phy_read = mv88e6xxx_g2_smi_phy_read,
2918 .phy_write = mv88e6xxx_g2_smi_phy_write,
2919 .port_set_link = mv88e6xxx_port_set_link,
2920 .port_set_duplex = mv88e6xxx_port_set_duplex,
2921 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 2922 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 2923 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 2924 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 2925 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 2926 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 2927 .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
b35d322a 2928 .port_pause_config = mv88e6097_port_pause_config,
c8c94891 2929 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 2930 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
7d381a02
SE
2931 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
2932 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
2933 .stats_get_strings = mv88e6095_stats_get_strings,
2934 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
2935 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
2936 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
91eaa475 2937 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 2938 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 2939 .reset = mv88e6352_g1_reset,
7d381a02
SE
2940};
2941
b3469dd8 2942static const struct mv88e6xxx_ops mv88e6123_ops = {
4b325d8c 2943 /* MV88E6XXX_FAMILY_6165 */
b073d4e2 2944 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
efb3e74d
AL
2945 .phy_read = mv88e6165_phy_read,
2946 .phy_write = mv88e6165_phy_write,
08ef7f10 2947 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 2948 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 2949 .port_set_speed = mv88e6185_port_set_speed,
56995cbc 2950 .port_set_frame_mode = mv88e6085_port_set_frame_mode,
601aeed3 2951 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
c8c94891 2952 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 2953 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 2954 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
2955 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
2956 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 2957 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
2958 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
2959 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 2960 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 2961 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 2962 .reset = mv88e6352_g1_reset,
b3469dd8
VD
2963};
2964
2965static const struct mv88e6xxx_ops mv88e6131_ops = {
4b325d8c 2966 /* MV88E6XXX_FAMILY_6185 */
b073d4e2 2967 .set_switch_mac = mv88e6xxx_g1_set_switch_mac,
b3469dd8
VD
2968 .phy_read = mv88e6xxx_phy_ppu_read,
2969 .phy_write = mv88e6xxx_phy_ppu_write,
08ef7f10 2970 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 2971 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 2972 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 2973 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 2974 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 2975 .port_set_egress_floods = mv88e6185_port_set_egress_floods,
56995cbc 2976 .port_set_ether_type = mv88e6351_port_set_ether_type,
a23b2961 2977 .port_set_upstream_port = mv88e6095_port_set_upstream_port,
5f436666 2978 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 2979 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 2980 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 2981 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
2982 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
2983 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 2984 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
2985 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
2986 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 2987 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 2988 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
a199d8b6
VD
2989 .ppu_enable = mv88e6185_g1_ppu_enable,
2990 .ppu_disable = mv88e6185_g1_ppu_disable,
17e708ba 2991 .reset = mv88e6185_g1_reset,
b3469dd8
VD
2992};
2993
990e27b0
VD
2994static const struct mv88e6xxx_ops mv88e6141_ops = {
2995 /* MV88E6XXX_FAMILY_6341 */
2996 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
2997 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
2998 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2999 .phy_read = mv88e6xxx_g2_smi_phy_read,
3000 .phy_write = mv88e6xxx_g2_smi_phy_write,
3001 .port_set_link = mv88e6xxx_port_set_link,
3002 .port_set_duplex = mv88e6xxx_port_set_duplex,
3003 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3004 .port_set_speed = mv88e6390_port_set_speed,
3005 .port_tag_remap = mv88e6095_port_tag_remap,
3006 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3007 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
3008 .port_set_ether_type = mv88e6351_port_set_ether_type,
3009 .port_jumbo_config = mv88e6165_port_jumbo_config,
3010 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3011 .port_pause_config = mv88e6097_port_pause_config,
3012 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3013 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3014 .stats_snapshot = mv88e6390_g1_stats_snapshot,
3015 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3016 .stats_get_strings = mv88e6320_stats_get_strings,
3017 .stats_get_stats = mv88e6390_stats_get_stats,
3018 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3019 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
3020 .watchdog_ops = &mv88e6390_watchdog_ops,
3021 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
3022 .reset = mv88e6352_g1_reset,
3023};
3024
b3469dd8 3025static const struct mv88e6xxx_ops mv88e6161_ops = {
4b325d8c 3026 /* MV88E6XXX_FAMILY_6165 */
b073d4e2 3027 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
efb3e74d
AL
3028 .phy_read = mv88e6165_phy_read,
3029 .phy_write = mv88e6165_phy_write,
08ef7f10 3030 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3031 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3032 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3033 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 3034 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3035 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3036 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3037 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3038 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3039 .port_pause_config = mv88e6097_port_pause_config,
c8c94891 3040 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3041 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 3042 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
3043 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3044 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3045 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3046 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3047 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 3048 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 3049 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3050 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3051};
3052
3053static const struct mv88e6xxx_ops mv88e6165_ops = {
4b325d8c 3054 /* MV88E6XXX_FAMILY_6165 */
b073d4e2 3055 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
efb3e74d
AL
3056 .phy_read = mv88e6165_phy_read,
3057 .phy_write = mv88e6165_phy_write,
08ef7f10 3058 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3059 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3060 .port_set_speed = mv88e6185_port_set_speed,
c8c94891 3061 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3062 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 3063 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
3064 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3065 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3066 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3067 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3068 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 3069 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 3070 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3071 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3072};
3073
3074static const struct mv88e6xxx_ops mv88e6171_ops = {
4b325d8c 3075 /* MV88E6XXX_FAMILY_6351 */
b073d4e2 3076 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3077 .phy_read = mv88e6xxx_g2_smi_phy_read,
3078 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3079 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3080 .port_set_duplex = mv88e6xxx_port_set_duplex,
94d66ae6 3081 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3082 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3083 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 3084 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3085 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3086 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3087 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3088 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3089 .port_pause_config = mv88e6097_port_pause_config,
c8c94891 3090 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3091 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 3092 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3093 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3094 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3095 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3096 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3097 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 3098 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 3099 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3100 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3101};
3102
3103static const struct mv88e6xxx_ops mv88e6172_ops = {
4b325d8c 3104 /* MV88E6XXX_FAMILY_6352 */
ee4dc2e7
VD
3105 .get_eeprom = mv88e6xxx_g2_get_eeprom16,
3106 .set_eeprom = mv88e6xxx_g2_set_eeprom16,
b073d4e2 3107 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3108 .phy_read = mv88e6xxx_g2_smi_phy_read,
3109 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3110 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3111 .port_set_duplex = mv88e6xxx_port_set_duplex,
a0a0f622 3112 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3113 .port_set_speed = mv88e6352_port_set_speed,
ef0a7318 3114 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 3115 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3116 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3117 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3118 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3119 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3120 .port_pause_config = mv88e6097_port_pause_config,
c8c94891 3121 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3122 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 3123 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3124 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3125 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3126 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3127 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3128 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 3129 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 3130 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3131 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3132};
3133
3134static const struct mv88e6xxx_ops mv88e6175_ops = {
4b325d8c 3135 /* MV88E6XXX_FAMILY_6351 */
b073d4e2 3136 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3137 .phy_read = mv88e6xxx_g2_smi_phy_read,
3138 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3139 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3140 .port_set_duplex = mv88e6xxx_port_set_duplex,
94d66ae6 3141 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3142 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3143 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 3144 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3145 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3146 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3147 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3148 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3149 .port_pause_config = mv88e6097_port_pause_config,
c8c94891 3150 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3151 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 3152 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3153 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3154 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3155 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3156 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3157 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 3158 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 3159 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3160 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3161};
3162
3163static const struct mv88e6xxx_ops mv88e6176_ops = {
4b325d8c 3164 /* MV88E6XXX_FAMILY_6352 */
ee4dc2e7
VD
3165 .get_eeprom = mv88e6xxx_g2_get_eeprom16,
3166 .set_eeprom = mv88e6xxx_g2_set_eeprom16,
b073d4e2 3167 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3168 .phy_read = mv88e6xxx_g2_smi_phy_read,
3169 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3170 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3171 .port_set_duplex = mv88e6xxx_port_set_duplex,
a0a0f622 3172 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3173 .port_set_speed = mv88e6352_port_set_speed,
ef0a7318 3174 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 3175 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3176 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3177 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3178 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3179 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3180 .port_pause_config = mv88e6097_port_pause_config,
c8c94891 3181 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3182 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 3183 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3184 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3185 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3186 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3187 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3188 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 3189 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 3190 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3191 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3192};
3193
3194static const struct mv88e6xxx_ops mv88e6185_ops = {
4b325d8c 3195 /* MV88E6XXX_FAMILY_6185 */
b073d4e2 3196 .set_switch_mac = mv88e6xxx_g1_set_switch_mac,
b3469dd8
VD
3197 .phy_read = mv88e6xxx_phy_ppu_read,
3198 .phy_write = mv88e6xxx_phy_ppu_write,
08ef7f10 3199 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3200 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3201 .port_set_speed = mv88e6185_port_set_speed,
56995cbc 3202 .port_set_frame_mode = mv88e6085_port_set_frame_mode,
601aeed3 3203 .port_set_egress_floods = mv88e6185_port_set_egress_floods,
ef70b111 3204 .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
a23b2961 3205 .port_set_upstream_port = mv88e6095_port_set_upstream_port,
a605a0fe 3206 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
3207 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3208 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3209 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3210 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3211 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 3212 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 3213 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
a199d8b6
VD
3214 .ppu_enable = mv88e6185_g1_ppu_enable,
3215 .ppu_disable = mv88e6185_g1_ppu_disable,
17e708ba 3216 .reset = mv88e6185_g1_reset,
b3469dd8
VD
3217};
3218
1a3b39ec 3219static const struct mv88e6xxx_ops mv88e6190_ops = {
4b325d8c 3220 /* MV88E6XXX_FAMILY_6390 */
98fc3c6f
VD
3221 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3222 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
1a3b39ec
AL
3223 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3224 .phy_read = mv88e6xxx_g2_smi_phy_read,
3225 .phy_write = mv88e6xxx_g2_smi_phy_write,
3226 .port_set_link = mv88e6xxx_port_set_link,
3227 .port_set_duplex = mv88e6xxx_port_set_duplex,
3228 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3229 .port_set_speed = mv88e6390_port_set_speed,
ef0a7318 3230 .port_tag_remap = mv88e6390_port_tag_remap,
56995cbc 3231 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3232 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3233 .port_set_ether_type = mv88e6351_port_set_ether_type,
3ce0e65e 3234 .port_pause_config = mv88e6390_port_pause_config,
c8c94891 3235 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3236 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
79523473 3237 .stats_snapshot = mv88e6390_g1_stats_snapshot,
de227387 3238 .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
dfafe449
AL
3239 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3240 .stats_get_strings = mv88e6320_stats_get_strings,
e0d8b615 3241 .stats_get_stats = mv88e6390_stats_get_stats,
33641994
AL
3242 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3243 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
61303736 3244 .watchdog_ops = &mv88e6390_watchdog_ops,
6e55f698 3245 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
17e708ba 3246 .reset = mv88e6352_g1_reset,
1a3b39ec
AL
3247};
3248
3249static const struct mv88e6xxx_ops mv88e6190x_ops = {
4b325d8c 3250 /* MV88E6XXX_FAMILY_6390 */
98fc3c6f
VD
3251 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3252 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
1a3b39ec
AL
3253 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3254 .phy_read = mv88e6xxx_g2_smi_phy_read,
3255 .phy_write = mv88e6xxx_g2_smi_phy_write,
3256 .port_set_link = mv88e6xxx_port_set_link,
3257 .port_set_duplex = mv88e6xxx_port_set_duplex,
3258 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3259 .port_set_speed = mv88e6390x_port_set_speed,
ef0a7318 3260 .port_tag_remap = mv88e6390_port_tag_remap,
56995cbc 3261 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3262 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3263 .port_set_ether_type = mv88e6351_port_set_ether_type,
3ce0e65e 3264 .port_pause_config = mv88e6390_port_pause_config,
c8c94891 3265 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3266 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
79523473 3267 .stats_snapshot = mv88e6390_g1_stats_snapshot,
de227387 3268 .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
dfafe449
AL
3269 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3270 .stats_get_strings = mv88e6320_stats_get_strings,
e0d8b615 3271 .stats_get_stats = mv88e6390_stats_get_stats,
33641994
AL
3272 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3273 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
61303736 3274 .watchdog_ops = &mv88e6390_watchdog_ops,
6e55f698 3275 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
17e708ba 3276 .reset = mv88e6352_g1_reset,
1a3b39ec
AL
3277};
3278
3279static const struct mv88e6xxx_ops mv88e6191_ops = {
4b325d8c 3280 /* MV88E6XXX_FAMILY_6390 */
98fc3c6f
VD
3281 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3282 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
1a3b39ec
AL
3283 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3284 .phy_read = mv88e6xxx_g2_smi_phy_read,
3285 .phy_write = mv88e6xxx_g2_smi_phy_write,
3286 .port_set_link = mv88e6xxx_port_set_link,
3287 .port_set_duplex = mv88e6xxx_port_set_duplex,
3288 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3289 .port_set_speed = mv88e6390_port_set_speed,
ef0a7318 3290 .port_tag_remap = mv88e6390_port_tag_remap,
56995cbc 3291 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3292 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3293 .port_set_ether_type = mv88e6351_port_set_ether_type,
3ce0e65e 3294 .port_pause_config = mv88e6390_port_pause_config,
c8c94891 3295 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3296 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
79523473 3297 .stats_snapshot = mv88e6390_g1_stats_snapshot,
de227387 3298 .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
dfafe449
AL
3299 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3300 .stats_get_strings = mv88e6320_stats_get_strings,
e0d8b615 3301 .stats_get_stats = mv88e6390_stats_get_stats,
33641994
AL
3302 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3303 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
61303736 3304 .watchdog_ops = &mv88e6390_watchdog_ops,
6e55f698 3305 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
17e708ba 3306 .reset = mv88e6352_g1_reset,
1a3b39ec
AL
3307};
3308
b3469dd8 3309static const struct mv88e6xxx_ops mv88e6240_ops = {
4b325d8c 3310 /* MV88E6XXX_FAMILY_6352 */
ee4dc2e7
VD
3311 .get_eeprom = mv88e6xxx_g2_get_eeprom16,
3312 .set_eeprom = mv88e6xxx_g2_set_eeprom16,
b073d4e2 3313 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3314 .phy_read = mv88e6xxx_g2_smi_phy_read,
3315 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3316 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3317 .port_set_duplex = mv88e6xxx_port_set_duplex,
a0a0f622 3318 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3319 .port_set_speed = mv88e6352_port_set_speed,
ef0a7318 3320 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 3321 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3322 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3323 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3324 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3325 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3326 .port_pause_config = mv88e6097_port_pause_config,
c8c94891 3327 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3328 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 3329 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3330 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3331 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3332 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3333 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3334 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 3335 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 3336 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3337 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3338};
3339
1a3b39ec 3340static const struct mv88e6xxx_ops mv88e6290_ops = {
4b325d8c 3341 /* MV88E6XXX_FAMILY_6390 */
98fc3c6f
VD
3342 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3343 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
1a3b39ec
AL
3344 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3345 .phy_read = mv88e6xxx_g2_smi_phy_read,
3346 .phy_write = mv88e6xxx_g2_smi_phy_write,
3347 .port_set_link = mv88e6xxx_port_set_link,
3348 .port_set_duplex = mv88e6xxx_port_set_duplex,
3349 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3350 .port_set_speed = mv88e6390_port_set_speed,
ef0a7318 3351 .port_tag_remap = mv88e6390_port_tag_remap,
56995cbc 3352 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3353 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3354 .port_set_ether_type = mv88e6351_port_set_ether_type,
3ce0e65e 3355 .port_pause_config = mv88e6390_port_pause_config,
f39908d3 3356 .port_set_cmode = mv88e6390x_port_set_cmode,
c8c94891 3357 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3358 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
79523473 3359 .stats_snapshot = mv88e6390_g1_stats_snapshot,
de227387 3360 .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
dfafe449
AL
3361 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3362 .stats_get_strings = mv88e6320_stats_get_strings,
e0d8b615 3363 .stats_get_stats = mv88e6390_stats_get_stats,
33641994
AL
3364 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3365 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
61303736 3366 .watchdog_ops = &mv88e6390_watchdog_ops,
6e55f698 3367 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
17e708ba 3368 .reset = mv88e6352_g1_reset,
1a3b39ec
AL
3369};
3370
b3469dd8 3371static const struct mv88e6xxx_ops mv88e6320_ops = {
4b325d8c 3372 /* MV88E6XXX_FAMILY_6320 */
ee4dc2e7
VD
3373 .get_eeprom = mv88e6xxx_g2_get_eeprom16,
3374 .set_eeprom = mv88e6xxx_g2_set_eeprom16,
b073d4e2 3375 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3376 .phy_read = mv88e6xxx_g2_smi_phy_read,
3377 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3378 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3379 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3380 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3381 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 3382 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3383 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3384 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3385 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3386 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3387 .port_pause_config = mv88e6097_port_pause_config,
c8c94891 3388 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3389 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 3390 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3391 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3392 .stats_get_strings = mv88e6320_stats_get_strings,
052f947f 3393 .stats_get_stats = mv88e6320_stats_get_stats,
33641994
AL
3394 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3395 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3396 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3397 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3398};
3399
3400static const struct mv88e6xxx_ops mv88e6321_ops = {
4b325d8c 3401 /* MV88E6XXX_FAMILY_6321 */
ee4dc2e7
VD
3402 .get_eeprom = mv88e6xxx_g2_get_eeprom16,
3403 .set_eeprom = mv88e6xxx_g2_set_eeprom16,
b073d4e2 3404 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3405 .phy_read = mv88e6xxx_g2_smi_phy_read,
3406 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3407 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3408 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3409 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3410 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 3411 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3412 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3413 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3414 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3415 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3416 .port_pause_config = mv88e6097_port_pause_config,
c8c94891 3417 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3418 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 3419 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3420 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3421 .stats_get_strings = mv88e6320_stats_get_strings,
052f947f 3422 .stats_get_stats = mv88e6320_stats_get_stats,
33641994
AL
3423 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3424 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
17e708ba 3425 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3426};
3427
16e329ae
VD
3428static const struct mv88e6xxx_ops mv88e6341_ops = {
3429 /* MV88E6XXX_FAMILY_6341 */
3430 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3431 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
3432 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3433 .phy_read = mv88e6xxx_g2_smi_phy_read,
3434 .phy_write = mv88e6xxx_g2_smi_phy_write,
3435 .port_set_link = mv88e6xxx_port_set_link,
3436 .port_set_duplex = mv88e6xxx_port_set_duplex,
3437 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3438 .port_set_speed = mv88e6390_port_set_speed,
3439 .port_tag_remap = mv88e6095_port_tag_remap,
3440 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3441 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
3442 .port_set_ether_type = mv88e6351_port_set_ether_type,
3443 .port_jumbo_config = mv88e6165_port_jumbo_config,
3444 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3445 .port_pause_config = mv88e6097_port_pause_config,
3446 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3447 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3448 .stats_snapshot = mv88e6390_g1_stats_snapshot,
3449 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3450 .stats_get_strings = mv88e6320_stats_get_strings,
3451 .stats_get_stats = mv88e6390_stats_get_stats,
3452 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3453 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
3454 .watchdog_ops = &mv88e6390_watchdog_ops,
3455 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
3456 .reset = mv88e6352_g1_reset,
3457};
3458
b3469dd8 3459static const struct mv88e6xxx_ops mv88e6350_ops = {
4b325d8c 3460 /* MV88E6XXX_FAMILY_6351 */
b073d4e2 3461 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3462 .phy_read = mv88e6xxx_g2_smi_phy_read,
3463 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3464 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3465 .port_set_duplex = mv88e6xxx_port_set_duplex,
94d66ae6 3466 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3467 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3468 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 3469 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3470 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3471 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3472 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3473 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3474 .port_pause_config = mv88e6097_port_pause_config,
c8c94891 3475 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3476 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 3477 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3478 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3479 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3480 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3481 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3482 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 3483 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 3484 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3485 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3486};
3487
3488static const struct mv88e6xxx_ops mv88e6351_ops = {
4b325d8c 3489 /* MV88E6XXX_FAMILY_6351 */
b073d4e2 3490 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3491 .phy_read = mv88e6xxx_g2_smi_phy_read,
3492 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3493 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3494 .port_set_duplex = mv88e6xxx_port_set_duplex,
94d66ae6 3495 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3496 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3497 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 3498 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3499 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3500 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3501 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3502 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3503 .port_pause_config = mv88e6097_port_pause_config,
c8c94891 3504 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3505 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 3506 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3507 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3508 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3509 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3510 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3511 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 3512 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 3513 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3514 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3515};
3516
3517static const struct mv88e6xxx_ops mv88e6352_ops = {
4b325d8c 3518 /* MV88E6XXX_FAMILY_6352 */
ee4dc2e7
VD
3519 .get_eeprom = mv88e6xxx_g2_get_eeprom16,
3520 .set_eeprom = mv88e6xxx_g2_set_eeprom16,
b073d4e2 3521 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3522 .phy_read = mv88e6xxx_g2_smi_phy_read,
3523 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3524 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3525 .port_set_duplex = mv88e6xxx_port_set_duplex,
a0a0f622 3526 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3527 .port_set_speed = mv88e6352_port_set_speed,
ef0a7318 3528 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc 3529 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3530 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3531 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3532 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3533 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3534 .port_pause_config = mv88e6097_port_pause_config,
c8c94891 3535 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3536 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
a605a0fe 3537 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3538 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3539 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3540 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3541 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3542 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
fcd25166 3543 .watchdog_ops = &mv88e6097_watchdog_ops,
6e55f698 3544 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3545 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3546};
3547
1a3b39ec 3548static const struct mv88e6xxx_ops mv88e6390_ops = {
4b325d8c 3549 /* MV88E6XXX_FAMILY_6390 */
98fc3c6f
VD
3550 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3551 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
1a3b39ec
AL
3552 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3553 .phy_read = mv88e6xxx_g2_smi_phy_read,
3554 .phy_write = mv88e6xxx_g2_smi_phy_write,
3555 .port_set_link = mv88e6xxx_port_set_link,
3556 .port_set_duplex = mv88e6xxx_port_set_duplex,
3557 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3558 .port_set_speed = mv88e6390_port_set_speed,
ef0a7318 3559 .port_tag_remap = mv88e6390_port_tag_remap,
56995cbc 3560 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3561 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3562 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3563 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3564 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3ce0e65e 3565 .port_pause_config = mv88e6390_port_pause_config,
f39908d3 3566 .port_set_cmode = mv88e6390x_port_set_cmode,
c8c94891 3567 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3568 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
79523473 3569 .stats_snapshot = mv88e6390_g1_stats_snapshot,
de227387 3570 .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
dfafe449
AL
3571 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3572 .stats_get_strings = mv88e6320_stats_get_strings,
e0d8b615 3573 .stats_get_stats = mv88e6390_stats_get_stats,
33641994
AL
3574 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3575 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
61303736 3576 .watchdog_ops = &mv88e6390_watchdog_ops,
6e55f698 3577 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
17e708ba 3578 .reset = mv88e6352_g1_reset,
1a3b39ec
AL
3579};
3580
3581static const struct mv88e6xxx_ops mv88e6390x_ops = {
4b325d8c 3582 /* MV88E6XXX_FAMILY_6390 */
98fc3c6f
VD
3583 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3584 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
1a3b39ec
AL
3585 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3586 .phy_read = mv88e6xxx_g2_smi_phy_read,
3587 .phy_write = mv88e6xxx_g2_smi_phy_write,
3588 .port_set_link = mv88e6xxx_port_set_link,
3589 .port_set_duplex = mv88e6xxx_port_set_duplex,
3590 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3591 .port_set_speed = mv88e6390x_port_set_speed,
ef0a7318 3592 .port_tag_remap = mv88e6390_port_tag_remap,
56995cbc 3593 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
601aeed3 3594 .port_set_egress_floods = mv88e6352_port_set_egress_floods,
56995cbc 3595 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3596 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3597 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3ce0e65e 3598 .port_pause_config = mv88e6390_port_pause_config,
c8c94891 3599 .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
9dbfb4e1 3600 .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
79523473 3601 .stats_snapshot = mv88e6390_g1_stats_snapshot,
de227387 3602 .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
dfafe449
AL
3603 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3604 .stats_get_strings = mv88e6320_stats_get_strings,
e0d8b615 3605 .stats_get_stats = mv88e6390_stats_get_stats,
33641994
AL
3606 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3607 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
61303736 3608 .watchdog_ops = &mv88e6390_watchdog_ops,
6e55f698 3609 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
17e708ba 3610 .reset = mv88e6352_g1_reset,
1a3b39ec
AL
3611};
3612
f81ec90f
VD
3613static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3614 [MV88E6085] = {
3615 .prod_num = PORT_SWITCH_ID_PROD_NUM_6085,
3616 .family = MV88E6XXX_FAMILY_6097,
3617 .name = "Marvell 88E6085",
3618 .num_databases = 4096,
3619 .num_ports = 10,
9dddd478 3620 .port_base_addr = 0x10,
a935c052 3621 .global1_addr = 0x1b,
acddbd21 3622 .age_time_coeff = 15000,
dc30c35b 3623 .g1_irqs = 8,
e606ca36 3624 .atu_move_port_mask = 0xf,
f3645652 3625 .pvt = true,
443d5a1b 3626 .tag_protocol = DSA_TAG_PROTO_DSA,
f81ec90f 3627 .flags = MV88E6XXX_FLAGS_FAMILY_6097,
b3469dd8 3628 .ops = &mv88e6085_ops,
f81ec90f
VD
3629 },
3630
3631 [MV88E6095] = {
3632 .prod_num = PORT_SWITCH_ID_PROD_NUM_6095,
3633 .family = MV88E6XXX_FAMILY_6095,
3634 .name = "Marvell 88E6095/88E6095F",
3635 .num_databases = 256,
3636 .num_ports = 11,
9dddd478 3637 .port_base_addr = 0x10,
a935c052 3638 .global1_addr = 0x1b,
acddbd21 3639 .age_time_coeff = 15000,
dc30c35b 3640 .g1_irqs = 8,
e606ca36 3641 .atu_move_port_mask = 0xf,
443d5a1b 3642 .tag_protocol = DSA_TAG_PROTO_DSA,
f81ec90f 3643 .flags = MV88E6XXX_FLAGS_FAMILY_6095,
b3469dd8 3644 .ops = &mv88e6095_ops,
f81ec90f
VD
3645 },
3646
7d381a02
SE
3647 [MV88E6097] = {
3648 .prod_num = PORT_SWITCH_ID_PROD_NUM_6097,
3649 .family = MV88E6XXX_FAMILY_6097,
3650 .name = "Marvell 88E6097/88E6097F",
3651 .num_databases = 4096,
3652 .num_ports = 11,
3653 .port_base_addr = 0x10,
3654 .global1_addr = 0x1b,
3655 .age_time_coeff = 15000,
c534178b 3656 .g1_irqs = 8,
e606ca36 3657 .atu_move_port_mask = 0xf,
f3645652 3658 .pvt = true,
2bfcfcd3 3659 .tag_protocol = DSA_TAG_PROTO_EDSA,
7d381a02
SE
3660 .flags = MV88E6XXX_FLAGS_FAMILY_6097,
3661 .ops = &mv88e6097_ops,
3662 },
3663
f81ec90f
VD
3664 [MV88E6123] = {
3665 .prod_num = PORT_SWITCH_ID_PROD_NUM_6123,
3666 .family = MV88E6XXX_FAMILY_6165,
3667 .name = "Marvell 88E6123",
3668 .num_databases = 4096,
3669 .num_ports = 3,
9dddd478 3670 .port_base_addr = 0x10,
a935c052 3671 .global1_addr = 0x1b,
acddbd21 3672 .age_time_coeff = 15000,
dc30c35b 3673 .g1_irqs = 9,
e606ca36 3674 .atu_move_port_mask = 0xf,
f3645652 3675 .pvt = true,
443d5a1b 3676 .tag_protocol = DSA_TAG_PROTO_DSA,
f81ec90f 3677 .flags = MV88E6XXX_FLAGS_FAMILY_6165,
b3469dd8 3678 .ops = &mv88e6123_ops,
f81ec90f
VD
3679 },
3680
3681 [MV88E6131] = {
3682 .prod_num = PORT_SWITCH_ID_PROD_NUM_6131,
3683 .family = MV88E6XXX_FAMILY_6185,
3684 .name = "Marvell 88E6131",
3685 .num_databases = 256,
3686 .num_ports = 8,
9dddd478 3687 .port_base_addr = 0x10,
a935c052 3688 .global1_addr = 0x1b,
acddbd21 3689 .age_time_coeff = 15000,
dc30c35b 3690 .g1_irqs = 9,
e606ca36 3691 .atu_move_port_mask = 0xf,
443d5a1b 3692 .tag_protocol = DSA_TAG_PROTO_DSA,
f81ec90f 3693 .flags = MV88E6XXX_FLAGS_FAMILY_6185,
b3469dd8 3694 .ops = &mv88e6131_ops,
f81ec90f
VD
3695 },
3696
990e27b0
VD
3697 [MV88E6141] = {
3698 .prod_num = PORT_SWITCH_ID_PROD_NUM_6141,
3699 .family = MV88E6XXX_FAMILY_6341,
3700 .name = "Marvell 88E6341",
3701 .num_databases = 4096,
3702 .num_ports = 6,
3703 .port_base_addr = 0x10,
3704 .global1_addr = 0x1b,
3705 .age_time_coeff = 3750,
3706 .atu_move_port_mask = 0x1f,
f3645652 3707 .pvt = true,
990e27b0
VD
3708 .tag_protocol = DSA_TAG_PROTO_EDSA,
3709 .flags = MV88E6XXX_FLAGS_FAMILY_6341,
3710 .ops = &mv88e6141_ops,
3711 },
3712
f81ec90f
VD
3713 [MV88E6161] = {
3714 .prod_num = PORT_SWITCH_ID_PROD_NUM_6161,
3715 .family = MV88E6XXX_FAMILY_6165,
3716 .name = "Marvell 88E6161",
3717 .num_databases = 4096,
3718 .num_ports = 6,
9dddd478 3719 .port_base_addr = 0x10,
a935c052 3720 .global1_addr = 0x1b,
acddbd21 3721 .age_time_coeff = 15000,
dc30c35b 3722 .g1_irqs = 9,
e606ca36 3723 .atu_move_port_mask = 0xf,
f3645652 3724 .pvt = true,
443d5a1b 3725 .tag_protocol = DSA_TAG_PROTO_DSA,
f81ec90f 3726 .flags = MV88E6XXX_FLAGS_FAMILY_6165,
b3469dd8 3727 .ops = &mv88e6161_ops,
f81ec90f
VD
3728 },
3729
3730 [MV88E6165] = {
3731 .prod_num = PORT_SWITCH_ID_PROD_NUM_6165,
3732 .family = MV88E6XXX_FAMILY_6165,
3733 .name = "Marvell 88E6165",
3734 .num_databases = 4096,
3735 .num_ports = 6,
9dddd478 3736 .port_base_addr = 0x10,
a935c052 3737 .global1_addr = 0x1b,
acddbd21 3738 .age_time_coeff = 15000,
dc30c35b 3739 .g1_irqs = 9,
e606ca36 3740 .atu_move_port_mask = 0xf,
f3645652 3741 .pvt = true,
443d5a1b 3742 .tag_protocol = DSA_TAG_PROTO_DSA,
f81ec90f 3743 .flags = MV88E6XXX_FLAGS_FAMILY_6165,
b3469dd8 3744 .ops = &mv88e6165_ops,
f81ec90f
VD
3745 },
3746
3747 [MV88E6171] = {
3748 .prod_num = PORT_SWITCH_ID_PROD_NUM_6171,
3749 .family = MV88E6XXX_FAMILY_6351,
3750 .name = "Marvell 88E6171",
3751 .num_databases = 4096,
3752 .num_ports = 7,
9dddd478 3753 .port_base_addr = 0x10,
a935c052 3754 .global1_addr = 0x1b,
acddbd21 3755 .age_time_coeff = 15000,
dc30c35b 3756 .g1_irqs = 9,
e606ca36 3757 .atu_move_port_mask = 0xf,
f3645652 3758 .pvt = true,
443d5a1b 3759 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3760 .flags = MV88E6XXX_FLAGS_FAMILY_6351,
b3469dd8 3761 .ops = &mv88e6171_ops,
f81ec90f
VD
3762 },
3763
3764 [MV88E6172] = {
3765 .prod_num = PORT_SWITCH_ID_PROD_NUM_6172,
3766 .family = MV88E6XXX_FAMILY_6352,
3767 .name = "Marvell 88E6172",
3768 .num_databases = 4096,
3769 .num_ports = 7,
9dddd478 3770 .port_base_addr = 0x10,
a935c052 3771 .global1_addr = 0x1b,
acddbd21 3772 .age_time_coeff = 15000,
dc30c35b 3773 .g1_irqs = 9,
e606ca36 3774 .atu_move_port_mask = 0xf,
f3645652 3775 .pvt = true,
443d5a1b 3776 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3777 .flags = MV88E6XXX_FLAGS_FAMILY_6352,
b3469dd8 3778 .ops = &mv88e6172_ops,
f81ec90f
VD
3779 },
3780
3781 [MV88E6175] = {
3782 .prod_num = PORT_SWITCH_ID_PROD_NUM_6175,
3783 .family = MV88E6XXX_FAMILY_6351,
3784 .name = "Marvell 88E6175",
3785 .num_databases = 4096,
3786 .num_ports = 7,
9dddd478 3787 .port_base_addr = 0x10,
a935c052 3788 .global1_addr = 0x1b,
acddbd21 3789 .age_time_coeff = 15000,
dc30c35b 3790 .g1_irqs = 9,
e606ca36 3791 .atu_move_port_mask = 0xf,
f3645652 3792 .pvt = true,
443d5a1b 3793 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3794 .flags = MV88E6XXX_FLAGS_FAMILY_6351,
b3469dd8 3795 .ops = &mv88e6175_ops,
f81ec90f
VD
3796 },
3797
3798 [MV88E6176] = {
3799 .prod_num = PORT_SWITCH_ID_PROD_NUM_6176,
3800 .family = MV88E6XXX_FAMILY_6352,
3801 .name = "Marvell 88E6176",
3802 .num_databases = 4096,
3803 .num_ports = 7,
9dddd478 3804 .port_base_addr = 0x10,
a935c052 3805 .global1_addr = 0x1b,
acddbd21 3806 .age_time_coeff = 15000,
dc30c35b 3807 .g1_irqs = 9,
e606ca36 3808 .atu_move_port_mask = 0xf,
f3645652 3809 .pvt = true,
443d5a1b 3810 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3811 .flags = MV88E6XXX_FLAGS_FAMILY_6352,
b3469dd8 3812 .ops = &mv88e6176_ops,
f81ec90f
VD
3813 },
3814
3815 [MV88E6185] = {
3816 .prod_num = PORT_SWITCH_ID_PROD_NUM_6185,
3817 .family = MV88E6XXX_FAMILY_6185,
3818 .name = "Marvell 88E6185",
3819 .num_databases = 256,
3820 .num_ports = 10,
9dddd478 3821 .port_base_addr = 0x10,
a935c052 3822 .global1_addr = 0x1b,
acddbd21 3823 .age_time_coeff = 15000,
dc30c35b 3824 .g1_irqs = 8,
e606ca36 3825 .atu_move_port_mask = 0xf,
443d5a1b 3826 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3827 .flags = MV88E6XXX_FLAGS_FAMILY_6185,
b3469dd8 3828 .ops = &mv88e6185_ops,
f81ec90f
VD
3829 },
3830
1a3b39ec
AL
3831 [MV88E6190] = {
3832 .prod_num = PORT_SWITCH_ID_PROD_NUM_6190,
3833 .family = MV88E6XXX_FAMILY_6390,
3834 .name = "Marvell 88E6190",
3835 .num_databases = 4096,
3836 .num_ports = 11, /* 10 + Z80 */
3837 .port_base_addr = 0x0,
3838 .global1_addr = 0x1b,
443d5a1b 3839 .tag_protocol = DSA_TAG_PROTO_DSA,
b91e055c 3840 .age_time_coeff = 3750,
1a3b39ec 3841 .g1_irqs = 9,
f3645652 3842 .pvt = true,
e606ca36 3843 .atu_move_port_mask = 0x1f,
1a3b39ec
AL
3844 .flags = MV88E6XXX_FLAGS_FAMILY_6390,
3845 .ops = &mv88e6190_ops,
3846 },
3847
3848 [MV88E6190X] = {
3849 .prod_num = PORT_SWITCH_ID_PROD_NUM_6190X,
3850 .family = MV88E6XXX_FAMILY_6390,
3851 .name = "Marvell 88E6190X",
3852 .num_databases = 4096,
3853 .num_ports = 11, /* 10 + Z80 */
3854 .port_base_addr = 0x0,
3855 .global1_addr = 0x1b,
b91e055c 3856 .age_time_coeff = 3750,
1a3b39ec 3857 .g1_irqs = 9,
e606ca36 3858 .atu_move_port_mask = 0x1f,
f3645652 3859 .pvt = true,
443d5a1b 3860 .tag_protocol = DSA_TAG_PROTO_DSA,
1a3b39ec
AL
3861 .flags = MV88E6XXX_FLAGS_FAMILY_6390,
3862 .ops = &mv88e6190x_ops,
3863 },
3864
3865 [MV88E6191] = {
3866 .prod_num = PORT_SWITCH_ID_PROD_NUM_6191,
3867 .family = MV88E6XXX_FAMILY_6390,
3868 .name = "Marvell 88E6191",
3869 .num_databases = 4096,
3870 .num_ports = 11, /* 10 + Z80 */
3871 .port_base_addr = 0x0,
3872 .global1_addr = 0x1b,
b91e055c 3873 .age_time_coeff = 3750,
443d5a1b 3874 .g1_irqs = 9,
e606ca36 3875 .atu_move_port_mask = 0x1f,
f3645652 3876 .pvt = true,
443d5a1b 3877 .tag_protocol = DSA_TAG_PROTO_DSA,
1a3b39ec 3878 .flags = MV88E6XXX_FLAGS_FAMILY_6390,
2cf4cefb 3879 .ops = &mv88e6191_ops,
1a3b39ec
AL
3880 },
3881
f81ec90f
VD
3882 [MV88E6240] = {
3883 .prod_num = PORT_SWITCH_ID_PROD_NUM_6240,
3884 .family = MV88E6XXX_FAMILY_6352,
3885 .name = "Marvell 88E6240",
3886 .num_databases = 4096,
3887 .num_ports = 7,
9dddd478 3888 .port_base_addr = 0x10,
a935c052 3889 .global1_addr = 0x1b,
acddbd21 3890 .age_time_coeff = 15000,
dc30c35b 3891 .g1_irqs = 9,
e606ca36 3892 .atu_move_port_mask = 0xf,
f3645652 3893 .pvt = true,
443d5a1b 3894 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3895 .flags = MV88E6XXX_FLAGS_FAMILY_6352,
b3469dd8 3896 .ops = &mv88e6240_ops,
f81ec90f
VD
3897 },
3898
1a3b39ec
AL
3899 [MV88E6290] = {
3900 .prod_num = PORT_SWITCH_ID_PROD_NUM_6290,
3901 .family = MV88E6XXX_FAMILY_6390,
3902 .name = "Marvell 88E6290",
3903 .num_databases = 4096,
3904 .num_ports = 11, /* 10 + Z80 */
3905 .port_base_addr = 0x0,
3906 .global1_addr = 0x1b,
b91e055c 3907 .age_time_coeff = 3750,
1a3b39ec 3908 .g1_irqs = 9,
e606ca36 3909 .atu_move_port_mask = 0x1f,
f3645652 3910 .pvt = true,
443d5a1b 3911 .tag_protocol = DSA_TAG_PROTO_DSA,
1a3b39ec
AL
3912 .flags = MV88E6XXX_FLAGS_FAMILY_6390,
3913 .ops = &mv88e6290_ops,
3914 },
3915
f81ec90f
VD
3916 [MV88E6320] = {
3917 .prod_num = PORT_SWITCH_ID_PROD_NUM_6320,
3918 .family = MV88E6XXX_FAMILY_6320,
3919 .name = "Marvell 88E6320",
3920 .num_databases = 4096,
3921 .num_ports = 7,
9dddd478 3922 .port_base_addr = 0x10,
a935c052 3923 .global1_addr = 0x1b,
acddbd21 3924 .age_time_coeff = 15000,
dc30c35b 3925 .g1_irqs = 8,
e606ca36 3926 .atu_move_port_mask = 0xf,
f3645652 3927 .pvt = true,
443d5a1b 3928 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3929 .flags = MV88E6XXX_FLAGS_FAMILY_6320,
b3469dd8 3930 .ops = &mv88e6320_ops,
f81ec90f
VD
3931 },
3932
3933 [MV88E6321] = {
3934 .prod_num = PORT_SWITCH_ID_PROD_NUM_6321,
3935 .family = MV88E6XXX_FAMILY_6320,
3936 .name = "Marvell 88E6321",
3937 .num_databases = 4096,
3938 .num_ports = 7,
9dddd478 3939 .port_base_addr = 0x10,
a935c052 3940 .global1_addr = 0x1b,
acddbd21 3941 .age_time_coeff = 15000,
dc30c35b 3942 .g1_irqs = 8,
e606ca36 3943 .atu_move_port_mask = 0xf,
443d5a1b 3944 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3945 .flags = MV88E6XXX_FLAGS_FAMILY_6320,
b3469dd8 3946 .ops = &mv88e6321_ops,
f81ec90f
VD
3947 },
3948
a75961d0
GC
3949 [MV88E6341] = {
3950 .prod_num = PORT_SWITCH_ID_PROD_NUM_6341,
3951 .family = MV88E6XXX_FAMILY_6341,
3952 .name = "Marvell 88E6341",
3953 .num_databases = 4096,
3954 .num_ports = 6,
3955 .port_base_addr = 0x10,
3956 .global1_addr = 0x1b,
3957 .age_time_coeff = 3750,
e606ca36 3958 .atu_move_port_mask = 0x1f,
f3645652 3959 .pvt = true,
a75961d0
GC
3960 .tag_protocol = DSA_TAG_PROTO_EDSA,
3961 .flags = MV88E6XXX_FLAGS_FAMILY_6341,
3962 .ops = &mv88e6341_ops,
3963 },
3964
f81ec90f
VD
3965 [MV88E6350] = {
3966 .prod_num = PORT_SWITCH_ID_PROD_NUM_6350,
3967 .family = MV88E6XXX_FAMILY_6351,
3968 .name = "Marvell 88E6350",
3969 .num_databases = 4096,
3970 .num_ports = 7,
9dddd478 3971 .port_base_addr = 0x10,
a935c052 3972 .global1_addr = 0x1b,
acddbd21 3973 .age_time_coeff = 15000,
dc30c35b 3974 .g1_irqs = 9,
e606ca36 3975 .atu_move_port_mask = 0xf,
f3645652 3976 .pvt = true,
443d5a1b 3977 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3978 .flags = MV88E6XXX_FLAGS_FAMILY_6351,
b3469dd8 3979 .ops = &mv88e6350_ops,
f81ec90f
VD
3980 },
3981
3982 [MV88E6351] = {
3983 .prod_num = PORT_SWITCH_ID_PROD_NUM_6351,
3984 .family = MV88E6XXX_FAMILY_6351,
3985 .name = "Marvell 88E6351",
3986 .num_databases = 4096,
3987 .num_ports = 7,
9dddd478 3988 .port_base_addr = 0x10,
a935c052 3989 .global1_addr = 0x1b,
acddbd21 3990 .age_time_coeff = 15000,
dc30c35b 3991 .g1_irqs = 9,
e606ca36 3992 .atu_move_port_mask = 0xf,
f3645652 3993 .pvt = true,
443d5a1b 3994 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3995 .flags = MV88E6XXX_FLAGS_FAMILY_6351,
b3469dd8 3996 .ops = &mv88e6351_ops,
f81ec90f
VD
3997 },
3998
3999 [MV88E6352] = {
4000 .prod_num = PORT_SWITCH_ID_PROD_NUM_6352,
4001 .family = MV88E6XXX_FAMILY_6352,
4002 .name = "Marvell 88E6352",
4003 .num_databases = 4096,
4004 .num_ports = 7,
9dddd478 4005 .port_base_addr = 0x10,
a935c052 4006 .global1_addr = 0x1b,
acddbd21 4007 .age_time_coeff = 15000,
dc30c35b 4008 .g1_irqs = 9,
e606ca36 4009 .atu_move_port_mask = 0xf,
f3645652 4010 .pvt = true,
443d5a1b 4011 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 4012 .flags = MV88E6XXX_FLAGS_FAMILY_6352,
b3469dd8 4013 .ops = &mv88e6352_ops,
f81ec90f 4014 },
1a3b39ec
AL
4015 [MV88E6390] = {
4016 .prod_num = PORT_SWITCH_ID_PROD_NUM_6390,
4017 .family = MV88E6XXX_FAMILY_6390,
4018 .name = "Marvell 88E6390",
4019 .num_databases = 4096,
4020 .num_ports = 11, /* 10 + Z80 */
4021 .port_base_addr = 0x0,
4022 .global1_addr = 0x1b,
b91e055c 4023 .age_time_coeff = 3750,
1a3b39ec 4024 .g1_irqs = 9,
e606ca36 4025 .atu_move_port_mask = 0x1f,
f3645652 4026 .pvt = true,
443d5a1b 4027 .tag_protocol = DSA_TAG_PROTO_DSA,
1a3b39ec
AL
4028 .flags = MV88E6XXX_FLAGS_FAMILY_6390,
4029 .ops = &mv88e6390_ops,
4030 },
4031 [MV88E6390X] = {
4032 .prod_num = PORT_SWITCH_ID_PROD_NUM_6390X,
4033 .family = MV88E6XXX_FAMILY_6390,
4034 .name = "Marvell 88E6390X",
4035 .num_databases = 4096,
4036 .num_ports = 11, /* 10 + Z80 */
4037 .port_base_addr = 0x0,
4038 .global1_addr = 0x1b,
b91e055c 4039 .age_time_coeff = 3750,
1a3b39ec 4040 .g1_irqs = 9,
e606ca36 4041 .atu_move_port_mask = 0x1f,
f3645652 4042 .pvt = true,
443d5a1b 4043 .tag_protocol = DSA_TAG_PROTO_DSA,
1a3b39ec
AL
4044 .flags = MV88E6XXX_FLAGS_FAMILY_6390,
4045 .ops = &mv88e6390x_ops,
4046 },
f81ec90f
VD
4047};
4048
5f7c0367 4049static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
b9b37713 4050{
a439c061 4051 int i;
b9b37713 4052
5f7c0367
VD
4053 for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
4054 if (mv88e6xxx_table[i].prod_num == prod_num)
4055 return &mv88e6xxx_table[i];
b9b37713 4056
b9b37713
VD
4057 return NULL;
4058}
4059
fad09c73 4060static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
bc46a3d5
VD
4061{
4062 const struct mv88e6xxx_info *info;
8f6345b2
VD
4063 unsigned int prod_num, rev;
4064 u16 id;
4065 int err;
bc46a3d5 4066
8f6345b2
VD
4067 mutex_lock(&chip->reg_lock);
4068 err = mv88e6xxx_port_read(chip, 0, PORT_SWITCH_ID, &id);
4069 mutex_unlock(&chip->reg_lock);
4070 if (err)
4071 return err;
bc46a3d5
VD
4072
4073 prod_num = (id & 0xfff0) >> 4;
4074 rev = id & 0x000f;
4075
4076 info = mv88e6xxx_lookup_info(prod_num);
4077 if (!info)
4078 return -ENODEV;
4079
caac8545 4080 /* Update the compatible info with the probed one */
fad09c73 4081 chip->info = info;
bc46a3d5 4082
ca070c10
VD
4083 err = mv88e6xxx_g2_require(chip);
4084 if (err)
4085 return err;
4086
fad09c73
VD
4087 dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
4088 chip->info->prod_num, chip->info->name, rev);
bc46a3d5
VD
4089
4090 return 0;
4091}
4092
fad09c73 4093static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
469d729f 4094{
fad09c73 4095 struct mv88e6xxx_chip *chip;
469d729f 4096
fad09c73
VD
4097 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
4098 if (!chip)
469d729f
VD
4099 return NULL;
4100
fad09c73 4101 chip->dev = dev;
469d729f 4102
fad09c73 4103 mutex_init(&chip->reg_lock);
a3c53be5 4104 INIT_LIST_HEAD(&chip->mdios);
469d729f 4105
fad09c73 4106 return chip;
469d729f
VD
4107}
4108
e57e5e77
VD
4109static void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip)
4110{
a199d8b6 4111 if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
e57e5e77 4112 mv88e6xxx_ppu_state_init(chip);
e57e5e77
VD
4113}
4114
930188ce
AL
4115static void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip)
4116{
a199d8b6 4117 if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
930188ce 4118 mv88e6xxx_ppu_state_destroy(chip);
930188ce
AL
4119}
4120
fad09c73 4121static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
4a70c4ab
VD
4122 struct mii_bus *bus, int sw_addr)
4123{
914b32f6 4124 if (sw_addr == 0)
fad09c73 4125 chip->smi_ops = &mv88e6xxx_smi_single_chip_ops;
a0ffff24 4126 else if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_MULTI_CHIP))
fad09c73 4127 chip->smi_ops = &mv88e6xxx_smi_multi_chip_ops;
914b32f6
VD
4128 else
4129 return -EINVAL;
4130
fad09c73
VD
4131 chip->bus = bus;
4132 chip->sw_addr = sw_addr;
4a70c4ab
VD
4133
4134 return 0;
4135}
4136
7b314362
AL
4137static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds)
4138{
04bed143 4139 struct mv88e6xxx_chip *chip = ds->priv;
2bbb33be 4140
443d5a1b 4141 return chip->info->tag_protocol;
7b314362
AL
4142}
4143
fcdce7d0
AL
4144static const char *mv88e6xxx_drv_probe(struct device *dsa_dev,
4145 struct device *host_dev, int sw_addr,
4146 void **priv)
a77d43f1 4147{
fad09c73 4148 struct mv88e6xxx_chip *chip;
a439c061 4149 struct mii_bus *bus;
b516d453 4150 int err;
a77d43f1 4151
a439c061 4152 bus = dsa_host_dev_to_mii_bus(host_dev);
c156913b
AL
4153 if (!bus)
4154 return NULL;
4155
fad09c73
VD
4156 chip = mv88e6xxx_alloc_chip(dsa_dev);
4157 if (!chip)
469d729f
VD
4158 return NULL;
4159
caac8545 4160 /* Legacy SMI probing will only support chips similar to 88E6085 */
fad09c73 4161 chip->info = &mv88e6xxx_table[MV88E6085];
caac8545 4162
fad09c73 4163 err = mv88e6xxx_smi_init(chip, bus, sw_addr);
4a70c4ab
VD
4164 if (err)
4165 goto free;
4166
fad09c73 4167 err = mv88e6xxx_detect(chip);
bc46a3d5 4168 if (err)
469d729f 4169 goto free;
a439c061 4170
dc30c35b
AL
4171 mutex_lock(&chip->reg_lock);
4172 err = mv88e6xxx_switch_reset(chip);
4173 mutex_unlock(&chip->reg_lock);
4174 if (err)
4175 goto free;
4176
e57e5e77
VD
4177 mv88e6xxx_phy_init(chip);
4178
a3c53be5 4179 err = mv88e6xxx_mdios_register(chip, NULL);
b516d453 4180 if (err)
469d729f 4181 goto free;
b516d453 4182
fad09c73 4183 *priv = chip;
a439c061 4184
fad09c73 4185 return chip->info->name;
469d729f 4186free:
fad09c73 4187 devm_kfree(dsa_dev, chip);
469d729f
VD
4188
4189 return NULL;
a77d43f1
AL
4190}
4191
7df8fbdd
VD
4192static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port,
4193 const struct switchdev_obj_port_mdb *mdb,
4194 struct switchdev_trans *trans)
4195{
4196 /* We don't need any dynamic resource from the kernel (yet),
4197 * so skip the prepare phase.
4198 */
4199
4200 return 0;
4201}
4202
4203static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
4204 const struct switchdev_obj_port_mdb *mdb,
4205 struct switchdev_trans *trans)
4206{
04bed143 4207 struct mv88e6xxx_chip *chip = ds->priv;
7df8fbdd
VD
4208
4209 mutex_lock(&chip->reg_lock);
4210 if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
4211 GLOBAL_ATU_DATA_STATE_MC_STATIC))
4212 netdev_err(ds->ports[port].netdev, "failed to load multicast MAC address\n");
4213 mutex_unlock(&chip->reg_lock);
4214}
4215
4216static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
4217 const struct switchdev_obj_port_mdb *mdb)
4218{
04bed143 4219 struct mv88e6xxx_chip *chip = ds->priv;
7df8fbdd
VD
4220 int err;
4221
4222 mutex_lock(&chip->reg_lock);
4223 err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
4224 GLOBAL_ATU_DATA_STATE_UNUSED);
4225 mutex_unlock(&chip->reg_lock);
4226
4227 return err;
4228}
4229
4230static int mv88e6xxx_port_mdb_dump(struct dsa_switch *ds, int port,
4231 struct switchdev_obj_port_mdb *mdb,
4232 int (*cb)(struct switchdev_obj *obj))
4233{
04bed143 4234 struct mv88e6xxx_chip *chip = ds->priv;
7df8fbdd
VD
4235 int err;
4236
4237 mutex_lock(&chip->reg_lock);
4238 err = mv88e6xxx_port_db_dump(chip, port, &mdb->obj, cb);
4239 mutex_unlock(&chip->reg_lock);
4240
4241 return err;
4242}
4243
a82f67af 4244static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
fcdce7d0 4245 .probe = mv88e6xxx_drv_probe,
7b314362 4246 .get_tag_protocol = mv88e6xxx_get_tag_protocol,
f81ec90f
VD
4247 .setup = mv88e6xxx_setup,
4248 .set_addr = mv88e6xxx_set_addr,
f81ec90f
VD
4249 .adjust_link = mv88e6xxx_adjust_link,
4250 .get_strings = mv88e6xxx_get_strings,
4251 .get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
4252 .get_sset_count = mv88e6xxx_get_sset_count,
4253 .set_eee = mv88e6xxx_set_eee,
4254 .get_eee = mv88e6xxx_get_eee,
f8cd8753 4255 .get_eeprom_len = mv88e6xxx_get_eeprom_len,
f81ec90f
VD
4256 .get_eeprom = mv88e6xxx_get_eeprom,
4257 .set_eeprom = mv88e6xxx_set_eeprom,
4258 .get_regs_len = mv88e6xxx_get_regs_len,
4259 .get_regs = mv88e6xxx_get_regs,
2cfcd964 4260 .set_ageing_time = mv88e6xxx_set_ageing_time,
f81ec90f
VD
4261 .port_bridge_join = mv88e6xxx_port_bridge_join,
4262 .port_bridge_leave = mv88e6xxx_port_bridge_leave,
4263 .port_stp_state_set = mv88e6xxx_port_stp_state_set,
749efcb8 4264 .port_fast_age = mv88e6xxx_port_fast_age,
f81ec90f
VD
4265 .port_vlan_filtering = mv88e6xxx_port_vlan_filtering,
4266 .port_vlan_prepare = mv88e6xxx_port_vlan_prepare,
4267 .port_vlan_add = mv88e6xxx_port_vlan_add,
4268 .port_vlan_del = mv88e6xxx_port_vlan_del,
4269 .port_vlan_dump = mv88e6xxx_port_vlan_dump,
4270 .port_fdb_prepare = mv88e6xxx_port_fdb_prepare,
4271 .port_fdb_add = mv88e6xxx_port_fdb_add,
4272 .port_fdb_del = mv88e6xxx_port_fdb_del,
4273 .port_fdb_dump = mv88e6xxx_port_fdb_dump,
7df8fbdd
VD
4274 .port_mdb_prepare = mv88e6xxx_port_mdb_prepare,
4275 .port_mdb_add = mv88e6xxx_port_mdb_add,
4276 .port_mdb_del = mv88e6xxx_port_mdb_del,
4277 .port_mdb_dump = mv88e6xxx_port_mdb_dump,
f81ec90f
VD
4278};
4279
ab3d408d
FF
4280static struct dsa_switch_driver mv88e6xxx_switch_drv = {
4281 .ops = &mv88e6xxx_switch_ops,
4282};
4283
55ed0ce0 4284static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
b7e66a5f 4285{
fad09c73 4286 struct device *dev = chip->dev;
b7e66a5f
VD
4287 struct dsa_switch *ds;
4288
a0c02161 4289 ds = dsa_switch_alloc(dev, DSA_MAX_PORTS);
b7e66a5f
VD
4290 if (!ds)
4291 return -ENOMEM;
4292
fad09c73 4293 ds->priv = chip;
9d490b4e 4294 ds->ops = &mv88e6xxx_switch_ops;
9ff74f24
VD
4295 ds->ageing_time_min = chip->info->age_time_coeff;
4296 ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
b7e66a5f
VD
4297
4298 dev_set_drvdata(dev, ds);
4299
55ed0ce0 4300 return dsa_register_switch(ds, dev);
b7e66a5f
VD
4301}
4302
fad09c73 4303static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
b7e66a5f 4304{
fad09c73 4305 dsa_unregister_switch(chip->ds);
b7e66a5f
VD
4306}
4307
57d32310 4308static int mv88e6xxx_probe(struct mdio_device *mdiodev)
98e67308 4309{
14c7b3c3 4310 struct device *dev = &mdiodev->dev;
f8cd8753 4311 struct device_node *np = dev->of_node;
caac8545 4312 const struct mv88e6xxx_info *compat_info;
fad09c73 4313 struct mv88e6xxx_chip *chip;
f8cd8753 4314 u32 eeprom_len;
52638f71 4315 int err;
14c7b3c3 4316
caac8545
VD
4317 compat_info = of_device_get_match_data(dev);
4318 if (!compat_info)
4319 return -EINVAL;
4320
fad09c73
VD
4321 chip = mv88e6xxx_alloc_chip(dev);
4322 if (!chip)
14c7b3c3
AL
4323 return -ENOMEM;
4324
fad09c73 4325 chip->info = compat_info;
caac8545 4326
fad09c73 4327 err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
4a70c4ab
VD
4328 if (err)
4329 return err;
14c7b3c3 4330
b4308f04
AL
4331 chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
4332 if (IS_ERR(chip->reset))
4333 return PTR_ERR(chip->reset);
4334
fad09c73 4335 err = mv88e6xxx_detect(chip);
bc46a3d5
VD
4336 if (err)
4337 return err;
14c7b3c3 4338
e57e5e77
VD
4339 mv88e6xxx_phy_init(chip);
4340
ee4dc2e7 4341 if (chip->info->ops->get_eeprom &&
f8cd8753 4342 !of_property_read_u32(np, "eeprom-length", &eeprom_len))
fad09c73 4343 chip->eeprom_len = eeprom_len;
f8cd8753 4344
dc30c35b
AL
4345 mutex_lock(&chip->reg_lock);
4346 err = mv88e6xxx_switch_reset(chip);
4347 mutex_unlock(&chip->reg_lock);
4348 if (err)
4349 goto out;
4350
4351 chip->irq = of_irq_get(np, 0);
4352 if (chip->irq == -EPROBE_DEFER) {
4353 err = chip->irq;
4354 goto out;
4355 }
4356
4357 if (chip->irq > 0) {
4358 /* Has to be performed before the MDIO bus is created,
4359 * because the PHYs will link there interrupts to these
4360 * interrupt controllers
4361 */
4362 mutex_lock(&chip->reg_lock);
4363 err = mv88e6xxx_g1_irq_setup(chip);
4364 mutex_unlock(&chip->reg_lock);
4365
4366 if (err)
4367 goto out;
4368
4369 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT)) {
4370 err = mv88e6xxx_g2_irq_setup(chip);
4371 if (err)
4372 goto out_g1_irq;
4373 }
4374 }
4375
a3c53be5 4376 err = mv88e6xxx_mdios_register(chip, np);
b516d453 4377 if (err)
dc30c35b 4378 goto out_g2_irq;
b516d453 4379
55ed0ce0 4380 err = mv88e6xxx_register_switch(chip);
dc30c35b
AL
4381 if (err)
4382 goto out_mdio;
83c0afae 4383
98e67308 4384 return 0;
dc30c35b
AL
4385
4386out_mdio:
a3c53be5 4387 mv88e6xxx_mdios_unregister(chip);
dc30c35b 4388out_g2_irq:
46712644 4389 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT) && chip->irq > 0)
dc30c35b
AL
4390 mv88e6xxx_g2_irq_free(chip);
4391out_g1_irq:
61f7c3f8
AL
4392 if (chip->irq > 0) {
4393 mutex_lock(&chip->reg_lock);
46712644 4394 mv88e6xxx_g1_irq_free(chip);
61f7c3f8
AL
4395 mutex_unlock(&chip->reg_lock);
4396 }
dc30c35b
AL
4397out:
4398 return err;
98e67308 4399}
14c7b3c3
AL
4400
4401static void mv88e6xxx_remove(struct mdio_device *mdiodev)
4402{
4403 struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
04bed143 4404 struct mv88e6xxx_chip *chip = ds->priv;
14c7b3c3 4405
930188ce 4406 mv88e6xxx_phy_destroy(chip);
fad09c73 4407 mv88e6xxx_unregister_switch(chip);
a3c53be5 4408 mv88e6xxx_mdios_unregister(chip);
dc30c35b 4409
46712644
AL
4410 if (chip->irq > 0) {
4411 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT))
4412 mv88e6xxx_g2_irq_free(chip);
4413 mv88e6xxx_g1_irq_free(chip);
4414 }
14c7b3c3
AL
4415}
4416
4417static const struct of_device_id mv88e6xxx_of_match[] = {
caac8545
VD
4418 {
4419 .compatible = "marvell,mv88e6085",
4420 .data = &mv88e6xxx_table[MV88E6085],
4421 },
1a3b39ec
AL
4422 {
4423 .compatible = "marvell,mv88e6190",
4424 .data = &mv88e6xxx_table[MV88E6190],
4425 },
14c7b3c3
AL
4426 { /* sentinel */ },
4427};
4428
4429MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);
4430
4431static struct mdio_driver mv88e6xxx_driver = {
4432 .probe = mv88e6xxx_probe,
4433 .remove = mv88e6xxx_remove,
4434 .mdiodrv.driver = {
4435 .name = "mv88e6085",
4436 .of_match_table = mv88e6xxx_of_match,
4437 },
4438};
4439
4440static int __init mv88e6xxx_init(void)
4441{
ab3d408d 4442 register_switch_driver(&mv88e6xxx_switch_drv);
14c7b3c3
AL
4443 return mdio_driver_register(&mv88e6xxx_driver);
4444}
98e67308
BH
4445module_init(mv88e6xxx_init);
4446
4447static void __exit mv88e6xxx_cleanup(void)
4448{
14c7b3c3 4449 mdio_driver_unregister(&mv88e6xxx_driver);
ab3d408d 4450 unregister_switch_driver(&mv88e6xxx_switch_drv);
98e67308
BH
4451}
4452module_exit(mv88e6xxx_cleanup);
3d825ede
BH
4453
4454MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
4455MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
4456MODULE_LICENSE("GPL");