12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 218abed21SVivien Didelot /* 318abed21SVivien Didelot * Marvell 88E6xxx Switch Port Registers support 418abed21SVivien Didelot * 518abed21SVivien Didelot * Copyright (c) 2008 Marvell Semiconductor 618abed21SVivien Didelot * 74333d619SVivien Didelot * Copyright (c) 2016-2017 Savoir-faire Linux Inc. 84333d619SVivien Didelot * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 918abed21SVivien Didelot */ 1018abed21SVivien Didelot 11ddcbabf4SVivien Didelot #include <linux/bitfield.h> 12f894c29cSVivien Didelot #include <linux/if_bridge.h> 13f39908d3SAndrew Lunn #include <linux/phy.h> 14c9a2356fSRussell King #include <linux/phylink.h> 154d5f2ba7SVivien Didelot 164d5f2ba7SVivien Didelot #include "chip.h" 1718abed21SVivien Didelot #include "port.h" 18364e9d77SAndrew Lunn #include "serdes.h" 1918abed21SVivien Didelot 2018abed21SVivien Didelot int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, 2118abed21SVivien Didelot u16 *val) 2218abed21SVivien Didelot { 2318abed21SVivien Didelot int addr = chip->info->port_base_addr + port; 2418abed21SVivien Didelot 2518abed21SVivien Didelot return mv88e6xxx_read(chip, addr, reg, val); 2618abed21SVivien Didelot } 2718abed21SVivien Didelot 2818abed21SVivien Didelot int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg, 2918abed21SVivien Didelot u16 val) 3018abed21SVivien Didelot { 3118abed21SVivien Didelot int addr = chip->info->port_base_addr + port; 3218abed21SVivien Didelot 3318abed21SVivien Didelot return mv88e6xxx_write(chip, addr, reg, val); 3418abed21SVivien Didelot } 35e28def33SVivien Didelot 3654186b91SAndrew Lunn /* Offset 0x00: MAC (or PCS or Physical) Status Register 3754186b91SAndrew Lunn * 3854186b91SAndrew Lunn * For most devices, this is read only. However the 6185 has the MyPause 3954186b91SAndrew Lunn * bit read/write. 4054186b91SAndrew Lunn */ 4154186b91SAndrew Lunn int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port, 4254186b91SAndrew Lunn int pause) 4354186b91SAndrew Lunn { 4454186b91SAndrew Lunn u16 reg; 4554186b91SAndrew Lunn int err; 4654186b91SAndrew Lunn 4754186b91SAndrew Lunn err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 4854186b91SAndrew Lunn if (err) 4954186b91SAndrew Lunn return err; 5054186b91SAndrew Lunn 5154186b91SAndrew Lunn if (pause) 5254186b91SAndrew Lunn reg |= MV88E6XXX_PORT_STS_MY_PAUSE; 5354186b91SAndrew Lunn else 5454186b91SAndrew Lunn reg &= ~MV88E6XXX_PORT_STS_MY_PAUSE; 5554186b91SAndrew Lunn 5654186b91SAndrew Lunn return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg); 5754186b91SAndrew Lunn } 5854186b91SAndrew Lunn 5908ef7f10SVivien Didelot /* Offset 0x01: MAC (or PCS or Physical) Control Register 6008ef7f10SVivien Didelot * 6108ef7f10SVivien Didelot * Link, Duplex and Flow Control have one force bit, one value bit. 6296a2b40cSVivien Didelot * 6396a2b40cSVivien Didelot * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value. 6496a2b40cSVivien Didelot * Alternative values require the 200BASE (or AltSpeed) bit 12 set. 6596a2b40cSVivien Didelot * Newer chips need a ForcedSpd bit 13 set to consider the value. 6608ef7f10SVivien Didelot */ 6708ef7f10SVivien Didelot 68a0a0f622SVivien Didelot static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, 69a0a0f622SVivien Didelot phy_interface_t mode) 70a0a0f622SVivien Didelot { 71a0a0f622SVivien Didelot u16 reg; 72a0a0f622SVivien Didelot int err; 73a0a0f622SVivien Didelot 745ee55577SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); 75a0a0f622SVivien Didelot if (err) 76a0a0f622SVivien Didelot return err; 77a0a0f622SVivien Didelot 785ee55577SVivien Didelot reg &= ~(MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK | 795ee55577SVivien Didelot MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK); 80a0a0f622SVivien Didelot 81a0a0f622SVivien Didelot switch (mode) { 82a0a0f622SVivien Didelot case PHY_INTERFACE_MODE_RGMII_RXID: 835ee55577SVivien Didelot reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK; 84a0a0f622SVivien Didelot break; 85a0a0f622SVivien Didelot case PHY_INTERFACE_MODE_RGMII_TXID: 865ee55577SVivien Didelot reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK; 87a0a0f622SVivien Didelot break; 88a0a0f622SVivien Didelot case PHY_INTERFACE_MODE_RGMII_ID: 895ee55577SVivien Didelot reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK | 905ee55577SVivien Didelot MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK; 91a0a0f622SVivien Didelot break; 92fedf1865SAndrew Lunn case PHY_INTERFACE_MODE_RGMII: 93a0a0f622SVivien Didelot break; 94fedf1865SAndrew Lunn default: 95fedf1865SAndrew Lunn return 0; 96a0a0f622SVivien Didelot } 97a0a0f622SVivien Didelot 985ee55577SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); 99a0a0f622SVivien Didelot if (err) 100a0a0f622SVivien Didelot return err; 101a0a0f622SVivien Didelot 102774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: delay RXCLK %s, TXCLK %s\n", port, 1035ee55577SVivien Didelot reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK ? "yes" : "no", 1045ee55577SVivien Didelot reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK ? "yes" : "no"); 105a0a0f622SVivien Didelot 106a0a0f622SVivien Didelot return 0; 107a0a0f622SVivien Didelot } 108a0a0f622SVivien Didelot 109a0a0f622SVivien Didelot int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, 110a0a0f622SVivien Didelot phy_interface_t mode) 111a0a0f622SVivien Didelot { 112a0a0f622SVivien Didelot if (port < 5) 113a0a0f622SVivien Didelot return -EOPNOTSUPP; 114a0a0f622SVivien Didelot 115a0a0f622SVivien Didelot return mv88e6xxx_port_set_rgmii_delay(chip, port, mode); 116a0a0f622SVivien Didelot } 117a0a0f622SVivien Didelot 118a0a0f622SVivien Didelot int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, 119a0a0f622SVivien Didelot phy_interface_t mode) 120a0a0f622SVivien Didelot { 121a0a0f622SVivien Didelot if (port != 0) 122a0a0f622SVivien Didelot return -EOPNOTSUPP; 123a0a0f622SVivien Didelot 124a0a0f622SVivien Didelot return mv88e6xxx_port_set_rgmii_delay(chip, port, mode); 125a0a0f622SVivien Didelot } 126a0a0f622SVivien Didelot 12708ef7f10SVivien Didelot int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link) 12808ef7f10SVivien Didelot { 12908ef7f10SVivien Didelot u16 reg; 13008ef7f10SVivien Didelot int err; 13108ef7f10SVivien Didelot 1325ee55577SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); 13308ef7f10SVivien Didelot if (err) 13408ef7f10SVivien Didelot return err; 13508ef7f10SVivien Didelot 1365ee55577SVivien Didelot reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_LINK | 1375ee55577SVivien Didelot MV88E6XXX_PORT_MAC_CTL_LINK_UP); 13808ef7f10SVivien Didelot 13908ef7f10SVivien Didelot switch (link) { 14008ef7f10SVivien Didelot case LINK_FORCED_DOWN: 1415ee55577SVivien Didelot reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK; 14208ef7f10SVivien Didelot break; 14308ef7f10SVivien Didelot case LINK_FORCED_UP: 1445ee55577SVivien Didelot reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK | 1455ee55577SVivien Didelot MV88E6XXX_PORT_MAC_CTL_LINK_UP; 14608ef7f10SVivien Didelot break; 14708ef7f10SVivien Didelot case LINK_UNFORCED: 14808ef7f10SVivien Didelot /* normal link detection */ 14908ef7f10SVivien Didelot break; 15008ef7f10SVivien Didelot default: 15108ef7f10SVivien Didelot return -EINVAL; 15208ef7f10SVivien Didelot } 15308ef7f10SVivien Didelot 1545ee55577SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); 15508ef7f10SVivien Didelot if (err) 15608ef7f10SVivien Didelot return err; 15708ef7f10SVivien Didelot 158774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: %s link %s\n", port, 1595ee55577SVivien Didelot reg & MV88E6XXX_PORT_MAC_CTL_FORCE_LINK ? "Force" : "Unforce", 1605ee55577SVivien Didelot reg & MV88E6XXX_PORT_MAC_CTL_LINK_UP ? "up" : "down"); 16108ef7f10SVivien Didelot 16208ef7f10SVivien Didelot return 0; 16308ef7f10SVivien Didelot } 16408ef7f10SVivien Didelot 1657f1ae07bSVivien Didelot int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup) 1667f1ae07bSVivien Didelot { 1677f1ae07bSVivien Didelot u16 reg; 1687f1ae07bSVivien Didelot int err; 1697f1ae07bSVivien Didelot 1705ee55577SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); 1717f1ae07bSVivien Didelot if (err) 1727f1ae07bSVivien Didelot return err; 1737f1ae07bSVivien Didelot 1745ee55577SVivien Didelot reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX | 1755ee55577SVivien Didelot MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL); 1767f1ae07bSVivien Didelot 1777f1ae07bSVivien Didelot switch (dup) { 1787f1ae07bSVivien Didelot case DUPLEX_HALF: 1795ee55577SVivien Didelot reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX; 1807f1ae07bSVivien Didelot break; 1817f1ae07bSVivien Didelot case DUPLEX_FULL: 1825ee55577SVivien Didelot reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX | 1835ee55577SVivien Didelot MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL; 1847f1ae07bSVivien Didelot break; 1857f1ae07bSVivien Didelot case DUPLEX_UNFORCED: 1867f1ae07bSVivien Didelot /* normal duplex detection */ 1877f1ae07bSVivien Didelot break; 1887f1ae07bSVivien Didelot default: 189c6195a8bSHeiner Kallweit return -EOPNOTSUPP; 1907f1ae07bSVivien Didelot } 1917f1ae07bSVivien Didelot 1925ee55577SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); 1937f1ae07bSVivien Didelot if (err) 1947f1ae07bSVivien Didelot return err; 1957f1ae07bSVivien Didelot 196774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: %s %s duplex\n", port, 1975ee55577SVivien Didelot reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce", 1985ee55577SVivien Didelot reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half"); 1997f1ae07bSVivien Didelot 2007f1ae07bSVivien Didelot return 0; 2017f1ae07bSVivien Didelot } 2027f1ae07bSVivien Didelot 20396a2b40cSVivien Didelot static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port, 20496a2b40cSVivien Didelot int speed, bool alt_bit, bool force_bit) 20596a2b40cSVivien Didelot { 20696a2b40cSVivien Didelot u16 reg, ctrl; 20796a2b40cSVivien Didelot int err; 20896a2b40cSVivien Didelot 20996a2b40cSVivien Didelot switch (speed) { 21096a2b40cSVivien Didelot case 10: 2115ee55577SVivien Didelot ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10; 21296a2b40cSVivien Didelot break; 21396a2b40cSVivien Didelot case 100: 2145ee55577SVivien Didelot ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100; 21596a2b40cSVivien Didelot break; 21696a2b40cSVivien Didelot case 200: 21796a2b40cSVivien Didelot if (alt_bit) 2185ee55577SVivien Didelot ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 | 2195ee55577SVivien Didelot MV88E6390_PORT_MAC_CTL_ALTSPEED; 22096a2b40cSVivien Didelot else 2215ee55577SVivien Didelot ctrl = MV88E6065_PORT_MAC_CTL_SPEED_200; 22296a2b40cSVivien Didelot break; 22396a2b40cSVivien Didelot case 1000: 2245ee55577SVivien Didelot ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000; 22596a2b40cSVivien Didelot break; 22696a2b40cSVivien Didelot case 2500: 22726422340SMarek Behún if (alt_bit) 2285ee55577SVivien Didelot ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 | 2295ee55577SVivien Didelot MV88E6390_PORT_MAC_CTL_ALTSPEED; 23026422340SMarek Behún else 23126422340SMarek Behún ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000; 23296a2b40cSVivien Didelot break; 23396a2b40cSVivien Didelot case 10000: 23496a2b40cSVivien Didelot /* all bits set, fall through... */ 23596a2b40cSVivien Didelot case SPEED_UNFORCED: 2365ee55577SVivien Didelot ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED; 23796a2b40cSVivien Didelot break; 23896a2b40cSVivien Didelot default: 23996a2b40cSVivien Didelot return -EOPNOTSUPP; 24096a2b40cSVivien Didelot } 24196a2b40cSVivien Didelot 2425ee55577SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); 24396a2b40cSVivien Didelot if (err) 24496a2b40cSVivien Didelot return err; 24596a2b40cSVivien Didelot 2465ee55577SVivien Didelot reg &= ~MV88E6XXX_PORT_MAC_CTL_SPEED_MASK; 24796a2b40cSVivien Didelot if (alt_bit) 2485ee55577SVivien Didelot reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED; 24996a2b40cSVivien Didelot if (force_bit) { 2505ee55577SVivien Didelot reg &= ~MV88E6390_PORT_MAC_CTL_FORCE_SPEED; 2510b6e3d03SAndrew Lunn if (speed != SPEED_UNFORCED) 2525ee55577SVivien Didelot ctrl |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED; 25396a2b40cSVivien Didelot } 25496a2b40cSVivien Didelot reg |= ctrl; 25596a2b40cSVivien Didelot 2565ee55577SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); 25796a2b40cSVivien Didelot if (err) 25896a2b40cSVivien Didelot return err; 25996a2b40cSVivien Didelot 26096a2b40cSVivien Didelot if (speed) 261774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed); 26296a2b40cSVivien Didelot else 263774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: Speed unforced\n", port); 26496a2b40cSVivien Didelot 26596a2b40cSVivien Didelot return 0; 26696a2b40cSVivien Didelot } 26796a2b40cSVivien Didelot 26896a2b40cSVivien Didelot /* Support 10, 100, 200 Mbps (e.g. 88E6065 family) */ 26996a2b40cSVivien Didelot int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 27096a2b40cSVivien Didelot { 27196a2b40cSVivien Didelot if (speed == SPEED_MAX) 27296a2b40cSVivien Didelot speed = 200; 27396a2b40cSVivien Didelot 27496a2b40cSVivien Didelot if (speed > 200) 27596a2b40cSVivien Didelot return -EOPNOTSUPP; 27696a2b40cSVivien Didelot 27796a2b40cSVivien Didelot /* Setting 200 Mbps on port 0 to 3 selects 100 Mbps */ 27896a2b40cSVivien Didelot return mv88e6xxx_port_set_speed(chip, port, speed, false, false); 27996a2b40cSVivien Didelot } 28096a2b40cSVivien Didelot 28196a2b40cSVivien Didelot /* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */ 28296a2b40cSVivien Didelot int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 28396a2b40cSVivien Didelot { 28496a2b40cSVivien Didelot if (speed == SPEED_MAX) 28596a2b40cSVivien Didelot speed = 1000; 28696a2b40cSVivien Didelot 28796a2b40cSVivien Didelot if (speed == 200 || speed > 1000) 28896a2b40cSVivien Didelot return -EOPNOTSUPP; 28996a2b40cSVivien Didelot 29096a2b40cSVivien Didelot return mv88e6xxx_port_set_speed(chip, port, speed, false, false); 29196a2b40cSVivien Didelot } 29296a2b40cSVivien Didelot 293a528e5beSRasmus Villemoes /* Support 10, 100 Mbps (e.g. 88E6250 family) */ 294a528e5beSRasmus Villemoes int mv88e6250_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 295a528e5beSRasmus Villemoes { 296a528e5beSRasmus Villemoes if (speed == SPEED_MAX) 297a528e5beSRasmus Villemoes speed = 100; 298a528e5beSRasmus Villemoes 299a528e5beSRasmus Villemoes if (speed > 100) 300a528e5beSRasmus Villemoes return -EOPNOTSUPP; 301a528e5beSRasmus Villemoes 302a528e5beSRasmus Villemoes return mv88e6xxx_port_set_speed(chip, port, speed, false, false); 303a528e5beSRasmus Villemoes } 304a528e5beSRasmus Villemoes 30526422340SMarek Behún /* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6341) */ 30626422340SMarek Behún int mv88e6341_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 30726422340SMarek Behún { 30826422340SMarek Behún if (speed == SPEED_MAX) 30926422340SMarek Behún speed = port < 5 ? 1000 : 2500; 31026422340SMarek Behún 31126422340SMarek Behún if (speed > 2500) 31226422340SMarek Behún return -EOPNOTSUPP; 31326422340SMarek Behún 31426422340SMarek Behún if (speed == 200 && port != 0) 31526422340SMarek Behún return -EOPNOTSUPP; 31626422340SMarek Behún 31726422340SMarek Behún if (speed == 2500 && port < 5) 31826422340SMarek Behún return -EOPNOTSUPP; 31926422340SMarek Behún 32026422340SMarek Behún return mv88e6xxx_port_set_speed(chip, port, speed, !port, true); 32126422340SMarek Behún } 32226422340SMarek Behún 3237cbbee05SAndrew Lunn phy_interface_t mv88e6341_port_max_speed_mode(int port) 3247cbbee05SAndrew Lunn { 3257cbbee05SAndrew Lunn if (port == 5) 3267cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_2500BASEX; 3277cbbee05SAndrew Lunn 3287cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_NA; 3297cbbee05SAndrew Lunn } 3307cbbee05SAndrew Lunn 33196a2b40cSVivien Didelot /* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */ 33296a2b40cSVivien Didelot int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 33396a2b40cSVivien Didelot { 33496a2b40cSVivien Didelot if (speed == SPEED_MAX) 33596a2b40cSVivien Didelot speed = 1000; 33696a2b40cSVivien Didelot 33796a2b40cSVivien Didelot if (speed > 1000) 33896a2b40cSVivien Didelot return -EOPNOTSUPP; 33996a2b40cSVivien Didelot 34096a2b40cSVivien Didelot if (speed == 200 && port < 5) 34196a2b40cSVivien Didelot return -EOPNOTSUPP; 34296a2b40cSVivien Didelot 34396a2b40cSVivien Didelot return mv88e6xxx_port_set_speed(chip, port, speed, true, false); 34496a2b40cSVivien Didelot } 34596a2b40cSVivien Didelot 34696a2b40cSVivien Didelot /* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */ 34796a2b40cSVivien Didelot int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 34896a2b40cSVivien Didelot { 34996a2b40cSVivien Didelot if (speed == SPEED_MAX) 35096a2b40cSVivien Didelot speed = port < 9 ? 1000 : 2500; 35196a2b40cSVivien Didelot 35296a2b40cSVivien Didelot if (speed > 2500) 35396a2b40cSVivien Didelot return -EOPNOTSUPP; 35496a2b40cSVivien Didelot 35596a2b40cSVivien Didelot if (speed == 200 && port != 0) 35696a2b40cSVivien Didelot return -EOPNOTSUPP; 35796a2b40cSVivien Didelot 35896a2b40cSVivien Didelot if (speed == 2500 && port < 9) 35996a2b40cSVivien Didelot return -EOPNOTSUPP; 36096a2b40cSVivien Didelot 36196a2b40cSVivien Didelot return mv88e6xxx_port_set_speed(chip, port, speed, true, true); 36296a2b40cSVivien Didelot } 36396a2b40cSVivien Didelot 3647cbbee05SAndrew Lunn phy_interface_t mv88e6390_port_max_speed_mode(int port) 3657cbbee05SAndrew Lunn { 3667cbbee05SAndrew Lunn if (port == 9 || port == 10) 3677cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_2500BASEX; 3687cbbee05SAndrew Lunn 3697cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_NA; 3707cbbee05SAndrew Lunn } 3717cbbee05SAndrew Lunn 37296a2b40cSVivien Didelot /* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */ 37396a2b40cSVivien Didelot int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 37496a2b40cSVivien Didelot { 37596a2b40cSVivien Didelot if (speed == SPEED_MAX) 37696a2b40cSVivien Didelot speed = port < 9 ? 1000 : 10000; 37796a2b40cSVivien Didelot 37896a2b40cSVivien Didelot if (speed == 200 && port != 0) 37996a2b40cSVivien Didelot return -EOPNOTSUPP; 38096a2b40cSVivien Didelot 38196a2b40cSVivien Didelot if (speed >= 2500 && port < 9) 38296a2b40cSVivien Didelot return -EOPNOTSUPP; 38396a2b40cSVivien Didelot 38496a2b40cSVivien Didelot return mv88e6xxx_port_set_speed(chip, port, speed, true, true); 38596a2b40cSVivien Didelot } 38696a2b40cSVivien Didelot 3877cbbee05SAndrew Lunn phy_interface_t mv88e6390x_port_max_speed_mode(int port) 3887cbbee05SAndrew Lunn { 3897cbbee05SAndrew Lunn if (port == 9 || port == 10) 3907cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_XAUI; 3917cbbee05SAndrew Lunn 3927cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_NA; 3937cbbee05SAndrew Lunn } 3947cbbee05SAndrew Lunn 3957a3007d2SMarek Behún static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port, 396f39908d3SAndrew Lunn phy_interface_t mode) 397f39908d3SAndrew Lunn { 39817deaf5cSMarek Behún u8 lane; 399f39908d3SAndrew Lunn u16 cmode; 400734447d4SAndrew Lunn u16 reg; 401f39908d3SAndrew Lunn int err; 402f39908d3SAndrew Lunn 403787799a9SAndrew Lunn /* Default to a slow mode, so freeing up SERDES interfaces for 404787799a9SAndrew Lunn * other ports which might use them for SFPs. 405787799a9SAndrew Lunn */ 406787799a9SAndrew Lunn if (mode == PHY_INTERFACE_MODE_NA) 407787799a9SAndrew Lunn mode = PHY_INTERFACE_MODE_1000BASEX; 408787799a9SAndrew Lunn 409f39908d3SAndrew Lunn switch (mode) { 410f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_1000BASEX: 4113bbb8867SMarek Behún cmode = MV88E6XXX_PORT_STS_CMODE_1000BASEX; 412f39908d3SAndrew Lunn break; 413f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_SGMII: 4145f83dc93SVivien Didelot cmode = MV88E6XXX_PORT_STS_CMODE_SGMII; 415f39908d3SAndrew Lunn break; 416f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_2500BASEX: 4175f83dc93SVivien Didelot cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX; 418f39908d3SAndrew Lunn break; 419f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_XGMII: 4202e51a8dcSRussell King case PHY_INTERFACE_MODE_XAUI: 4215f83dc93SVivien Didelot cmode = MV88E6XXX_PORT_STS_CMODE_XAUI; 422f39908d3SAndrew Lunn break; 423f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_RXAUI: 4245f83dc93SVivien Didelot cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI; 425f39908d3SAndrew Lunn break; 426f39908d3SAndrew Lunn default: 427f39908d3SAndrew Lunn cmode = 0; 428f39908d3SAndrew Lunn } 429f39908d3SAndrew Lunn 430ed8fe202SHeiner Kallweit /* cmode doesn't change, nothing to do for us */ 431ed8fe202SHeiner Kallweit if (cmode == chip->ports[port].cmode) 432ed8fe202SHeiner Kallweit return 0; 433ed8fe202SHeiner Kallweit 4345122d4ecSVivien Didelot lane = mv88e6xxx_serdes_get_lane(chip, port); 4355122d4ecSVivien Didelot if (lane) { 436734447d4SAndrew Lunn if (chip->ports[port].serdes_irq) { 43761a46b41SVivien Didelot err = mv88e6xxx_serdes_irq_disable(chip, port, lane); 438734447d4SAndrew Lunn if (err) 439734447d4SAndrew Lunn return err; 440734447d4SAndrew Lunn } 441734447d4SAndrew Lunn 442dc272f60SVivien Didelot err = mv88e6xxx_serdes_power_down(chip, port, lane); 443364e9d77SAndrew Lunn if (err) 444364e9d77SAndrew Lunn return err; 4455ceaeb99SHeiner Kallweit } 4465ceaeb99SHeiner Kallweit 4475ceaeb99SHeiner Kallweit chip->ports[port].cmode = 0; 448364e9d77SAndrew Lunn 449f39908d3SAndrew Lunn if (cmode) { 4505f83dc93SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 451f39908d3SAndrew Lunn if (err) 452f39908d3SAndrew Lunn return err; 453f39908d3SAndrew Lunn 4545f83dc93SVivien Didelot reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK; 455f39908d3SAndrew Lunn reg |= cmode; 456f39908d3SAndrew Lunn 4575f83dc93SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg); 458f39908d3SAndrew Lunn if (err) 459f39908d3SAndrew Lunn return err; 460364e9d77SAndrew Lunn 4615ceaeb99SHeiner Kallweit chip->ports[port].cmode = cmode; 4625ceaeb99SHeiner Kallweit 4635122d4ecSVivien Didelot lane = mv88e6xxx_serdes_get_lane(chip, port); 4645122d4ecSVivien Didelot if (!lane) 4655122d4ecSVivien Didelot return -ENODEV; 4665ceaeb99SHeiner Kallweit 467dc272f60SVivien Didelot err = mv88e6xxx_serdes_power_up(chip, port, lane); 468364e9d77SAndrew Lunn if (err) 469364e9d77SAndrew Lunn return err; 470734447d4SAndrew Lunn 471734447d4SAndrew Lunn if (chip->ports[port].serdes_irq) { 47261a46b41SVivien Didelot err = mv88e6xxx_serdes_irq_enable(chip, port, lane); 473734447d4SAndrew Lunn if (err) 474734447d4SAndrew Lunn return err; 475734447d4SAndrew Lunn } 476f39908d3SAndrew Lunn } 477f39908d3SAndrew Lunn 478f39908d3SAndrew Lunn return 0; 479f39908d3SAndrew Lunn } 480f39908d3SAndrew Lunn 4817a3007d2SMarek Behún int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, 4827a3007d2SMarek Behún phy_interface_t mode) 4837a3007d2SMarek Behún { 4847a3007d2SMarek Behún if (port != 9 && port != 10) 4857a3007d2SMarek Behún return -EOPNOTSUPP; 4867a3007d2SMarek Behún 4877a3007d2SMarek Behún return mv88e6xxx_port_set_cmode(chip, port, mode); 4887a3007d2SMarek Behún } 4897a3007d2SMarek Behún 490fdc71eeaSAndrew Lunn int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port, 491fdc71eeaSAndrew Lunn phy_interface_t mode) 492fdc71eeaSAndrew Lunn { 4937a3007d2SMarek Behún if (port != 9 && port != 10) 4947a3007d2SMarek Behún return -EOPNOTSUPP; 4957a3007d2SMarek Behún 496fdc71eeaSAndrew Lunn switch (mode) { 49765b034cfSMarek Behún case PHY_INTERFACE_MODE_NA: 49865b034cfSMarek Behún return 0; 499fdc71eeaSAndrew Lunn case PHY_INTERFACE_MODE_XGMII: 500fdc71eeaSAndrew Lunn case PHY_INTERFACE_MODE_XAUI: 501fdc71eeaSAndrew Lunn case PHY_INTERFACE_MODE_RXAUI: 502fdc71eeaSAndrew Lunn return -EINVAL; 503fdc71eeaSAndrew Lunn default: 504fdc71eeaSAndrew Lunn break; 505fdc71eeaSAndrew Lunn } 506fdc71eeaSAndrew Lunn 5077a3007d2SMarek Behún return mv88e6xxx_port_set_cmode(chip, port, mode); 5087a3007d2SMarek Behún } 5097a3007d2SMarek Behún 5105d24da1eSVivien Didelot static int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip, 5115d24da1eSVivien Didelot int port) 5127a3007d2SMarek Behún { 5137a3007d2SMarek Behún int err, addr; 5147a3007d2SMarek Behún u16 reg, bits; 5157a3007d2SMarek Behún 5167a3007d2SMarek Behún if (port != 5) 5177a3007d2SMarek Behún return -EOPNOTSUPP; 5187a3007d2SMarek Behún 5197a3007d2SMarek Behún addr = chip->info->port_base_addr + port; 5207a3007d2SMarek Behún 5217a3007d2SMarek Behún err = mv88e6xxx_port_hidden_read(chip, 0x7, addr, 0, ®); 5227a3007d2SMarek Behún if (err) 5237a3007d2SMarek Behún return err; 5247a3007d2SMarek Behún 5257a3007d2SMarek Behún bits = MV88E6341_PORT_RESERVED_1A_FORCE_CMODE | 5267a3007d2SMarek Behún MV88E6341_PORT_RESERVED_1A_SGMII_AN; 5277a3007d2SMarek Behún 5287a3007d2SMarek Behún if ((reg & bits) == bits) 5297a3007d2SMarek Behún return 0; 5307a3007d2SMarek Behún 5317a3007d2SMarek Behún reg |= bits; 5327a3007d2SMarek Behún return mv88e6xxx_port_hidden_write(chip, 0x7, addr, 0, reg); 5337a3007d2SMarek Behún } 5347a3007d2SMarek Behún 5357a3007d2SMarek Behún int mv88e6341_port_set_cmode(struct mv88e6xxx_chip *chip, int port, 5367a3007d2SMarek Behún phy_interface_t mode) 5377a3007d2SMarek Behún { 5385d24da1eSVivien Didelot int err; 5395d24da1eSVivien Didelot 5407a3007d2SMarek Behún if (port != 5) 5417a3007d2SMarek Behún return -EOPNOTSUPP; 5427a3007d2SMarek Behún 5437a3007d2SMarek Behún switch (mode) { 5447a3007d2SMarek Behún case PHY_INTERFACE_MODE_NA: 5457a3007d2SMarek Behún return 0; 5467a3007d2SMarek Behún case PHY_INTERFACE_MODE_XGMII: 5477a3007d2SMarek Behún case PHY_INTERFACE_MODE_XAUI: 5487a3007d2SMarek Behún case PHY_INTERFACE_MODE_RXAUI: 5497a3007d2SMarek Behún return -EINVAL; 5507a3007d2SMarek Behún default: 5517a3007d2SMarek Behún break; 5527a3007d2SMarek Behún } 5537a3007d2SMarek Behún 5545d24da1eSVivien Didelot err = mv88e6341_port_set_cmode_writable(chip, port); 5555d24da1eSVivien Didelot if (err) 5565d24da1eSVivien Didelot return err; 5575d24da1eSVivien Didelot 5587a3007d2SMarek Behún return mv88e6xxx_port_set_cmode(chip, port, mode); 559fdc71eeaSAndrew Lunn } 560fdc71eeaSAndrew Lunn 5612d2e1dd2SAndrew Lunn int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode) 5626c422e34SRussell King { 5636c422e34SRussell King int err; 5646c422e34SRussell King u16 reg; 5656c422e34SRussell King 5666c422e34SRussell King err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 5676c422e34SRussell King if (err) 5686c422e34SRussell King return err; 5696c422e34SRussell King 5702d2e1dd2SAndrew Lunn *cmode = reg & MV88E6185_PORT_STS_CMODE_MASK; 5712d2e1dd2SAndrew Lunn 5722d2e1dd2SAndrew Lunn return 0; 5736c422e34SRussell King } 5746c422e34SRussell King 5752d2e1dd2SAndrew Lunn int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode) 576f39908d3SAndrew Lunn { 577f39908d3SAndrew Lunn int err; 578f39908d3SAndrew Lunn u16 reg; 579f39908d3SAndrew Lunn 5805f83dc93SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 581f39908d3SAndrew Lunn if (err) 582f39908d3SAndrew Lunn return err; 583f39908d3SAndrew Lunn 5845f83dc93SVivien Didelot *cmode = reg & MV88E6XXX_PORT_STS_CMODE_MASK; 585f39908d3SAndrew Lunn 586f39908d3SAndrew Lunn return 0; 587f39908d3SAndrew Lunn } 588f39908d3SAndrew Lunn 589ce91c453SRasmus Villemoes int mv88e6250_port_link_state(struct mv88e6xxx_chip *chip, int port, 590ce91c453SRasmus Villemoes struct phylink_link_state *state) 591ce91c453SRasmus Villemoes { 592ce91c453SRasmus Villemoes int err; 593ce91c453SRasmus Villemoes u16 reg; 594ce91c453SRasmus Villemoes 595ce91c453SRasmus Villemoes err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 596ce91c453SRasmus Villemoes if (err) 597ce91c453SRasmus Villemoes return err; 598ce91c453SRasmus Villemoes 599ce91c453SRasmus Villemoes if (port < 5) { 600ce91c453SRasmus Villemoes switch (reg & MV88E6250_PORT_STS_PORTMODE_MASK) { 601ce91c453SRasmus Villemoes case MV88E6250_PORT_STS_PORTMODE_PHY_10_HALF: 602ce91c453SRasmus Villemoes state->speed = SPEED_10; 603ce91c453SRasmus Villemoes state->duplex = DUPLEX_HALF; 604ce91c453SRasmus Villemoes break; 605ce91c453SRasmus Villemoes case MV88E6250_PORT_STS_PORTMODE_PHY_100_HALF: 606ce91c453SRasmus Villemoes state->speed = SPEED_100; 607ce91c453SRasmus Villemoes state->duplex = DUPLEX_HALF; 608ce91c453SRasmus Villemoes break; 609ce91c453SRasmus Villemoes case MV88E6250_PORT_STS_PORTMODE_PHY_10_FULL: 610ce91c453SRasmus Villemoes state->speed = SPEED_10; 611ce91c453SRasmus Villemoes state->duplex = DUPLEX_FULL; 612ce91c453SRasmus Villemoes break; 613ce91c453SRasmus Villemoes case MV88E6250_PORT_STS_PORTMODE_PHY_100_FULL: 614ce91c453SRasmus Villemoes state->speed = SPEED_100; 615ce91c453SRasmus Villemoes state->duplex = DUPLEX_FULL; 616ce91c453SRasmus Villemoes break; 617ce91c453SRasmus Villemoes default: 618ce91c453SRasmus Villemoes state->speed = SPEED_UNKNOWN; 619ce91c453SRasmus Villemoes state->duplex = DUPLEX_UNKNOWN; 620ce91c453SRasmus Villemoes break; 621ce91c453SRasmus Villemoes } 622ce91c453SRasmus Villemoes } else { 623ce91c453SRasmus Villemoes switch (reg & MV88E6250_PORT_STS_PORTMODE_MASK) { 624ce91c453SRasmus Villemoes case MV88E6250_PORT_STS_PORTMODE_MII_10_HALF: 625ce91c453SRasmus Villemoes state->speed = SPEED_10; 626ce91c453SRasmus Villemoes state->duplex = DUPLEX_HALF; 627ce91c453SRasmus Villemoes break; 628ce91c453SRasmus Villemoes case MV88E6250_PORT_STS_PORTMODE_MII_100_HALF: 629ce91c453SRasmus Villemoes state->speed = SPEED_100; 630ce91c453SRasmus Villemoes state->duplex = DUPLEX_HALF; 631ce91c453SRasmus Villemoes break; 632ce91c453SRasmus Villemoes case MV88E6250_PORT_STS_PORTMODE_MII_10_FULL: 633ce91c453SRasmus Villemoes state->speed = SPEED_10; 634ce91c453SRasmus Villemoes state->duplex = DUPLEX_FULL; 635ce91c453SRasmus Villemoes break; 636ce91c453SRasmus Villemoes case MV88E6250_PORT_STS_PORTMODE_MII_100_FULL: 637ce91c453SRasmus Villemoes state->speed = SPEED_100; 638ce91c453SRasmus Villemoes state->duplex = DUPLEX_FULL; 639ce91c453SRasmus Villemoes break; 640ce91c453SRasmus Villemoes default: 641ce91c453SRasmus Villemoes state->speed = SPEED_UNKNOWN; 642ce91c453SRasmus Villemoes state->duplex = DUPLEX_UNKNOWN; 643ce91c453SRasmus Villemoes break; 644ce91c453SRasmus Villemoes } 645ce91c453SRasmus Villemoes } 646ce91c453SRasmus Villemoes 647ce91c453SRasmus Villemoes state->link = !!(reg & MV88E6250_PORT_STS_LINK); 648ce91c453SRasmus Villemoes state->an_enabled = 1; 649ce91c453SRasmus Villemoes state->an_complete = state->link; 650927441adSMarek Behún state->interface = PHY_INTERFACE_MODE_NA; 651ce91c453SRasmus Villemoes 652ce91c453SRasmus Villemoes return 0; 653ce91c453SRasmus Villemoes } 654ce91c453SRasmus Villemoes 6556c422e34SRussell King int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port, 656c9a2356fSRussell King struct phylink_link_state *state) 657c9a2356fSRussell King { 658c9a2356fSRussell King int err; 659c9a2356fSRussell King u16 reg; 660c9a2356fSRussell King 661927441adSMarek Behún switch (chip->ports[port].cmode) { 662927441adSMarek Behún case MV88E6XXX_PORT_STS_CMODE_RGMII: 663927441adSMarek Behún err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, 664927441adSMarek Behún ®); 665927441adSMarek Behún if (err) 666927441adSMarek Behún return err; 667927441adSMarek Behún 668927441adSMarek Behún if ((reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK) && 669927441adSMarek Behún (reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK)) 670927441adSMarek Behún state->interface = PHY_INTERFACE_MODE_RGMII_ID; 671927441adSMarek Behún else if (reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK) 672927441adSMarek Behún state->interface = PHY_INTERFACE_MODE_RGMII_RXID; 673927441adSMarek Behún else if (reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK) 674927441adSMarek Behún state->interface = PHY_INTERFACE_MODE_RGMII_TXID; 675927441adSMarek Behún else 676927441adSMarek Behún state->interface = PHY_INTERFACE_MODE_RGMII; 677927441adSMarek Behún break; 6783bbb8867SMarek Behún case MV88E6XXX_PORT_STS_CMODE_1000BASEX: 679927441adSMarek Behún state->interface = PHY_INTERFACE_MODE_1000BASEX; 680927441adSMarek Behún break; 681927441adSMarek Behún case MV88E6XXX_PORT_STS_CMODE_SGMII: 682927441adSMarek Behún state->interface = PHY_INTERFACE_MODE_SGMII; 683927441adSMarek Behún break; 684927441adSMarek Behún case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 685927441adSMarek Behún state->interface = PHY_INTERFACE_MODE_2500BASEX; 686927441adSMarek Behún break; 687927441adSMarek Behún case MV88E6XXX_PORT_STS_CMODE_XAUI: 688927441adSMarek Behún state->interface = PHY_INTERFACE_MODE_XAUI; 689927441adSMarek Behún break; 690927441adSMarek Behún case MV88E6XXX_PORT_STS_CMODE_RXAUI: 691927441adSMarek Behún state->interface = PHY_INTERFACE_MODE_RXAUI; 692927441adSMarek Behún break; 693927441adSMarek Behún default: 694927441adSMarek Behún /* we do not support other cmode values here */ 695927441adSMarek Behún state->interface = PHY_INTERFACE_MODE_NA; 696927441adSMarek Behún } 697927441adSMarek Behún 698c9a2356fSRussell King err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 699c9a2356fSRussell King if (err) 700c9a2356fSRussell King return err; 701c9a2356fSRussell King 702c9a2356fSRussell King switch (reg & MV88E6XXX_PORT_STS_SPEED_MASK) { 703c9a2356fSRussell King case MV88E6XXX_PORT_STS_SPEED_10: 704c9a2356fSRussell King state->speed = SPEED_10; 705c9a2356fSRussell King break; 706c9a2356fSRussell King case MV88E6XXX_PORT_STS_SPEED_100: 707c9a2356fSRussell King state->speed = SPEED_100; 708c9a2356fSRussell King break; 709c9a2356fSRussell King case MV88E6XXX_PORT_STS_SPEED_1000: 710c9a2356fSRussell King state->speed = SPEED_1000; 711c9a2356fSRussell King break; 712c9a2356fSRussell King case MV88E6XXX_PORT_STS_SPEED_10000: 713c9a2356fSRussell King if ((reg & MV88E6XXX_PORT_STS_CMODE_MASK) == 714c9a2356fSRussell King MV88E6XXX_PORT_STS_CMODE_2500BASEX) 715c9a2356fSRussell King state->speed = SPEED_2500; 716c9a2356fSRussell King else 717c9a2356fSRussell King state->speed = SPEED_10000; 718c9a2356fSRussell King break; 719c9a2356fSRussell King } 720c9a2356fSRussell King 721c9a2356fSRussell King state->duplex = reg & MV88E6XXX_PORT_STS_DUPLEX ? 722c9a2356fSRussell King DUPLEX_FULL : DUPLEX_HALF; 723c9a2356fSRussell King state->link = !!(reg & MV88E6XXX_PORT_STS_LINK); 724c9a2356fSRussell King state->an_enabled = 1; 725c9a2356fSRussell King state->an_complete = state->link; 726c9a2356fSRussell King 727c9a2356fSRussell King return 0; 728c9a2356fSRussell King } 729c9a2356fSRussell King 7306c422e34SRussell King int mv88e6185_port_link_state(struct mv88e6xxx_chip *chip, int port, 7316c422e34SRussell King struct phylink_link_state *state) 7326c422e34SRussell King { 7336c422e34SRussell King if (state->interface == PHY_INTERFACE_MODE_1000BASEX) { 7342d2e1dd2SAndrew Lunn u8 cmode = chip->ports[port].cmode; 7356c422e34SRussell King 7366c422e34SRussell King /* When a port is in "Cross-chip serdes" mode, it uses 7376c422e34SRussell King * 1000Base-X full duplex mode, but there is no automatic 7386c422e34SRussell King * link detection. Use the sync OK status for link (as it 7396c422e34SRussell King * would do for 1000Base-X mode.) 7406c422e34SRussell King */ 7416c422e34SRussell King if (cmode == MV88E6185_PORT_STS_CMODE_SERDES) { 7426c422e34SRussell King u16 mac; 7436c422e34SRussell King int err; 7446c422e34SRussell King 7456c422e34SRussell King err = mv88e6xxx_port_read(chip, port, 7466c422e34SRussell King MV88E6XXX_PORT_MAC_CTL, &mac); 7476c422e34SRussell King if (err) 7486c422e34SRussell King return err; 7496c422e34SRussell King 7506c422e34SRussell King state->link = !!(mac & MV88E6185_PORT_MAC_CTL_SYNC_OK); 7516c422e34SRussell King state->an_enabled = 1; 7526c422e34SRussell King state->an_complete = 7536c422e34SRussell King !!(mac & MV88E6185_PORT_MAC_CTL_AN_DONE); 7546c422e34SRussell King state->duplex = 7556c422e34SRussell King state->link ? DUPLEX_FULL : DUPLEX_UNKNOWN; 7566c422e34SRussell King state->speed = 7576c422e34SRussell King state->link ? SPEED_1000 : SPEED_UNKNOWN; 7586c422e34SRussell King 7596c422e34SRussell King return 0; 7606c422e34SRussell King } 7616c422e34SRussell King } 7626c422e34SRussell King 7636c422e34SRussell King return mv88e6352_port_link_state(chip, port, state); 7646c422e34SRussell King } 7656c422e34SRussell King 7666c96bbfdSVivien Didelot /* Offset 0x02: Jamming Control 767b35d322aSAndrew Lunn * 768b35d322aSAndrew Lunn * Do not limit the period of time that this port can be paused for by 769b35d322aSAndrew Lunn * the remote end or the period of time that this port can pause the 770b35d322aSAndrew Lunn * remote end. 771b35d322aSAndrew Lunn */ 7720898432cSVivien Didelot int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, 7730898432cSVivien Didelot u8 out) 774b35d322aSAndrew Lunn { 7756c96bbfdSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6097_PORT_JAM_CTL, 7766c96bbfdSVivien Didelot out << 8 | in); 777b35d322aSAndrew Lunn } 778b35d322aSAndrew Lunn 7790898432cSVivien Didelot int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, 7800898432cSVivien Didelot u8 out) 7813ce0e65eSAndrew Lunn { 7823ce0e65eSAndrew Lunn int err; 7833ce0e65eSAndrew Lunn 7846c96bbfdSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL, 7856c96bbfdSVivien Didelot MV88E6390_PORT_FLOW_CTL_UPDATE | 7866c96bbfdSVivien Didelot MV88E6390_PORT_FLOW_CTL_LIMIT_IN | in); 7873ce0e65eSAndrew Lunn if (err) 7883ce0e65eSAndrew Lunn return err; 7893ce0e65eSAndrew Lunn 7906c96bbfdSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL, 7916c96bbfdSVivien Didelot MV88E6390_PORT_FLOW_CTL_UPDATE | 7926c96bbfdSVivien Didelot MV88E6390_PORT_FLOW_CTL_LIMIT_OUT | out); 7933ce0e65eSAndrew Lunn } 7943ce0e65eSAndrew Lunn 795e28def33SVivien Didelot /* Offset 0x04: Port Control Register */ 796e28def33SVivien Didelot 797e28def33SVivien Didelot static const char * const mv88e6xxx_port_state_names[] = { 798a89b433bSVivien Didelot [MV88E6XXX_PORT_CTL0_STATE_DISABLED] = "Disabled", 799a89b433bSVivien Didelot [MV88E6XXX_PORT_CTL0_STATE_BLOCKING] = "Blocking/Listening", 800a89b433bSVivien Didelot [MV88E6XXX_PORT_CTL0_STATE_LEARNING] = "Learning", 801a89b433bSVivien Didelot [MV88E6XXX_PORT_CTL0_STATE_FORWARDING] = "Forwarding", 802e28def33SVivien Didelot }; 803e28def33SVivien Didelot 804e28def33SVivien Didelot int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state) 805e28def33SVivien Didelot { 806e28def33SVivien Didelot u16 reg; 807e28def33SVivien Didelot int err; 808e28def33SVivien Didelot 809a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 810e28def33SVivien Didelot if (err) 811e28def33SVivien Didelot return err; 812e28def33SVivien Didelot 813a89b433bSVivien Didelot reg &= ~MV88E6XXX_PORT_CTL0_STATE_MASK; 814f894c29cSVivien Didelot 815f894c29cSVivien Didelot switch (state) { 816f894c29cSVivien Didelot case BR_STATE_DISABLED: 817a89b433bSVivien Didelot state = MV88E6XXX_PORT_CTL0_STATE_DISABLED; 818f894c29cSVivien Didelot break; 819f894c29cSVivien Didelot case BR_STATE_BLOCKING: 820f894c29cSVivien Didelot case BR_STATE_LISTENING: 821a89b433bSVivien Didelot state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING; 822f894c29cSVivien Didelot break; 823f894c29cSVivien Didelot case BR_STATE_LEARNING: 824a89b433bSVivien Didelot state = MV88E6XXX_PORT_CTL0_STATE_LEARNING; 825f894c29cSVivien Didelot break; 826f894c29cSVivien Didelot case BR_STATE_FORWARDING: 827a89b433bSVivien Didelot state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 828f894c29cSVivien Didelot break; 829f894c29cSVivien Didelot default: 830f894c29cSVivien Didelot return -EINVAL; 831f894c29cSVivien Didelot } 832f894c29cSVivien Didelot 833e28def33SVivien Didelot reg |= state; 834e28def33SVivien Didelot 835a89b433bSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 836e28def33SVivien Didelot if (err) 837e28def33SVivien Didelot return err; 838e28def33SVivien Didelot 839774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: PortState set to %s\n", port, 840e28def33SVivien Didelot mv88e6xxx_port_state_names[state]); 841e28def33SVivien Didelot 842e28def33SVivien Didelot return 0; 843e28def33SVivien Didelot } 8445a7921f4SVivien Didelot 84556995cbcSAndrew Lunn int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port, 84631bef4e9SVivien Didelot enum mv88e6xxx_egress_mode mode) 84756995cbcSAndrew Lunn { 84856995cbcSAndrew Lunn int err; 84956995cbcSAndrew Lunn u16 reg; 85056995cbcSAndrew Lunn 851a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 85256995cbcSAndrew Lunn if (err) 85356995cbcSAndrew Lunn return err; 85456995cbcSAndrew Lunn 855a89b433bSVivien Didelot reg &= ~MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK; 85631bef4e9SVivien Didelot 85731bef4e9SVivien Didelot switch (mode) { 85831bef4e9SVivien Didelot case MV88E6XXX_EGRESS_MODE_UNMODIFIED: 859a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED; 86031bef4e9SVivien Didelot break; 86131bef4e9SVivien Didelot case MV88E6XXX_EGRESS_MODE_UNTAGGED: 862a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED; 86331bef4e9SVivien Didelot break; 86431bef4e9SVivien Didelot case MV88E6XXX_EGRESS_MODE_TAGGED: 865a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED; 86631bef4e9SVivien Didelot break; 86731bef4e9SVivien Didelot case MV88E6XXX_EGRESS_MODE_ETHERTYPE: 868a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA; 86931bef4e9SVivien Didelot break; 87031bef4e9SVivien Didelot default: 87131bef4e9SVivien Didelot return -EINVAL; 87231bef4e9SVivien Didelot } 87356995cbcSAndrew Lunn 874a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 87556995cbcSAndrew Lunn } 87656995cbcSAndrew Lunn 87756995cbcSAndrew Lunn int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, 87856995cbcSAndrew Lunn enum mv88e6xxx_frame_mode mode) 87956995cbcSAndrew Lunn { 88056995cbcSAndrew Lunn int err; 88156995cbcSAndrew Lunn u16 reg; 88256995cbcSAndrew Lunn 883a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 88456995cbcSAndrew Lunn if (err) 88556995cbcSAndrew Lunn return err; 88656995cbcSAndrew Lunn 887a89b433bSVivien Didelot reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK; 88856995cbcSAndrew Lunn 88956995cbcSAndrew Lunn switch (mode) { 89056995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_NORMAL: 891a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL; 89256995cbcSAndrew Lunn break; 89356995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_DSA: 894a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA; 89556995cbcSAndrew Lunn break; 89656995cbcSAndrew Lunn default: 89756995cbcSAndrew Lunn return -EINVAL; 89856995cbcSAndrew Lunn } 89956995cbcSAndrew Lunn 900a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 90156995cbcSAndrew Lunn } 90256995cbcSAndrew Lunn 90356995cbcSAndrew Lunn int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, 90456995cbcSAndrew Lunn enum mv88e6xxx_frame_mode mode) 90556995cbcSAndrew Lunn { 90656995cbcSAndrew Lunn int err; 90756995cbcSAndrew Lunn u16 reg; 90856995cbcSAndrew Lunn 909a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 91056995cbcSAndrew Lunn if (err) 91156995cbcSAndrew Lunn return err; 91256995cbcSAndrew Lunn 913a89b433bSVivien Didelot reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK; 91456995cbcSAndrew Lunn 91556995cbcSAndrew Lunn switch (mode) { 91656995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_NORMAL: 917a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL; 91856995cbcSAndrew Lunn break; 91956995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_DSA: 920a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA; 92156995cbcSAndrew Lunn break; 92256995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_PROVIDER: 923a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_PROVIDER; 92456995cbcSAndrew Lunn break; 92556995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_ETHERTYPE: 926a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_ETHER_TYPE_DSA; 92756995cbcSAndrew Lunn break; 92856995cbcSAndrew Lunn default: 92956995cbcSAndrew Lunn return -EINVAL; 93056995cbcSAndrew Lunn } 93156995cbcSAndrew Lunn 932a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 93356995cbcSAndrew Lunn } 93456995cbcSAndrew Lunn 935601aeed3SVivien Didelot static int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip, 936601aeed3SVivien Didelot int port, bool unicast) 93756995cbcSAndrew Lunn { 93856995cbcSAndrew Lunn int err; 93956995cbcSAndrew Lunn u16 reg; 94056995cbcSAndrew Lunn 941a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 94256995cbcSAndrew Lunn if (err) 94356995cbcSAndrew Lunn return err; 94456995cbcSAndrew Lunn 945601aeed3SVivien Didelot if (unicast) 946a89b433bSVivien Didelot reg |= MV88E6185_PORT_CTL0_FORWARD_UNKNOWN; 94756995cbcSAndrew Lunn else 948a89b433bSVivien Didelot reg &= ~MV88E6185_PORT_CTL0_FORWARD_UNKNOWN; 94956995cbcSAndrew Lunn 950a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 95156995cbcSAndrew Lunn } 95256995cbcSAndrew Lunn 953601aeed3SVivien Didelot int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, 954601aeed3SVivien Didelot bool unicast, bool multicast) 95556995cbcSAndrew Lunn { 95656995cbcSAndrew Lunn int err; 95756995cbcSAndrew Lunn u16 reg; 95856995cbcSAndrew Lunn 959a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 96056995cbcSAndrew Lunn if (err) 96156995cbcSAndrew Lunn return err; 96256995cbcSAndrew Lunn 963a89b433bSVivien Didelot reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MASK; 964601aeed3SVivien Didelot 965601aeed3SVivien Didelot if (unicast && multicast) 966a89b433bSVivien Didelot reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_ALL_UNKNOWN_DA; 967601aeed3SVivien Didelot else if (unicast) 968a89b433bSVivien Didelot reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_MC_DA; 969601aeed3SVivien Didelot else if (multicast) 970a89b433bSVivien Didelot reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_UC_DA; 97156995cbcSAndrew Lunn else 972a89b433bSVivien Didelot reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_DA; 97356995cbcSAndrew Lunn 974a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 97556995cbcSAndrew Lunn } 97656995cbcSAndrew Lunn 977b4e48c50SVivien Didelot /* Offset 0x05: Port Control 1 */ 978b4e48c50SVivien Didelot 979ea698f4fSVivien Didelot int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port, 980ea698f4fSVivien Didelot bool message_port) 981ea698f4fSVivien Didelot { 982ea698f4fSVivien Didelot u16 val; 983ea698f4fSVivien Didelot int err; 984ea698f4fSVivien Didelot 985cd985bbfSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val); 986ea698f4fSVivien Didelot if (err) 987ea698f4fSVivien Didelot return err; 988ea698f4fSVivien Didelot 989ea698f4fSVivien Didelot if (message_port) 990cd985bbfSVivien Didelot val |= MV88E6XXX_PORT_CTL1_MESSAGE_PORT; 991ea698f4fSVivien Didelot else 992cd985bbfSVivien Didelot val &= ~MV88E6XXX_PORT_CTL1_MESSAGE_PORT; 993ea698f4fSVivien Didelot 994cd985bbfSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val); 995ea698f4fSVivien Didelot } 996ea698f4fSVivien Didelot 9975a7921f4SVivien Didelot /* Offset 0x06: Port Based VLAN Map */ 9985a7921f4SVivien Didelot 9995a7921f4SVivien Didelot int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map) 10005a7921f4SVivien Didelot { 10014d294af2SVivien Didelot const u16 mask = mv88e6xxx_port_mask(chip); 10025a7921f4SVivien Didelot u16 reg; 10035a7921f4SVivien Didelot int err; 10045a7921f4SVivien Didelot 10057e5cc5f1SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®); 10065a7921f4SVivien Didelot if (err) 10075a7921f4SVivien Didelot return err; 10085a7921f4SVivien Didelot 10095a7921f4SVivien Didelot reg &= ~mask; 10105a7921f4SVivien Didelot reg |= map & mask; 10115a7921f4SVivien Didelot 10127e5cc5f1SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg); 10135a7921f4SVivien Didelot if (err) 10145a7921f4SVivien Didelot return err; 10155a7921f4SVivien Didelot 1016774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: VLANTable set to %.3x\n", port, map); 10175a7921f4SVivien Didelot 10185a7921f4SVivien Didelot return 0; 10195a7921f4SVivien Didelot } 1020b4e48c50SVivien Didelot 1021b4e48c50SVivien Didelot int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid) 1022b4e48c50SVivien Didelot { 1023b4e48c50SVivien Didelot const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4; 1024b4e48c50SVivien Didelot u16 reg; 1025b4e48c50SVivien Didelot int err; 1026b4e48c50SVivien Didelot 1027b4e48c50SVivien Didelot /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */ 10287e5cc5f1SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®); 1029b4e48c50SVivien Didelot if (err) 1030b4e48c50SVivien Didelot return err; 1031b4e48c50SVivien Didelot 1032b4e48c50SVivien Didelot *fid = (reg & 0xf000) >> 12; 1033b4e48c50SVivien Didelot 1034b4e48c50SVivien Didelot /* Port's default FID upper bits are located in reg 0x05, offset 0 */ 1035b4e48c50SVivien Didelot if (upper_mask) { 1036cd985bbfSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, 1037cd985bbfSVivien Didelot ®); 1038b4e48c50SVivien Didelot if (err) 1039b4e48c50SVivien Didelot return err; 1040b4e48c50SVivien Didelot 1041b4e48c50SVivien Didelot *fid |= (reg & upper_mask) << 4; 1042b4e48c50SVivien Didelot } 1043b4e48c50SVivien Didelot 1044b4e48c50SVivien Didelot return 0; 1045b4e48c50SVivien Didelot } 1046b4e48c50SVivien Didelot 1047b4e48c50SVivien Didelot int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid) 1048b4e48c50SVivien Didelot { 1049b4e48c50SVivien Didelot const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4; 1050b4e48c50SVivien Didelot u16 reg; 1051b4e48c50SVivien Didelot int err; 1052b4e48c50SVivien Didelot 1053b4e48c50SVivien Didelot if (fid >= mv88e6xxx_num_databases(chip)) 1054b4e48c50SVivien Didelot return -EINVAL; 1055b4e48c50SVivien Didelot 1056b4e48c50SVivien Didelot /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */ 10577e5cc5f1SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®); 1058b4e48c50SVivien Didelot if (err) 1059b4e48c50SVivien Didelot return err; 1060b4e48c50SVivien Didelot 1061b4e48c50SVivien Didelot reg &= 0x0fff; 1062b4e48c50SVivien Didelot reg |= (fid & 0x000f) << 12; 1063b4e48c50SVivien Didelot 10647e5cc5f1SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg); 1065b4e48c50SVivien Didelot if (err) 1066b4e48c50SVivien Didelot return err; 1067b4e48c50SVivien Didelot 1068b4e48c50SVivien Didelot /* Port's default FID upper bits are located in reg 0x05, offset 0 */ 1069b4e48c50SVivien Didelot if (upper_mask) { 1070cd985bbfSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, 1071cd985bbfSVivien Didelot ®); 1072b4e48c50SVivien Didelot if (err) 1073b4e48c50SVivien Didelot return err; 1074b4e48c50SVivien Didelot 1075b4e48c50SVivien Didelot reg &= ~upper_mask; 1076b4e48c50SVivien Didelot reg |= (fid >> 4) & upper_mask; 1077b4e48c50SVivien Didelot 1078cd985bbfSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, 1079cd985bbfSVivien Didelot reg); 1080b4e48c50SVivien Didelot if (err) 1081b4e48c50SVivien Didelot return err; 1082b4e48c50SVivien Didelot } 1083b4e48c50SVivien Didelot 1084774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: FID set to %u\n", port, fid); 1085b4e48c50SVivien Didelot 1086b4e48c50SVivien Didelot return 0; 1087b4e48c50SVivien Didelot } 108877064f37SVivien Didelot 108977064f37SVivien Didelot /* Offset 0x07: Default Port VLAN ID & Priority */ 109077064f37SVivien Didelot 109177064f37SVivien Didelot int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid) 109277064f37SVivien Didelot { 109377064f37SVivien Didelot u16 reg; 109477064f37SVivien Didelot int err; 109577064f37SVivien Didelot 1096b7929fb3SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 1097b7929fb3SVivien Didelot ®); 109877064f37SVivien Didelot if (err) 109977064f37SVivien Didelot return err; 110077064f37SVivien Didelot 1101b7929fb3SVivien Didelot *pvid = reg & MV88E6XXX_PORT_DEFAULT_VLAN_MASK; 110277064f37SVivien Didelot 110377064f37SVivien Didelot return 0; 110477064f37SVivien Didelot } 110577064f37SVivien Didelot 110677064f37SVivien Didelot int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid) 110777064f37SVivien Didelot { 110877064f37SVivien Didelot u16 reg; 110977064f37SVivien Didelot int err; 111077064f37SVivien Didelot 1111b7929fb3SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 1112b7929fb3SVivien Didelot ®); 111377064f37SVivien Didelot if (err) 111477064f37SVivien Didelot return err; 111577064f37SVivien Didelot 1116b7929fb3SVivien Didelot reg &= ~MV88E6XXX_PORT_DEFAULT_VLAN_MASK; 1117b7929fb3SVivien Didelot reg |= pvid & MV88E6XXX_PORT_DEFAULT_VLAN_MASK; 111877064f37SVivien Didelot 1119b7929fb3SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 1120b7929fb3SVivien Didelot reg); 112177064f37SVivien Didelot if (err) 112277064f37SVivien Didelot return err; 112377064f37SVivien Didelot 1124774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: DefaultVID set to %u\n", port, pvid); 112577064f37SVivien Didelot 112677064f37SVivien Didelot return 0; 112777064f37SVivien Didelot } 1128385a0995SVivien Didelot 1129385a0995SVivien Didelot /* Offset 0x08: Port Control 2 Register */ 1130385a0995SVivien Didelot 1131385a0995SVivien Didelot static const char * const mv88e6xxx_port_8021q_mode_names[] = { 113281c6edb2SVivien Didelot [MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED] = "Disabled", 113381c6edb2SVivien Didelot [MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK] = "Fallback", 113481c6edb2SVivien Didelot [MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK] = "Check", 113581c6edb2SVivien Didelot [MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure", 1136385a0995SVivien Didelot }; 1137385a0995SVivien Didelot 1138601aeed3SVivien Didelot static int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip, 1139601aeed3SVivien Didelot int port, bool multicast) 1140a23b2961SAndrew Lunn { 1141a23b2961SAndrew Lunn int err; 1142a23b2961SAndrew Lunn u16 reg; 1143a23b2961SAndrew Lunn 114481c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 1145a23b2961SAndrew Lunn if (err) 1146a23b2961SAndrew Lunn return err; 1147a23b2961SAndrew Lunn 1148601aeed3SVivien Didelot if (multicast) 114981c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD; 1150a23b2961SAndrew Lunn else 115181c6edb2SVivien Didelot reg &= ~MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD; 1152a23b2961SAndrew Lunn 115381c6edb2SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 1154a23b2961SAndrew Lunn } 1155a23b2961SAndrew Lunn 1156601aeed3SVivien Didelot int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, 1157601aeed3SVivien Didelot bool unicast, bool multicast) 1158601aeed3SVivien Didelot { 1159601aeed3SVivien Didelot int err; 1160601aeed3SVivien Didelot 1161601aeed3SVivien Didelot err = mv88e6185_port_set_forward_unknown(chip, port, unicast); 1162601aeed3SVivien Didelot if (err) 1163601aeed3SVivien Didelot return err; 1164601aeed3SVivien Didelot 1165601aeed3SVivien Didelot return mv88e6185_port_set_default_forward(chip, port, multicast); 1166601aeed3SVivien Didelot } 1167601aeed3SVivien Didelot 1168a23b2961SAndrew Lunn int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port, 1169a23b2961SAndrew Lunn int upstream_port) 1170a23b2961SAndrew Lunn { 1171a23b2961SAndrew Lunn int err; 1172a23b2961SAndrew Lunn u16 reg; 1173a23b2961SAndrew Lunn 117481c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 1175a23b2961SAndrew Lunn if (err) 1176a23b2961SAndrew Lunn return err; 1177a23b2961SAndrew Lunn 117881c6edb2SVivien Didelot reg &= ~MV88E6095_PORT_CTL2_CPU_PORT_MASK; 1179a23b2961SAndrew Lunn reg |= upstream_port; 1180a23b2961SAndrew Lunn 118181c6edb2SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 1182a23b2961SAndrew Lunn } 1183a23b2961SAndrew Lunn 1184*f0942e00SIwan R Timmer int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port, 1185*f0942e00SIwan R Timmer enum mv88e6xxx_egress_direction direction, 1186*f0942e00SIwan R Timmer bool mirror) 1187*f0942e00SIwan R Timmer { 1188*f0942e00SIwan R Timmer bool *mirror_port; 1189*f0942e00SIwan R Timmer u16 reg; 1190*f0942e00SIwan R Timmer u16 bit; 1191*f0942e00SIwan R Timmer int err; 1192*f0942e00SIwan R Timmer 1193*f0942e00SIwan R Timmer err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 1194*f0942e00SIwan R Timmer if (err) 1195*f0942e00SIwan R Timmer return err; 1196*f0942e00SIwan R Timmer 1197*f0942e00SIwan R Timmer switch (direction) { 1198*f0942e00SIwan R Timmer case MV88E6XXX_EGRESS_DIR_INGRESS: 1199*f0942e00SIwan R Timmer bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR; 1200*f0942e00SIwan R Timmer mirror_port = &chip->ports[port].mirror_ingress; 1201*f0942e00SIwan R Timmer break; 1202*f0942e00SIwan R Timmer case MV88E6XXX_EGRESS_DIR_EGRESS: 1203*f0942e00SIwan R Timmer bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR; 1204*f0942e00SIwan R Timmer mirror_port = &chip->ports[port].mirror_egress; 1205*f0942e00SIwan R Timmer break; 1206*f0942e00SIwan R Timmer default: 1207*f0942e00SIwan R Timmer return -EINVAL; 1208*f0942e00SIwan R Timmer } 1209*f0942e00SIwan R Timmer 1210*f0942e00SIwan R Timmer reg &= ~bit; 1211*f0942e00SIwan R Timmer if (mirror) 1212*f0942e00SIwan R Timmer reg |= bit; 1213*f0942e00SIwan R Timmer 1214*f0942e00SIwan R Timmer err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 1215*f0942e00SIwan R Timmer if (!err) 1216*f0942e00SIwan R Timmer *mirror_port = mirror; 1217*f0942e00SIwan R Timmer 1218*f0942e00SIwan R Timmer return err; 1219*f0942e00SIwan R Timmer } 1220*f0942e00SIwan R Timmer 1221385a0995SVivien Didelot int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port, 1222385a0995SVivien Didelot u16 mode) 1223385a0995SVivien Didelot { 1224385a0995SVivien Didelot u16 reg; 1225385a0995SVivien Didelot int err; 1226385a0995SVivien Didelot 122781c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 1228385a0995SVivien Didelot if (err) 1229385a0995SVivien Didelot return err; 1230385a0995SVivien Didelot 123181c6edb2SVivien Didelot reg &= ~MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK; 123281c6edb2SVivien Didelot reg |= mode & MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK; 1233385a0995SVivien Didelot 123481c6edb2SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 1235385a0995SVivien Didelot if (err) 1236385a0995SVivien Didelot return err; 1237385a0995SVivien Didelot 1238774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: 802.1QMode set to %s\n", port, 1239385a0995SVivien Didelot mv88e6xxx_port_8021q_mode_names[mode]); 1240385a0995SVivien Didelot 1241385a0995SVivien Didelot return 0; 1242385a0995SVivien Didelot } 1243ef0a7318SAndrew Lunn 1244a23b2961SAndrew Lunn int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port) 1245a23b2961SAndrew Lunn { 1246a23b2961SAndrew Lunn u16 reg; 1247a23b2961SAndrew Lunn int err; 1248a23b2961SAndrew Lunn 124981c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 1250a23b2961SAndrew Lunn if (err) 1251a23b2961SAndrew Lunn return err; 1252a23b2961SAndrew Lunn 125381c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_MAP_DA; 1254a23b2961SAndrew Lunn 125581c6edb2SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 1256a23b2961SAndrew Lunn } 1257a23b2961SAndrew Lunn 1258cd782656SVivien Didelot int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port, 1259cd782656SVivien Didelot size_t size) 12605f436666SAndrew Lunn { 12615f436666SAndrew Lunn u16 reg; 12625f436666SAndrew Lunn int err; 12635f436666SAndrew Lunn 126481c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 12655f436666SAndrew Lunn if (err) 12665f436666SAndrew Lunn return err; 12675f436666SAndrew Lunn 126881c6edb2SVivien Didelot reg &= ~MV88E6XXX_PORT_CTL2_JUMBO_MODE_MASK; 1269cd782656SVivien Didelot 1270cd782656SVivien Didelot if (size <= 1522) 127181c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_1522; 1272cd782656SVivien Didelot else if (size <= 2048) 127381c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_2048; 1274cd782656SVivien Didelot else if (size <= 10240) 127581c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_10240; 1276cd782656SVivien Didelot else 1277cd782656SVivien Didelot return -ERANGE; 12785f436666SAndrew Lunn 127981c6edb2SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 12805f436666SAndrew Lunn } 12815f436666SAndrew Lunn 1282ef70b111SAndrew Lunn /* Offset 0x09: Port Rate Control */ 1283ef70b111SAndrew Lunn 1284ef70b111SAndrew Lunn int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port) 1285ef70b111SAndrew Lunn { 12862cb8cb14SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1, 12872cb8cb14SVivien Didelot 0x0000); 1288ef70b111SAndrew Lunn } 1289ef70b111SAndrew Lunn 1290ef70b111SAndrew Lunn int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port) 1291ef70b111SAndrew Lunn { 12922cb8cb14SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1, 12932cb8cb14SVivien Didelot 0x0001); 1294ef70b111SAndrew Lunn } 1295ef70b111SAndrew Lunn 1296c8c94891SVivien Didelot /* Offset 0x0C: Port ATU Control */ 1297c8c94891SVivien Didelot 1298c8c94891SVivien Didelot int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port) 1299c8c94891SVivien Didelot { 1300b8109594SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ATU_CTL, 0); 1301c8c94891SVivien Didelot } 1302c8c94891SVivien Didelot 13039dbfb4e1SVivien Didelot /* Offset 0x0D: (Priority) Override Register */ 13049dbfb4e1SVivien Didelot 13059dbfb4e1SVivien Didelot int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port) 13069dbfb4e1SVivien Didelot { 1307b8109594SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0); 13089dbfb4e1SVivien Didelot } 13099dbfb4e1SVivien Didelot 131056995cbcSAndrew Lunn /* Offset 0x0f: Port Ether type */ 131156995cbcSAndrew Lunn 131256995cbcSAndrew Lunn int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port, 131356995cbcSAndrew Lunn u16 etype) 131456995cbcSAndrew Lunn { 1315b8109594SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype); 131656995cbcSAndrew Lunn } 131756995cbcSAndrew Lunn 1318ef0a7318SAndrew Lunn /* Offset 0x18: Port IEEE Priority Remapping Registers [0-3] 1319ef0a7318SAndrew Lunn * Offset 0x19: Port IEEE Priority Remapping Registers [4-7] 1320ef0a7318SAndrew Lunn */ 1321ef0a7318SAndrew Lunn 1322ef0a7318SAndrew Lunn int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port) 1323ef0a7318SAndrew Lunn { 1324ef0a7318SAndrew Lunn int err; 1325ef0a7318SAndrew Lunn 1326ef0a7318SAndrew Lunn /* Use a direct priority mapping for all IEEE tagged frames */ 13278009df9eSVivien Didelot err = mv88e6xxx_port_write(chip, port, 13288009df9eSVivien Didelot MV88E6095_PORT_IEEE_PRIO_REMAP_0123, 13298009df9eSVivien Didelot 0x3210); 1330ef0a7318SAndrew Lunn if (err) 1331ef0a7318SAndrew Lunn return err; 1332ef0a7318SAndrew Lunn 13338009df9eSVivien Didelot return mv88e6xxx_port_write(chip, port, 13348009df9eSVivien Didelot MV88E6095_PORT_IEEE_PRIO_REMAP_4567, 13358009df9eSVivien Didelot 0x7654); 1336ef0a7318SAndrew Lunn } 1337ef0a7318SAndrew Lunn 1338ef0a7318SAndrew Lunn static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip, 1339ddcbabf4SVivien Didelot int port, u16 table, u8 ptr, u16 data) 1340ef0a7318SAndrew Lunn { 1341ef0a7318SAndrew Lunn u16 reg; 1342ef0a7318SAndrew Lunn 1343ddcbabf4SVivien Didelot reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE | table | 1344ddcbabf4SVivien Didelot (ptr << __bf_shf(MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_PTR_MASK)) | 1345ddcbabf4SVivien Didelot (data & MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_DATA_MASK); 1346ef0a7318SAndrew Lunn 13478009df9eSVivien Didelot return mv88e6xxx_port_write(chip, port, 13488009df9eSVivien Didelot MV88E6390_PORT_IEEE_PRIO_MAP_TABLE, reg); 1349ef0a7318SAndrew Lunn } 1350ef0a7318SAndrew Lunn 1351ef0a7318SAndrew Lunn int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port) 1352ef0a7318SAndrew Lunn { 1353ef0a7318SAndrew Lunn int err, i; 13548009df9eSVivien Didelot u16 table; 1355ef0a7318SAndrew Lunn 1356ef0a7318SAndrew Lunn for (i = 0; i <= 7; i++) { 13578009df9eSVivien Didelot table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP; 13588009df9eSVivien Didelot err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, 13598009df9eSVivien Didelot (i | i << 4)); 1360ef0a7318SAndrew Lunn if (err) 1361ef0a7318SAndrew Lunn return err; 1362ef0a7318SAndrew Lunn 13638009df9eSVivien Didelot table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP; 13648009df9eSVivien Didelot err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); 1365ef0a7318SAndrew Lunn if (err) 1366ef0a7318SAndrew Lunn return err; 1367ef0a7318SAndrew Lunn 13688009df9eSVivien Didelot table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP; 13698009df9eSVivien Didelot err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); 1370ef0a7318SAndrew Lunn if (err) 1371ef0a7318SAndrew Lunn return err; 1372ef0a7318SAndrew Lunn 13738009df9eSVivien Didelot table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP; 13748009df9eSVivien Didelot err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); 1375ef0a7318SAndrew Lunn if (err) 1376ef0a7318SAndrew Lunn return err; 1377ef0a7318SAndrew Lunn } 1378ef0a7318SAndrew Lunn 1379ef0a7318SAndrew Lunn return 0; 1380ef0a7318SAndrew Lunn } 1381f3a2cd32SVivien Didelot 1382f3a2cd32SVivien Didelot /* Offset 0x0E: Policy Control Register */ 1383f3a2cd32SVivien Didelot 1384f3a2cd32SVivien Didelot int mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port, 1385f3a2cd32SVivien Didelot enum mv88e6xxx_policy_mapping mapping, 1386f3a2cd32SVivien Didelot enum mv88e6xxx_policy_action action) 1387f3a2cd32SVivien Didelot { 1388f3a2cd32SVivien Didelot u16 reg, mask, val; 1389f3a2cd32SVivien Didelot int shift; 1390f3a2cd32SVivien Didelot int err; 1391f3a2cd32SVivien Didelot 1392f3a2cd32SVivien Didelot switch (mapping) { 1393f3a2cd32SVivien Didelot case MV88E6XXX_POLICY_MAPPING_DA: 1394f3a2cd32SVivien Didelot shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_DA_MASK); 1395f3a2cd32SVivien Didelot mask = MV88E6XXX_PORT_POLICY_CTL_DA_MASK; 1396f3a2cd32SVivien Didelot break; 1397f3a2cd32SVivien Didelot case MV88E6XXX_POLICY_MAPPING_SA: 1398f3a2cd32SVivien Didelot shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_SA_MASK); 1399f3a2cd32SVivien Didelot mask = MV88E6XXX_PORT_POLICY_CTL_SA_MASK; 1400f3a2cd32SVivien Didelot break; 1401f3a2cd32SVivien Didelot case MV88E6XXX_POLICY_MAPPING_VTU: 1402f3a2cd32SVivien Didelot shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VTU_MASK); 1403f3a2cd32SVivien Didelot mask = MV88E6XXX_PORT_POLICY_CTL_VTU_MASK; 1404f3a2cd32SVivien Didelot break; 1405f3a2cd32SVivien Didelot case MV88E6XXX_POLICY_MAPPING_ETYPE: 1406f3a2cd32SVivien Didelot shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK); 1407f3a2cd32SVivien Didelot mask = MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK; 1408f3a2cd32SVivien Didelot break; 1409f3a2cd32SVivien Didelot case MV88E6XXX_POLICY_MAPPING_PPPOE: 1410f3a2cd32SVivien Didelot shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK); 1411f3a2cd32SVivien Didelot mask = MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK; 1412f3a2cd32SVivien Didelot break; 1413f3a2cd32SVivien Didelot case MV88E6XXX_POLICY_MAPPING_VBAS: 1414f3a2cd32SVivien Didelot shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK); 1415f3a2cd32SVivien Didelot mask = MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK; 1416f3a2cd32SVivien Didelot break; 1417f3a2cd32SVivien Didelot case MV88E6XXX_POLICY_MAPPING_OPT82: 1418f3a2cd32SVivien Didelot shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK); 1419f3a2cd32SVivien Didelot mask = MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK; 1420f3a2cd32SVivien Didelot break; 1421f3a2cd32SVivien Didelot case MV88E6XXX_POLICY_MAPPING_UDP: 1422f3a2cd32SVivien Didelot shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_UDP_MASK); 1423f3a2cd32SVivien Didelot mask = MV88E6XXX_PORT_POLICY_CTL_UDP_MASK; 1424f3a2cd32SVivien Didelot break; 1425f3a2cd32SVivien Didelot default: 1426f3a2cd32SVivien Didelot return -EOPNOTSUPP; 1427f3a2cd32SVivien Didelot } 1428f3a2cd32SVivien Didelot 1429f3a2cd32SVivien Didelot switch (action) { 1430f3a2cd32SVivien Didelot case MV88E6XXX_POLICY_ACTION_NORMAL: 1431f3a2cd32SVivien Didelot val = MV88E6XXX_PORT_POLICY_CTL_NORMAL; 1432f3a2cd32SVivien Didelot break; 1433f3a2cd32SVivien Didelot case MV88E6XXX_POLICY_ACTION_MIRROR: 1434f3a2cd32SVivien Didelot val = MV88E6XXX_PORT_POLICY_CTL_MIRROR; 1435f3a2cd32SVivien Didelot break; 1436f3a2cd32SVivien Didelot case MV88E6XXX_POLICY_ACTION_TRAP: 1437f3a2cd32SVivien Didelot val = MV88E6XXX_PORT_POLICY_CTL_TRAP; 1438f3a2cd32SVivien Didelot break; 1439f3a2cd32SVivien Didelot case MV88E6XXX_POLICY_ACTION_DISCARD: 1440f3a2cd32SVivien Didelot val = MV88E6XXX_PORT_POLICY_CTL_DISCARD; 1441f3a2cd32SVivien Didelot break; 1442f3a2cd32SVivien Didelot default: 1443f3a2cd32SVivien Didelot return -EOPNOTSUPP; 1444f3a2cd32SVivien Didelot } 1445f3a2cd32SVivien Didelot 1446f3a2cd32SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_POLICY_CTL, ®); 1447f3a2cd32SVivien Didelot if (err) 1448f3a2cd32SVivien Didelot return err; 1449f3a2cd32SVivien Didelot 1450f3a2cd32SVivien Didelot reg &= ~mask; 1451f3a2cd32SVivien Didelot reg |= (val << shift) & mask; 1452f3a2cd32SVivien Didelot 1453f3a2cd32SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_POLICY_CTL, reg); 1454f3a2cd32SVivien Didelot } 1455