1727 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Marvell 88E6xxx Switch Port Registers support4 *5 * Copyright (c) 2008 Marvell Semiconductor6 *7 * Copyright (c) 2016-2017 Savoir-faire Linux Inc.8 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>9 */10 11#include <linux/bitfield.h>12#include <linux/if_bridge.h>13#include <linux/phy.h>14#include <linux/phylink.h>15 16#include "chip.h"17#include "global2.h"18#include "port.h"19#include "serdes.h"20 21int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,22 u16 *val)23{24 int addr = chip->info->port_base_addr + port;25 26 return mv88e6xxx_read(chip, addr, reg, val);27}28 29int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,30 int bit, int val)31{32 int addr = chip->info->port_base_addr + port;33 34 return mv88e6xxx_wait_bit(chip, addr, reg, bit, val);35}36 37int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,38 u16 val)39{40 int addr = chip->info->port_base_addr + port;41 42 return mv88e6xxx_write(chip, addr, reg, val);43}44 45/* Offset 0x00: MAC (or PCS or Physical) Status Register46 *47 * For most devices, this is read only. However the 6185 has the MyPause48 * bit read/write.49 */50int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,51 int pause)52{53 u16 reg;54 int err;55 56 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®);57 if (err)58 return err;59 60 if (pause)61 reg |= MV88E6XXX_PORT_STS_MY_PAUSE;62 else63 reg &= ~MV88E6XXX_PORT_STS_MY_PAUSE;64 65 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);66}67 68/* Offset 0x01: MAC (or PCS or Physical) Control Register69 *70 * Link, Duplex and Flow Control have one force bit, one value bit.71 *72 * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value.73 * Alternative values require the 200BASE (or AltSpeed) bit 12 set.74 * Newer chips need a ForcedSpd bit 13 set to consider the value.75 */76 77static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,78 phy_interface_t mode)79{80 u16 reg;81 int err;82 83 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®);84 if (err)85 return err;86 87 reg &= ~(MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |88 MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK);89 90 switch (mode) {91 case PHY_INTERFACE_MODE_RGMII_RXID:92 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK;93 break;94 case PHY_INTERFACE_MODE_RGMII_TXID:95 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;96 break;97 case PHY_INTERFACE_MODE_RGMII_ID:98 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |99 MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;100 break;101 case PHY_INTERFACE_MODE_RGMII:102 break;103 default:104 return 0;105 }106 107 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);108 if (err)109 return err;110 111 dev_dbg(chip->dev, "p%d: delay RXCLK %s, TXCLK %s\n", port,112 reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK ? "yes" : "no",113 reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK ? "yes" : "no");114 115 return 0;116}117 118int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,119 phy_interface_t mode)120{121 if (port < 5)122 return -EOPNOTSUPP;123 124 return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);125}126 127int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,128 phy_interface_t mode)129{130 if (port != 0)131 return -EOPNOTSUPP;132 133 return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);134}135 136int mv88e6320_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,137 phy_interface_t mode)138{139 if (port != 2 && port != 5 && port != 6)140 return -EOPNOTSUPP;141 142 return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);143}144 145int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link)146{147 u16 reg;148 int err;149 150 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®);151 if (err)152 return err;153 154 reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |155 MV88E6XXX_PORT_MAC_CTL_LINK_UP);156 157 switch (link) {158 case LINK_FORCED_DOWN:159 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK;160 break;161 case LINK_FORCED_UP:162 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |163 MV88E6XXX_PORT_MAC_CTL_LINK_UP;164 break;165 case LINK_UNFORCED:166 /* normal link detection */167 break;168 default:169 return -EINVAL;170 }171 172 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);173 if (err)174 return err;175 176 dev_dbg(chip->dev, "p%d: %s link %s\n", port,177 reg & MV88E6XXX_PORT_MAC_CTL_FORCE_LINK ? "Force" : "Unforce",178 reg & MV88E6XXX_PORT_MAC_CTL_LINK_UP ? "up" : "down");179 180 return 0;181}182 183int mv88e6xxx_port_sync_link(struct mv88e6xxx_chip *chip, int port, unsigned int mode, bool isup)184{185 const struct mv88e6xxx_ops *ops = chip->info->ops;186 int err = 0;187 int link;188 189 if (isup)190 link = LINK_FORCED_UP;191 else192 link = LINK_FORCED_DOWN;193 194 if (ops->port_set_link)195 err = ops->port_set_link(chip, port, link);196 197 return err;198}199 200int mv88e6185_port_sync_link(struct mv88e6xxx_chip *chip, int port, unsigned int mode, bool isup)201{202 const struct mv88e6xxx_ops *ops = chip->info->ops;203 int err = 0;204 int link;205 206 if (mode == MLO_AN_INBAND)207 link = LINK_UNFORCED;208 else if (isup)209 link = LINK_FORCED_UP;210 else211 link = LINK_FORCED_DOWN;212 213 if (ops->port_set_link)214 err = ops->port_set_link(chip, port, link);215 216 return err;217}218 219static int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip,220 int port, int speed, bool alt_bit,221 bool force_bit, int duplex)222{223 u16 reg, ctrl;224 int err;225 226 switch (speed) {227 case 10:228 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;229 break;230 case 100:231 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;232 break;233 case 200:234 if (alt_bit)235 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |236 MV88E6390_PORT_MAC_CTL_ALTSPEED;237 else238 ctrl = MV88E6065_PORT_MAC_CTL_SPEED_200;239 break;240 case 1000:241 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;242 break;243 case 2500:244 if (alt_bit)245 ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |246 MV88E6390_PORT_MAC_CTL_ALTSPEED;247 else248 ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000;249 break;250 case 10000:251 /* all bits set, fall through... */252 case SPEED_UNFORCED:253 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;254 break;255 default:256 return -EOPNOTSUPP;257 }258 259 switch (duplex) {260 case DUPLEX_HALF:261 ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;262 break;263 case DUPLEX_FULL:264 ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |265 MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;266 break;267 case DUPLEX_UNFORCED:268 /* normal duplex detection */269 break;270 default:271 return -EOPNOTSUPP;272 }273 274 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®);275 if (err)276 return err;277 278 reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |279 MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |280 MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);281 282 if (alt_bit)283 reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED;284 if (force_bit) {285 reg &= ~MV88E6390_PORT_MAC_CTL_FORCE_SPEED;286 if (speed != SPEED_UNFORCED)287 ctrl |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;288 }289 reg |= ctrl;290 291 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);292 if (err)293 return err;294 295 if (speed != SPEED_UNFORCED)296 dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);297 else298 dev_dbg(chip->dev, "p%d: Speed unforced\n", port);299 dev_dbg(chip->dev, "p%d: %s %s duplex\n", port,300 reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce",301 reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half");302 303 return 0;304}305 306/* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */307int mv88e6185_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,308 int speed, int duplex)309{310 if (speed == 200 || speed > 1000)311 return -EOPNOTSUPP;312 313 return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false,314 duplex);315}316 317/* Support 10, 100 Mbps (e.g. 88E6250 family) */318int mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,319 int speed, int duplex)320{321 if (speed > 100)322 return -EOPNOTSUPP;323 324 return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false,325 duplex);326}327 328/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6341) */329int mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,330 int speed, int duplex)331{332 if (speed > 2500)333 return -EOPNOTSUPP;334 335 if (speed == 200 && port != 0)336 return -EOPNOTSUPP;337 338 if (speed == 2500 && port < 5)339 return -EOPNOTSUPP;340 341 return mv88e6xxx_port_set_speed_duplex(chip, port, speed, !port, true,342 duplex);343}344 345phy_interface_t mv88e6341_port_max_speed_mode(struct mv88e6xxx_chip *chip,346 int port)347{348 if (port == 5)349 return PHY_INTERFACE_MODE_2500BASEX;350 351 return PHY_INTERFACE_MODE_NA;352}353 354/* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */355int mv88e6352_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,356 int speed, int duplex)357{358 if (speed > 1000)359 return -EOPNOTSUPP;360 361 if (speed == 200 && port < 5)362 return -EOPNOTSUPP;363 364 return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, false,365 duplex);366}367 368/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */369int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,370 int speed, int duplex)371{372 if (speed > 2500)373 return -EOPNOTSUPP;374 375 if (speed == 200 && port != 0)376 return -EOPNOTSUPP;377 378 if (speed == 2500 && port < 9)379 return -EOPNOTSUPP;380 381 return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true,382 duplex);383}384 385phy_interface_t mv88e6390_port_max_speed_mode(struct mv88e6xxx_chip *chip,386 int port)387{388 if (port == 9 || port == 10)389 return PHY_INTERFACE_MODE_2500BASEX;390 391 return PHY_INTERFACE_MODE_NA;392}393 394/* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */395int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,396 int speed, int duplex)397{398 if (speed == 200 && port != 0)399 return -EOPNOTSUPP;400 401 if (speed >= 2500 && port < 9)402 return -EOPNOTSUPP;403 404 return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true,405 duplex);406}407 408phy_interface_t mv88e6390x_port_max_speed_mode(struct mv88e6xxx_chip *chip,409 int port)410{411 if (port == 9 || port == 10)412 return PHY_INTERFACE_MODE_XAUI;413 414 return PHY_INTERFACE_MODE_NA;415}416 417/* Support 10, 100, 200, 1000, 2500, 5000, 10000 Mbps (e.g. 88E6393X)418 * Function mv88e6xxx_port_set_speed_duplex() can't be used as the register419 * values for speeds 2500 & 5000 conflict.420 */421int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,422 int speed, int duplex)423{424 u16 reg, ctrl;425 int err;426 427 if (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361 &&428 speed > 2500)429 return -EOPNOTSUPP;430 431 if (speed == 200 && port != 0)432 return -EOPNOTSUPP;433 434 if (speed >= 2500 && port > 0 && port < 9)435 return -EOPNOTSUPP;436 437 switch (speed) {438 case 10:439 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;440 break;441 case 100:442 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;443 break;444 case 200:445 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |446 MV88E6390_PORT_MAC_CTL_ALTSPEED;447 break;448 case 1000:449 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;450 break;451 case 2500:452 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000 |453 MV88E6390_PORT_MAC_CTL_ALTSPEED;454 break;455 case 5000:456 ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |457 MV88E6390_PORT_MAC_CTL_ALTSPEED;458 break;459 case 10000:460 case SPEED_UNFORCED:461 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;462 break;463 default:464 return -EOPNOTSUPP;465 }466 467 switch (duplex) {468 case DUPLEX_HALF:469 ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;470 break;471 case DUPLEX_FULL:472 ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |473 MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;474 break;475 case DUPLEX_UNFORCED:476 /* normal duplex detection */477 break;478 default:479 return -EOPNOTSUPP;480 }481 482 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®);483 if (err)484 return err;485 486 reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |487 MV88E6390_PORT_MAC_CTL_ALTSPEED |488 MV88E6390_PORT_MAC_CTL_FORCE_SPEED);489 490 if (speed != SPEED_UNFORCED)491 reg |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;492 493 reg |= ctrl;494 495 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);496 if (err)497 return err;498 499 if (speed != SPEED_UNFORCED)500 dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);501 else502 dev_dbg(chip->dev, "p%d: Speed unforced\n", port);503 dev_dbg(chip->dev, "p%d: %s %s duplex\n", port,504 reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce",505 reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half");506 507 return 0;508}509 510phy_interface_t mv88e6393x_port_max_speed_mode(struct mv88e6xxx_chip *chip,511 int port)512{513 514 if (port != 0 && port != 9 && port != 10)515 return PHY_INTERFACE_MODE_NA;516 517 if (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361)518 return PHY_INTERFACE_MODE_2500BASEX;519 520 return PHY_INTERFACE_MODE_10GBASER;521}522 523static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,524 phy_interface_t mode, bool force)525{526 u16 cmode;527 u16 reg;528 int err;529 530 /* Default to a slow mode, so freeing up SERDES interfaces for531 * other ports which might use them for SFPs.532 */533 if (mode == PHY_INTERFACE_MODE_NA)534 mode = PHY_INTERFACE_MODE_1000BASEX;535 536 switch (mode) {537 case PHY_INTERFACE_MODE_RMII:538 cmode = MV88E6XXX_PORT_STS_CMODE_RMII;539 break;540 case PHY_INTERFACE_MODE_RGMII:541 case PHY_INTERFACE_MODE_RGMII_ID:542 case PHY_INTERFACE_MODE_RGMII_RXID:543 case PHY_INTERFACE_MODE_RGMII_TXID:544 cmode = MV88E6XXX_PORT_STS_CMODE_RGMII;545 break;546 case PHY_INTERFACE_MODE_1000BASEX:547 cmode = MV88E6XXX_PORT_STS_CMODE_1000BASEX;548 break;549 case PHY_INTERFACE_MODE_SGMII:550 cmode = MV88E6XXX_PORT_STS_CMODE_SGMII;551 break;552 case PHY_INTERFACE_MODE_2500BASEX:553 cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;554 break;555 case PHY_INTERFACE_MODE_5GBASER:556 cmode = MV88E6393X_PORT_STS_CMODE_5GBASER;557 break;558 case PHY_INTERFACE_MODE_XGMII:559 case PHY_INTERFACE_MODE_XAUI:560 cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;561 break;562 case PHY_INTERFACE_MODE_RXAUI:563 cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI;564 break;565 case PHY_INTERFACE_MODE_10GBASER:566 cmode = MV88E6393X_PORT_STS_CMODE_10GBASER;567 break;568 case PHY_INTERFACE_MODE_USXGMII:569 cmode = MV88E6393X_PORT_STS_CMODE_USXGMII;570 break;571 default:572 cmode = 0;573 }574 575 /* cmode doesn't change, nothing to do for us unless forced */576 if (cmode == chip->ports[port].cmode && !force)577 return 0;578 579 chip->ports[port].cmode = 0;580 581 if (cmode) {582 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®);583 if (err)584 return err;585 586 reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK;587 reg |= cmode;588 589 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);590 if (err)591 return err;592 593 chip->ports[port].cmode = cmode;594 }595 596 return 0;597}598 599int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,600 phy_interface_t mode)601{602 if (port != 9 && port != 10)603 return -EOPNOTSUPP;604 605 return mv88e6xxx_port_set_cmode(chip, port, mode, false);606}607 608int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,609 phy_interface_t mode)610{611 if (port != 9 && port != 10)612 return -EOPNOTSUPP;613 614 switch (mode) {615 case PHY_INTERFACE_MODE_NA:616 return 0;617 case PHY_INTERFACE_MODE_XGMII:618 case PHY_INTERFACE_MODE_XAUI:619 case PHY_INTERFACE_MODE_RXAUI:620 return -EINVAL;621 default:622 break;623 }624 625 return mv88e6xxx_port_set_cmode(chip, port, mode, false);626}627 628int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,629 phy_interface_t mode)630{631 int err;632 u16 reg;633 634 if (port != 0 && port != 9 && port != 10)635 return -EOPNOTSUPP;636 637 if (port == 9 || port == 10) {638 switch (mode) {639 case PHY_INTERFACE_MODE_RMII:640 case PHY_INTERFACE_MODE_RGMII:641 case PHY_INTERFACE_MODE_RGMII_ID:642 case PHY_INTERFACE_MODE_RGMII_RXID:643 case PHY_INTERFACE_MODE_RGMII_TXID:644 return -EINVAL;645 default:646 break;647 }648 }649 650 /* mv88e6393x errata 4.5: EEE should be disabled on SERDES ports */651 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®);652 if (err)653 return err;654 655 reg &= ~MV88E6XXX_PORT_MAC_CTL_EEE;656 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_EEE;657 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);658 if (err)659 return err;660 661 return mv88e6xxx_port_set_cmode(chip, port, mode, false);662}663 664static int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip,665 int port)666{667 int err, addr;668 u16 reg, bits;669 670 if (port != 5)671 return -EOPNOTSUPP;672 673 addr = chip->info->port_base_addr + port;674 675 err = mv88e6xxx_port_hidden_read(chip, 0x7, addr, 0, ®);676 if (err)677 return err;678 679 bits = MV88E6341_PORT_RESERVED_1A_FORCE_CMODE |680 MV88E6341_PORT_RESERVED_1A_SGMII_AN;681 682 if ((reg & bits) == bits)683 return 0;684 685 reg |= bits;686 return mv88e6xxx_port_hidden_write(chip, 0x7, addr, 0, reg);687}688 689int mv88e6341_port_set_cmode(struct mv88e6xxx_chip *chip, int port,690 phy_interface_t mode)691{692 int err;693 694 if (port != 5)695 return -EOPNOTSUPP;696 697 switch (mode) {698 case PHY_INTERFACE_MODE_NA:699 return 0;700 case PHY_INTERFACE_MODE_XGMII:701 case PHY_INTERFACE_MODE_XAUI:702 case PHY_INTERFACE_MODE_RXAUI:703 return -EINVAL;704 default:705 break;706 }707 708 err = mv88e6341_port_set_cmode_writable(chip, port);709 if (err)710 return err;711 712 return mv88e6xxx_port_set_cmode(chip, port, mode, true);713}714 715int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)716{717 int err;718 u16 reg;719 720 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®);721 if (err)722 return err;723 724 *cmode = reg & MV88E6185_PORT_STS_CMODE_MASK;725 726 return 0;727}728 729int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)730{731 int err;732 u16 reg;733 734 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®);735 if (err)736 return err;737 738 *cmode = reg & MV88E6XXX_PORT_STS_CMODE_MASK;739 740 return 0;741}742 743/* Offset 0x02: Jamming Control744 *745 * Do not limit the period of time that this port can be paused for by746 * the remote end or the period of time that this port can pause the747 * remote end.748 */749int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,750 u8 out)751{752 return mv88e6xxx_port_write(chip, port, MV88E6097_PORT_JAM_CTL,753 out << 8 | in);754}755 756int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,757 u8 out)758{759 int err;760 761 err = mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,762 MV88E6390_PORT_FLOW_CTL_UPDATE |763 MV88E6390_PORT_FLOW_CTL_LIMIT_IN | in);764 if (err)765 return err;766 767 return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,768 MV88E6390_PORT_FLOW_CTL_UPDATE |769 MV88E6390_PORT_FLOW_CTL_LIMIT_OUT | out);770}771 772/* Offset 0x04: Port Control Register */773 774static const char * const mv88e6xxx_port_state_names[] = {775 [MV88E6XXX_PORT_CTL0_STATE_DISABLED] = "Disabled",776 [MV88E6XXX_PORT_CTL0_STATE_BLOCKING] = "Blocking/Listening",777 [MV88E6XXX_PORT_CTL0_STATE_LEARNING] = "Learning",778 [MV88E6XXX_PORT_CTL0_STATE_FORWARDING] = "Forwarding",779};780 781int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state)782{783 u16 reg;784 int err;785 786 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);787 if (err)788 return err;789 790 reg &= ~MV88E6XXX_PORT_CTL0_STATE_MASK;791 792 switch (state) {793 case BR_STATE_DISABLED:794 state = MV88E6XXX_PORT_CTL0_STATE_DISABLED;795 break;796 case BR_STATE_BLOCKING:797 case BR_STATE_LISTENING:798 state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING;799 break;800 case BR_STATE_LEARNING:801 state = MV88E6XXX_PORT_CTL0_STATE_LEARNING;802 break;803 case BR_STATE_FORWARDING:804 state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING;805 break;806 default:807 return -EINVAL;808 }809 810 reg |= state;811 812 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);813 if (err)814 return err;815 816 dev_dbg(chip->dev, "p%d: PortState set to %s\n", port,817 mv88e6xxx_port_state_names[state]);818 819 return 0;820}821 822int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port,823 enum mv88e6xxx_egress_mode mode)824{825 int err;826 u16 reg;827 828 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);829 if (err)830 return err;831 832 reg &= ~MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK;833 834 switch (mode) {835 case MV88E6XXX_EGRESS_MODE_UNMODIFIED:836 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED;837 break;838 case MV88E6XXX_EGRESS_MODE_UNTAGGED:839 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED;840 break;841 case MV88E6XXX_EGRESS_MODE_TAGGED:842 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED;843 break;844 case MV88E6XXX_EGRESS_MODE_ETHERTYPE:845 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA;846 break;847 default:848 return -EINVAL;849 }850 851 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);852}853 854int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,855 enum mv88e6xxx_frame_mode mode)856{857 int err;858 u16 reg;859 860 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);861 if (err)862 return err;863 864 reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;865 866 switch (mode) {867 case MV88E6XXX_FRAME_MODE_NORMAL:868 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;869 break;870 case MV88E6XXX_FRAME_MODE_DSA:871 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;872 break;873 default:874 return -EINVAL;875 }876 877 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);878}879 880int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,881 enum mv88e6xxx_frame_mode mode)882{883 int err;884 u16 reg;885 886 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);887 if (err)888 return err;889 890 reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;891 892 switch (mode) {893 case MV88E6XXX_FRAME_MODE_NORMAL:894 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;895 break;896 case MV88E6XXX_FRAME_MODE_DSA:897 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;898 break;899 case MV88E6XXX_FRAME_MODE_PROVIDER:900 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_PROVIDER;901 break;902 case MV88E6XXX_FRAME_MODE_ETHERTYPE:903 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_ETHER_TYPE_DSA;904 break;905 default:906 return -EINVAL;907 }908 909 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);910}911 912int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip,913 int port, bool unicast)914{915 int err;916 u16 reg;917 918 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);919 if (err)920 return err;921 922 if (unicast)923 reg |= MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;924 else925 reg &= ~MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;926 927 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);928}929 930int mv88e6352_port_set_ucast_flood(struct mv88e6xxx_chip *chip, int port,931 bool unicast)932{933 int err;934 u16 reg;935 936 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);937 if (err)938 return err;939 940 if (unicast)941 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_UC;942 else943 reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_UC;944 945 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);946}947 948int mv88e6352_port_set_mcast_flood(struct mv88e6xxx_chip *chip, int port,949 bool multicast)950{951 int err;952 u16 reg;953 954 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);955 if (err)956 return err;957 958 if (multicast)959 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_MC;960 else961 reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MC;962 963 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);964}965 966/* Offset 0x05: Port Control 1 */967 968int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,969 bool message_port)970{971 u16 val;972 int err;973 974 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val);975 if (err)976 return err;977 978 if (message_port)979 val |= MV88E6XXX_PORT_CTL1_MESSAGE_PORT;980 else981 val &= ~MV88E6XXX_PORT_CTL1_MESSAGE_PORT;982 983 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val);984}985 986int mv88e6xxx_port_set_trunk(struct mv88e6xxx_chip *chip, int port,987 bool trunk, u8 id)988{989 u16 val;990 int err;991 992 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val);993 if (err)994 return err;995 996 val &= ~MV88E6XXX_PORT_CTL1_TRUNK_ID_MASK;997 998 if (trunk)999 val |= MV88E6XXX_PORT_CTL1_TRUNK_PORT |1000 (id << MV88E6XXX_PORT_CTL1_TRUNK_ID_SHIFT);1001 else1002 val &= ~MV88E6XXX_PORT_CTL1_TRUNK_PORT;1003 1004 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val);1005}1006 1007/* Offset 0x06: Port Based VLAN Map */1008 1009int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map)1010{1011 const u16 mask = mv88e6xxx_port_mask(chip);1012 u16 reg;1013 int err;1014 1015 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®);1016 if (err)1017 return err;1018 1019 reg &= ~mask;1020 reg |= map & mask;1021 1022 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);1023 if (err)1024 return err;1025 1026 dev_dbg(chip->dev, "p%d: VLANTable set to %.3x\n", port, map);1027 1028 return 0;1029}1030 1031int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid)1032{1033 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;1034 u16 reg;1035 int err;1036 1037 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */1038 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®);1039 if (err)1040 return err;1041 1042 *fid = (reg & 0xf000) >> 12;1043 1044 /* Port's default FID upper bits are located in reg 0x05, offset 0 */1045 if (upper_mask) {1046 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,1047 ®);1048 if (err)1049 return err;1050 1051 *fid |= (reg & upper_mask) << 4;1052 }1053 1054 return 0;1055}1056 1057int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid)1058{1059 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;1060 u16 reg;1061 int err;1062 1063 if (fid >= mv88e6xxx_num_databases(chip))1064 return -EINVAL;1065 1066 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */1067 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®);1068 if (err)1069 return err;1070 1071 reg &= 0x0fff;1072 reg |= (fid & 0x000f) << 12;1073 1074 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);1075 if (err)1076 return err;1077 1078 /* Port's default FID upper bits are located in reg 0x05, offset 0 */1079 if (upper_mask) {1080 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,1081 ®);1082 if (err)1083 return err;1084 1085 reg &= ~upper_mask;1086 reg |= (fid >> 4) & upper_mask;1087 1088 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1,1089 reg);1090 if (err)1091 return err;1092 }1093 1094 dev_dbg(chip->dev, "p%d: FID set to %u\n", port, fid);1095 1096 return 0;1097}1098 1099/* Offset 0x07: Default Port VLAN ID & Priority */1100 1101int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid)1102{1103 u16 reg;1104 int err;1105 1106 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,1107 ®);1108 if (err)1109 return err;1110 1111 *pvid = reg & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;1112 1113 return 0;1114}1115 1116int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid)1117{1118 u16 reg;1119 int err;1120 1121 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,1122 ®);1123 if (err)1124 return err;1125 1126 reg &= ~MV88E6XXX_PORT_DEFAULT_VLAN_MASK;1127 reg |= pvid & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;1128 1129 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,1130 reg);1131 if (err)1132 return err;1133 1134 dev_dbg(chip->dev, "p%d: DefaultVID set to %u\n", port, pvid);1135 1136 return 0;1137}1138 1139/* Offset 0x08: Port Control 2 Register */1140 1141static const char * const mv88e6xxx_port_8021q_mode_names[] = {1142 [MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED] = "Disabled",1143 [MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK] = "Fallback",1144 [MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK] = "Check",1145 [MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure",1146};1147 1148int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip,1149 int port, bool multicast)1150{1151 int err;1152 u16 reg;1153 1154 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®);1155 if (err)1156 return err;1157 1158 if (multicast)1159 reg |= MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;1160 else1161 reg &= ~MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;1162 1163 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);1164}1165 1166int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,1167 int upstream_port)1168{1169 int err;1170 u16 reg;1171 1172 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®);1173 if (err)1174 return err;1175 1176 reg &= ~MV88E6095_PORT_CTL2_CPU_PORT_MASK;1177 reg |= upstream_port;1178 1179 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);1180}1181 1182int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,1183 enum mv88e6xxx_egress_direction direction,1184 bool mirror)1185{1186 bool *mirror_port;1187 u16 reg;1188 u16 bit;1189 int err;1190 1191 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®);1192 if (err)1193 return err;1194 1195 switch (direction) {1196 case MV88E6XXX_EGRESS_DIR_INGRESS:1197 bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR;1198 mirror_port = &chip->ports[port].mirror_ingress;1199 break;1200 case MV88E6XXX_EGRESS_DIR_EGRESS:1201 bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR;1202 mirror_port = &chip->ports[port].mirror_egress;1203 break;1204 default:1205 return -EINVAL;1206 }1207 1208 reg &= ~bit;1209 if (mirror)1210 reg |= bit;1211 1212 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);1213 if (!err)1214 *mirror_port = mirror;1215 1216 return err;1217}1218 1219int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,1220 bool locked)1221{1222 u16 reg;1223 int err;1224 1225 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);1226 if (err)1227 return err;1228 1229 reg &= ~MV88E6XXX_PORT_CTL0_SA_FILT_MASK;1230 if (locked)1231 reg |= MV88E6XXX_PORT_CTL0_SA_FILT_DROP_ON_LOCK;1232 1233 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);1234 if (err)1235 return err;1236 1237 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, ®);1238 if (err)1239 return err;1240 1241 reg &= ~MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;1242 if (locked)1243 reg |= MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;1244 1245 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, reg);1246}1247 1248int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,1249 u16 mode)1250{1251 u16 reg;1252 int err;1253 1254 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®);1255 if (err)1256 return err;1257 1258 reg &= ~MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;1259 reg |= mode & MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;1260 1261 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);1262 if (err)1263 return err;1264 1265 dev_dbg(chip->dev, "p%d: 802.1QMode set to %s\n", port,1266 mv88e6xxx_port_8021q_mode_names[mode]);1267 1268 return 0;1269}1270 1271int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,1272 bool drop_untagged)1273{1274 u16 old, new;1275 int err;1276 1277 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &old);1278 if (err)1279 return err;1280 1281 if (drop_untagged)1282 new = old | MV88E6XXX_PORT_CTL2_DISCARD_UNTAGGED;1283 else1284 new = old & ~MV88E6XXX_PORT_CTL2_DISCARD_UNTAGGED;1285 1286 if (new == old)1287 return 0;1288 1289 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, new);1290}1291 1292int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port, bool map)1293{1294 u16 reg;1295 int err;1296 1297 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®);1298 if (err)1299 return err;1300 1301 if (map)1302 reg |= MV88E6XXX_PORT_CTL2_MAP_DA;1303 else1304 reg &= ~MV88E6XXX_PORT_CTL2_MAP_DA;1305 1306 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);1307}1308 1309int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,1310 size_t size)1311{1312 u16 reg;1313 int err;1314 1315 size += VLAN_ETH_HLEN + ETH_FCS_LEN;1316 1317 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®);1318 if (err)1319 return err;1320 1321 reg &= ~MV88E6XXX_PORT_CTL2_JUMBO_MODE_MASK;1322 1323 if (size <= 1522)1324 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_1522;1325 else if (size <= 2048)1326 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_2048;1327 else if (size <= 10240)1328 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_10240;1329 else1330 return -ERANGE;1331 1332 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);1333}1334 1335/* Offset 0x09: Port Rate Control */1336 1337int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)1338{1339 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,1340 0x0000);1341}1342 1343int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)1344{1345 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,1346 0x0001);1347}1348 1349/* Offset 0x0B: Port Association Vector */1350 1351int mv88e6xxx_port_set_assoc_vector(struct mv88e6xxx_chip *chip, int port,1352 u16 pav)1353{1354 u16 reg, mask;1355 int err;1356 1357 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,1358 ®);1359 if (err)1360 return err;1361 1362 mask = mv88e6xxx_port_mask(chip);1363 reg &= ~mask;1364 reg |= pav & mask;1365 1366 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,1367 reg);1368}1369 1370/* Offset 0x0C: Port ATU Control */1371 1372int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port)1373{1374 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ATU_CTL, 0);1375}1376 1377/* Offset 0x0D: (Priority) Override Register */1378 1379int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port)1380{1381 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0);1382}1383 1384/* Offset 0x0E: Policy & MGMT Control Register for FAMILY 6191X 6193X 6393X */1385 1386static int mv88e6393x_port_policy_read(struct mv88e6xxx_chip *chip, int port,1387 u16 pointer, u8 *data)1388{1389 u16 reg;1390 int err;1391 1392 err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL,1393 pointer);1394 if (err)1395 return err;1396 1397 err = mv88e6xxx_port_read(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL,1398 ®);1399 if (err)1400 return err;1401 1402 *data = reg;1403 1404 return 0;1405}1406 1407static int mv88e6393x_port_policy_write(struct mv88e6xxx_chip *chip, int port,1408 u16 pointer, u8 data)1409{1410 u16 reg;1411 1412 reg = MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE | pointer | data;1413 1414 return mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL,1415 reg);1416}1417 1418static int mv88e6393x_port_policy_write_all(struct mv88e6xxx_chip *chip,1419 u16 pointer, u8 data)1420{1421 int err, port;1422 1423 for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {1424 if (dsa_is_unused_port(chip->ds, port))1425 continue;1426 1427 err = mv88e6393x_port_policy_write(chip, port, pointer, data);1428 if (err)1429 return err;1430 }1431 1432 return 0;1433}1434 1435int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip,1436 enum mv88e6xxx_egress_direction direction,1437 int port)1438{1439 u16 ptr;1440 int err;1441 1442 switch (direction) {1443 case MV88E6XXX_EGRESS_DIR_INGRESS:1444 ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_INGRESS_DEST;1445 err = mv88e6393x_port_policy_write_all(chip, ptr, port);1446 if (err)1447 return err;1448 break;1449 case MV88E6XXX_EGRESS_DIR_EGRESS:1450 ptr = MV88E6393X_G2_EGRESS_MONITOR_DEST;1451 err = mv88e6xxx_g2_write(chip, ptr, port);1452 if (err)1453 return err;1454 break;1455 }1456 1457 return 0;1458}1459 1460int mv88e6393x_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,1461 int upstream_port)1462{1463 u16 ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_CPU_DEST;1464 u8 data = MV88E6393X_PORT_POLICY_MGMT_CTL_CPU_DEST_MGMTPRI |1465 upstream_port;1466 1467 return mv88e6393x_port_policy_write(chip, port, ptr, data);1468}1469 1470int mv88e6393x_port_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)1471{1472 u16 ptr;1473 int err;1474 1475 /* Consider the frames with reserved multicast destination1476 * addresses matching 01:80:c2:00:00:00 and1477 * 01:80:c2:00:00:02 as MGMT.1478 */1479 ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XLO;1480 err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);1481 if (err)1482 return err;1483 1484 ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XHI;1485 err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);1486 if (err)1487 return err;1488 1489 ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XLO;1490 err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);1491 if (err)1492 return err;1493 1494 ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XHI;1495 err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);1496 if (err)1497 return err;1498 1499 return 0;1500}1501 1502/* Offset 0x10 & 0x11: EPC */1503 1504static int mv88e6393x_port_epc_wait_ready(struct mv88e6xxx_chip *chip, int port)1505{1506 int bit = __bf_shf(MV88E6393X_PORT_EPC_CMD_BUSY);1507 1508 return mv88e6xxx_port_wait_bit(chip, port, MV88E6393X_PORT_EPC_CMD, bit, 0);1509}1510 1511/* Port Ether type for 6393X family */1512 1513int mv88e6393x_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,1514 u16 etype)1515{1516 u16 val;1517 int err;1518 1519 err = mv88e6393x_port_epc_wait_ready(chip, port);1520 if (err)1521 return err;1522 1523 err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_DATA, etype);1524 if (err)1525 return err;1526 1527 val = MV88E6393X_PORT_EPC_CMD_BUSY |1528 MV88E6393X_PORT_EPC_CMD_WRITE |1529 MV88E6393X_PORT_EPC_INDEX_PORT_ETYPE;1530 1531 return mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_CMD, val);1532}1533 1534/* Offset 0x0f: Port Ether type */1535 1536int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,1537 u16 etype)1538{1539 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype);1540}1541 1542/* Offset 0x18: Port IEEE Priority Remapping Registers [0-3]1543 * Offset 0x19: Port IEEE Priority Remapping Registers [4-7]1544 */1545 1546int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port)1547{1548 int err;1549 1550 /* Use a direct priority mapping for all IEEE tagged frames */1551 err = mv88e6xxx_port_write(chip, port,1552 MV88E6095_PORT_IEEE_PRIO_REMAP_0123,1553 0x3210);1554 if (err)1555 return err;1556 1557 return mv88e6xxx_port_write(chip, port,1558 MV88E6095_PORT_IEEE_PRIO_REMAP_4567,1559 0x7654);1560}1561 1562static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip,1563 int port, u16 table, u8 ptr, u16 data)1564{1565 u16 reg;1566 1567 reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE | table |1568 (ptr << __bf_shf(MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_PTR_MASK)) |1569 (data & MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_DATA_MASK);1570 1571 return mv88e6xxx_port_write(chip, port,1572 MV88E6390_PORT_IEEE_PRIO_MAP_TABLE, reg);1573}1574 1575int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port)1576{1577 int err, i;1578 u16 table;1579 1580 for (i = 0; i <= 7; i++) {1581 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP;1582 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i,1583 (i | i << 4));1584 if (err)1585 return err;1586 1587 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP;1588 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);1589 if (err)1590 return err;1591 1592 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP;1593 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);1594 if (err)1595 return err;1596 1597 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP;1598 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);1599 if (err)1600 return err;1601 }1602 1603 return 0;1604}1605 1606/* Offset 0x0E: Policy Control Register */1607 1608static int1609mv88e6xxx_port_policy_mapping_get_pos(enum mv88e6xxx_policy_mapping mapping,1610 enum mv88e6xxx_policy_action action,1611 u16 *mask, u16 *val, int *shift)1612{1613 switch (mapping) {1614 case MV88E6XXX_POLICY_MAPPING_DA:1615 *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_DA_MASK);1616 *mask = MV88E6XXX_PORT_POLICY_CTL_DA_MASK;1617 break;1618 case MV88E6XXX_POLICY_MAPPING_SA:1619 *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_SA_MASK);1620 *mask = MV88E6XXX_PORT_POLICY_CTL_SA_MASK;1621 break;1622 case MV88E6XXX_POLICY_MAPPING_VTU:1623 *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VTU_MASK);1624 *mask = MV88E6XXX_PORT_POLICY_CTL_VTU_MASK;1625 break;1626 case MV88E6XXX_POLICY_MAPPING_ETYPE:1627 *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK);1628 *mask = MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK;1629 break;1630 case MV88E6XXX_POLICY_MAPPING_PPPOE:1631 *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK);1632 *mask = MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK;1633 break;1634 case MV88E6XXX_POLICY_MAPPING_VBAS:1635 *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK);1636 *mask = MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK;1637 break;1638 case MV88E6XXX_POLICY_MAPPING_OPT82:1639 *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK);1640 *mask = MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK;1641 break;1642 case MV88E6XXX_POLICY_MAPPING_UDP:1643 *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_UDP_MASK);1644 *mask = MV88E6XXX_PORT_POLICY_CTL_UDP_MASK;1645 break;1646 default:1647 return -EOPNOTSUPP;1648 }1649 1650 switch (action) {1651 case MV88E6XXX_POLICY_ACTION_NORMAL:1652 *val = MV88E6XXX_PORT_POLICY_CTL_NORMAL;1653 break;1654 case MV88E6XXX_POLICY_ACTION_MIRROR:1655 *val = MV88E6XXX_PORT_POLICY_CTL_MIRROR;1656 break;1657 case MV88E6XXX_POLICY_ACTION_TRAP:1658 *val = MV88E6XXX_PORT_POLICY_CTL_TRAP;1659 break;1660 case MV88E6XXX_POLICY_ACTION_DISCARD:1661 *val = MV88E6XXX_PORT_POLICY_CTL_DISCARD;1662 break;1663 default:1664 return -EOPNOTSUPP;1665 }1666 1667 return 0;1668}1669 1670int mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port,1671 enum mv88e6xxx_policy_mapping mapping,1672 enum mv88e6xxx_policy_action action)1673{1674 u16 reg, mask, val;1675 int shift;1676 int err;1677 1678 err = mv88e6xxx_port_policy_mapping_get_pos(mapping, action, &mask,1679 &val, &shift);1680 if (err)1681 return err;1682 1683 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_POLICY_CTL, ®);1684 if (err)1685 return err;1686 1687 reg &= ~mask;1688 reg |= (val << shift) & mask;1689 1690 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_POLICY_CTL, reg);1691}1692 1693int mv88e6393x_port_set_policy(struct mv88e6xxx_chip *chip, int port,1694 enum mv88e6xxx_policy_mapping mapping,1695 enum mv88e6xxx_policy_action action)1696{1697 u16 mask, val;1698 int shift;1699 int err;1700 u16 ptr;1701 u8 reg;1702 1703 err = mv88e6xxx_port_policy_mapping_get_pos(mapping, action, &mask,1704 &val, &shift);1705 if (err)1706 return err;1707 1708 /* The 16-bit Port Policy CTL register from older chips is on 6393x1709 * changed to Port Policy MGMT CTL, which can access more data, but1710 * indirectly. The original 16-bit value is divided into two 8-bit1711 * registers.1712 */1713 ptr = shift / 8;1714 shift %= 8;1715 mask >>= ptr * 8;1716 ptr <<= 8;1717 1718 err = mv88e6393x_port_policy_read(chip, port, ptr, ®);1719 if (err)1720 return err;1721 1722 reg &= ~mask;1723 reg |= (val << shift) & mask;1724 1725 return mv88e6393x_port_policy_write(chip, port, ptr, reg);1726}1727