1*2874c5fdSThomas 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 29326422340SMarek Behún /* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6341) */ 29426422340SMarek Behún int mv88e6341_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 29526422340SMarek Behún { 29626422340SMarek Behún if (speed == SPEED_MAX) 29726422340SMarek Behún speed = port < 5 ? 1000 : 2500; 29826422340SMarek Behún 29926422340SMarek Behún if (speed > 2500) 30026422340SMarek Behún return -EOPNOTSUPP; 30126422340SMarek Behún 30226422340SMarek Behún if (speed == 200 && port != 0) 30326422340SMarek Behún return -EOPNOTSUPP; 30426422340SMarek Behún 30526422340SMarek Behún if (speed == 2500 && port < 5) 30626422340SMarek Behún return -EOPNOTSUPP; 30726422340SMarek Behún 30826422340SMarek Behún return mv88e6xxx_port_set_speed(chip, port, speed, !port, true); 30926422340SMarek Behún } 31026422340SMarek Behún 3117cbbee05SAndrew Lunn phy_interface_t mv88e6341_port_max_speed_mode(int port) 3127cbbee05SAndrew Lunn { 3137cbbee05SAndrew Lunn if (port == 5) 3147cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_2500BASEX; 3157cbbee05SAndrew Lunn 3167cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_NA; 3177cbbee05SAndrew Lunn } 3187cbbee05SAndrew Lunn 31996a2b40cSVivien Didelot /* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */ 32096a2b40cSVivien Didelot int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 32196a2b40cSVivien Didelot { 32296a2b40cSVivien Didelot if (speed == SPEED_MAX) 32396a2b40cSVivien Didelot speed = 1000; 32496a2b40cSVivien Didelot 32596a2b40cSVivien Didelot if (speed > 1000) 32696a2b40cSVivien Didelot return -EOPNOTSUPP; 32796a2b40cSVivien Didelot 32896a2b40cSVivien Didelot if (speed == 200 && port < 5) 32996a2b40cSVivien Didelot return -EOPNOTSUPP; 33096a2b40cSVivien Didelot 33196a2b40cSVivien Didelot return mv88e6xxx_port_set_speed(chip, port, speed, true, false); 33296a2b40cSVivien Didelot } 33396a2b40cSVivien Didelot 33496a2b40cSVivien Didelot /* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */ 33596a2b40cSVivien Didelot int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 33696a2b40cSVivien Didelot { 33796a2b40cSVivien Didelot if (speed == SPEED_MAX) 33896a2b40cSVivien Didelot speed = port < 9 ? 1000 : 2500; 33996a2b40cSVivien Didelot 34096a2b40cSVivien Didelot if (speed > 2500) 34196a2b40cSVivien Didelot return -EOPNOTSUPP; 34296a2b40cSVivien Didelot 34396a2b40cSVivien Didelot if (speed == 200 && port != 0) 34496a2b40cSVivien Didelot return -EOPNOTSUPP; 34596a2b40cSVivien Didelot 34696a2b40cSVivien Didelot if (speed == 2500 && port < 9) 34796a2b40cSVivien Didelot return -EOPNOTSUPP; 34896a2b40cSVivien Didelot 34996a2b40cSVivien Didelot return mv88e6xxx_port_set_speed(chip, port, speed, true, true); 35096a2b40cSVivien Didelot } 35196a2b40cSVivien Didelot 3527cbbee05SAndrew Lunn phy_interface_t mv88e6390_port_max_speed_mode(int port) 3537cbbee05SAndrew Lunn { 3547cbbee05SAndrew Lunn if (port == 9 || port == 10) 3557cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_2500BASEX; 3567cbbee05SAndrew Lunn 3577cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_NA; 3587cbbee05SAndrew Lunn } 3597cbbee05SAndrew Lunn 36096a2b40cSVivien Didelot /* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */ 36196a2b40cSVivien Didelot int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 36296a2b40cSVivien Didelot { 36396a2b40cSVivien Didelot if (speed == SPEED_MAX) 36496a2b40cSVivien Didelot speed = port < 9 ? 1000 : 10000; 36596a2b40cSVivien Didelot 36696a2b40cSVivien Didelot if (speed == 200 && port != 0) 36796a2b40cSVivien Didelot return -EOPNOTSUPP; 36896a2b40cSVivien Didelot 36996a2b40cSVivien Didelot if (speed >= 2500 && port < 9) 37096a2b40cSVivien Didelot return -EOPNOTSUPP; 37196a2b40cSVivien Didelot 37296a2b40cSVivien Didelot return mv88e6xxx_port_set_speed(chip, port, speed, true, true); 37396a2b40cSVivien Didelot } 37496a2b40cSVivien Didelot 3757cbbee05SAndrew Lunn phy_interface_t mv88e6390x_port_max_speed_mode(int port) 3767cbbee05SAndrew Lunn { 3777cbbee05SAndrew Lunn if (port == 9 || port == 10) 3787cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_XAUI; 3797cbbee05SAndrew Lunn 3807cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_NA; 3817cbbee05SAndrew Lunn } 3827cbbee05SAndrew Lunn 383f39908d3SAndrew Lunn int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, 384f39908d3SAndrew Lunn phy_interface_t mode) 385f39908d3SAndrew Lunn { 386734447d4SAndrew Lunn int lane; 387f39908d3SAndrew Lunn u16 cmode; 388734447d4SAndrew Lunn u16 reg; 389f39908d3SAndrew Lunn int err; 390f39908d3SAndrew Lunn 391f39908d3SAndrew Lunn if (port != 9 && port != 10) 392f39908d3SAndrew Lunn return -EOPNOTSUPP; 393f39908d3SAndrew Lunn 394787799a9SAndrew Lunn /* Default to a slow mode, so freeing up SERDES interfaces for 395787799a9SAndrew Lunn * other ports which might use them for SFPs. 396787799a9SAndrew Lunn */ 397787799a9SAndrew Lunn if (mode == PHY_INTERFACE_MODE_NA) 398787799a9SAndrew Lunn mode = PHY_INTERFACE_MODE_1000BASEX; 399787799a9SAndrew Lunn 400f39908d3SAndrew Lunn switch (mode) { 401f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_1000BASEX: 4025f83dc93SVivien Didelot cmode = MV88E6XXX_PORT_STS_CMODE_1000BASE_X; 403f39908d3SAndrew Lunn break; 404f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_SGMII: 4055f83dc93SVivien Didelot cmode = MV88E6XXX_PORT_STS_CMODE_SGMII; 406f39908d3SAndrew Lunn break; 407f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_2500BASEX: 4085f83dc93SVivien Didelot cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX; 409f39908d3SAndrew Lunn break; 410f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_XGMII: 4112e51a8dcSRussell King case PHY_INTERFACE_MODE_XAUI: 4125f83dc93SVivien Didelot cmode = MV88E6XXX_PORT_STS_CMODE_XAUI; 413f39908d3SAndrew Lunn break; 414f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_RXAUI: 4155f83dc93SVivien Didelot cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI; 416f39908d3SAndrew Lunn break; 417f39908d3SAndrew Lunn default: 418f39908d3SAndrew Lunn cmode = 0; 419f39908d3SAndrew Lunn } 420f39908d3SAndrew Lunn 421ed8fe202SHeiner Kallweit /* cmode doesn't change, nothing to do for us */ 422ed8fe202SHeiner Kallweit if (cmode == chip->ports[port].cmode) 423ed8fe202SHeiner Kallweit return 0; 424ed8fe202SHeiner Kallweit 425734447d4SAndrew Lunn lane = mv88e6390x_serdes_get_lane(chip, port); 4265ceaeb99SHeiner Kallweit if (lane < 0 && lane != -ENODEV) 427734447d4SAndrew Lunn return lane; 428734447d4SAndrew Lunn 4295ceaeb99SHeiner Kallweit if (lane >= 0) { 430734447d4SAndrew Lunn if (chip->ports[port].serdes_irq) { 431734447d4SAndrew Lunn err = mv88e6390_serdes_irq_disable(chip, port, lane); 432734447d4SAndrew Lunn if (err) 433734447d4SAndrew Lunn return err; 434734447d4SAndrew Lunn } 435734447d4SAndrew Lunn 436d235c48bSMaxime Chevallier err = mv88e6390x_serdes_power(chip, port, false); 437364e9d77SAndrew Lunn if (err) 438364e9d77SAndrew Lunn return err; 4395ceaeb99SHeiner Kallweit } 4405ceaeb99SHeiner Kallweit 4415ceaeb99SHeiner Kallweit chip->ports[port].cmode = 0; 442364e9d77SAndrew Lunn 443f39908d3SAndrew Lunn if (cmode) { 4445f83dc93SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 445f39908d3SAndrew Lunn if (err) 446f39908d3SAndrew Lunn return err; 447f39908d3SAndrew Lunn 4485f83dc93SVivien Didelot reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK; 449f39908d3SAndrew Lunn reg |= cmode; 450f39908d3SAndrew Lunn 4515f83dc93SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg); 452f39908d3SAndrew Lunn if (err) 453f39908d3SAndrew Lunn return err; 454364e9d77SAndrew Lunn 4555ceaeb99SHeiner Kallweit chip->ports[port].cmode = cmode; 4565ceaeb99SHeiner Kallweit 4575ceaeb99SHeiner Kallweit lane = mv88e6390x_serdes_get_lane(chip, port); 4585ceaeb99SHeiner Kallweit if (lane < 0) 4595ceaeb99SHeiner Kallweit return lane; 4605ceaeb99SHeiner Kallweit 461d235c48bSMaxime Chevallier err = mv88e6390x_serdes_power(chip, port, true); 462364e9d77SAndrew Lunn if (err) 463364e9d77SAndrew Lunn return err; 464734447d4SAndrew Lunn 465734447d4SAndrew Lunn if (chip->ports[port].serdes_irq) { 466734447d4SAndrew Lunn err = mv88e6390_serdes_irq_enable(chip, port, lane); 467734447d4SAndrew Lunn if (err) 468734447d4SAndrew Lunn return err; 469734447d4SAndrew Lunn } 470f39908d3SAndrew Lunn } 471f39908d3SAndrew Lunn 472f39908d3SAndrew Lunn return 0; 473f39908d3SAndrew Lunn } 474f39908d3SAndrew Lunn 475fdc71eeaSAndrew Lunn int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port, 476fdc71eeaSAndrew Lunn phy_interface_t mode) 477fdc71eeaSAndrew Lunn { 478fdc71eeaSAndrew Lunn switch (mode) { 47965b034cfSMarek Behún case PHY_INTERFACE_MODE_NA: 48065b034cfSMarek Behún return 0; 481fdc71eeaSAndrew Lunn case PHY_INTERFACE_MODE_XGMII: 482fdc71eeaSAndrew Lunn case PHY_INTERFACE_MODE_XAUI: 483fdc71eeaSAndrew Lunn case PHY_INTERFACE_MODE_RXAUI: 484fdc71eeaSAndrew Lunn return -EINVAL; 485fdc71eeaSAndrew Lunn default: 486fdc71eeaSAndrew Lunn break; 487fdc71eeaSAndrew Lunn } 488fdc71eeaSAndrew Lunn 489fdc71eeaSAndrew Lunn return mv88e6390x_port_set_cmode(chip, port, mode); 490fdc71eeaSAndrew Lunn } 491fdc71eeaSAndrew Lunn 4922d2e1dd2SAndrew Lunn int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode) 4936c422e34SRussell King { 4946c422e34SRussell King int err; 4956c422e34SRussell King u16 reg; 4966c422e34SRussell King 4976c422e34SRussell King err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 4986c422e34SRussell King if (err) 4996c422e34SRussell King return err; 5006c422e34SRussell King 5012d2e1dd2SAndrew Lunn *cmode = reg & MV88E6185_PORT_STS_CMODE_MASK; 5022d2e1dd2SAndrew Lunn 5032d2e1dd2SAndrew Lunn return 0; 5046c422e34SRussell King } 5056c422e34SRussell King 5062d2e1dd2SAndrew Lunn int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode) 507f39908d3SAndrew Lunn { 508f39908d3SAndrew Lunn int err; 509f39908d3SAndrew Lunn u16 reg; 510f39908d3SAndrew Lunn 5115f83dc93SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 512f39908d3SAndrew Lunn if (err) 513f39908d3SAndrew Lunn return err; 514f39908d3SAndrew Lunn 5155f83dc93SVivien Didelot *cmode = reg & MV88E6XXX_PORT_STS_CMODE_MASK; 516f39908d3SAndrew Lunn 517f39908d3SAndrew Lunn return 0; 518f39908d3SAndrew Lunn } 519f39908d3SAndrew Lunn 5206c422e34SRussell King int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port, 521c9a2356fSRussell King struct phylink_link_state *state) 522c9a2356fSRussell King { 523c9a2356fSRussell King int err; 524c9a2356fSRussell King u16 reg; 525c9a2356fSRussell King 526c9a2356fSRussell King err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 527c9a2356fSRussell King if (err) 528c9a2356fSRussell King return err; 529c9a2356fSRussell King 530c9a2356fSRussell King switch (reg & MV88E6XXX_PORT_STS_SPEED_MASK) { 531c9a2356fSRussell King case MV88E6XXX_PORT_STS_SPEED_10: 532c9a2356fSRussell King state->speed = SPEED_10; 533c9a2356fSRussell King break; 534c9a2356fSRussell King case MV88E6XXX_PORT_STS_SPEED_100: 535c9a2356fSRussell King state->speed = SPEED_100; 536c9a2356fSRussell King break; 537c9a2356fSRussell King case MV88E6XXX_PORT_STS_SPEED_1000: 538c9a2356fSRussell King state->speed = SPEED_1000; 539c9a2356fSRussell King break; 540c9a2356fSRussell King case MV88E6XXX_PORT_STS_SPEED_10000: 541c9a2356fSRussell King if ((reg & MV88E6XXX_PORT_STS_CMODE_MASK) == 542c9a2356fSRussell King MV88E6XXX_PORT_STS_CMODE_2500BASEX) 543c9a2356fSRussell King state->speed = SPEED_2500; 544c9a2356fSRussell King else 545c9a2356fSRussell King state->speed = SPEED_10000; 546c9a2356fSRussell King break; 547c9a2356fSRussell King } 548c9a2356fSRussell King 549c9a2356fSRussell King state->duplex = reg & MV88E6XXX_PORT_STS_DUPLEX ? 550c9a2356fSRussell King DUPLEX_FULL : DUPLEX_HALF; 551c9a2356fSRussell King state->link = !!(reg & MV88E6XXX_PORT_STS_LINK); 552c9a2356fSRussell King state->an_enabled = 1; 553c9a2356fSRussell King state->an_complete = state->link; 554c9a2356fSRussell King 555c9a2356fSRussell King return 0; 556c9a2356fSRussell King } 557c9a2356fSRussell King 5586c422e34SRussell King int mv88e6185_port_link_state(struct mv88e6xxx_chip *chip, int port, 5596c422e34SRussell King struct phylink_link_state *state) 5606c422e34SRussell King { 5616c422e34SRussell King if (state->interface == PHY_INTERFACE_MODE_1000BASEX) { 5622d2e1dd2SAndrew Lunn u8 cmode = chip->ports[port].cmode; 5636c422e34SRussell King 5646c422e34SRussell King /* When a port is in "Cross-chip serdes" mode, it uses 5656c422e34SRussell King * 1000Base-X full duplex mode, but there is no automatic 5666c422e34SRussell King * link detection. Use the sync OK status for link (as it 5676c422e34SRussell King * would do for 1000Base-X mode.) 5686c422e34SRussell King */ 5696c422e34SRussell King if (cmode == MV88E6185_PORT_STS_CMODE_SERDES) { 5706c422e34SRussell King u16 mac; 5716c422e34SRussell King int err; 5726c422e34SRussell King 5736c422e34SRussell King err = mv88e6xxx_port_read(chip, port, 5746c422e34SRussell King MV88E6XXX_PORT_MAC_CTL, &mac); 5756c422e34SRussell King if (err) 5766c422e34SRussell King return err; 5776c422e34SRussell King 5786c422e34SRussell King state->link = !!(mac & MV88E6185_PORT_MAC_CTL_SYNC_OK); 5796c422e34SRussell King state->an_enabled = 1; 5806c422e34SRussell King state->an_complete = 5816c422e34SRussell King !!(mac & MV88E6185_PORT_MAC_CTL_AN_DONE); 5826c422e34SRussell King state->duplex = 5836c422e34SRussell King state->link ? DUPLEX_FULL : DUPLEX_UNKNOWN; 5846c422e34SRussell King state->speed = 5856c422e34SRussell King state->link ? SPEED_1000 : SPEED_UNKNOWN; 5866c422e34SRussell King 5876c422e34SRussell King return 0; 5886c422e34SRussell King } 5896c422e34SRussell King } 5906c422e34SRussell King 5916c422e34SRussell King return mv88e6352_port_link_state(chip, port, state); 5926c422e34SRussell King } 5936c422e34SRussell King 5946c96bbfdSVivien Didelot /* Offset 0x02: Jamming Control 595b35d322aSAndrew Lunn * 596b35d322aSAndrew Lunn * Do not limit the period of time that this port can be paused for by 597b35d322aSAndrew Lunn * the remote end or the period of time that this port can pause the 598b35d322aSAndrew Lunn * remote end. 599b35d322aSAndrew Lunn */ 6000898432cSVivien Didelot int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, 6010898432cSVivien Didelot u8 out) 602b35d322aSAndrew Lunn { 6036c96bbfdSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6097_PORT_JAM_CTL, 6046c96bbfdSVivien Didelot out << 8 | in); 605b35d322aSAndrew Lunn } 606b35d322aSAndrew Lunn 6070898432cSVivien Didelot int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, 6080898432cSVivien Didelot u8 out) 6093ce0e65eSAndrew Lunn { 6103ce0e65eSAndrew Lunn int err; 6113ce0e65eSAndrew Lunn 6126c96bbfdSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL, 6136c96bbfdSVivien Didelot MV88E6390_PORT_FLOW_CTL_UPDATE | 6146c96bbfdSVivien Didelot MV88E6390_PORT_FLOW_CTL_LIMIT_IN | in); 6153ce0e65eSAndrew Lunn if (err) 6163ce0e65eSAndrew Lunn return err; 6173ce0e65eSAndrew Lunn 6186c96bbfdSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL, 6196c96bbfdSVivien Didelot MV88E6390_PORT_FLOW_CTL_UPDATE | 6206c96bbfdSVivien Didelot MV88E6390_PORT_FLOW_CTL_LIMIT_OUT | out); 6213ce0e65eSAndrew Lunn } 6223ce0e65eSAndrew Lunn 623e28def33SVivien Didelot /* Offset 0x04: Port Control Register */ 624e28def33SVivien Didelot 625e28def33SVivien Didelot static const char * const mv88e6xxx_port_state_names[] = { 626a89b433bSVivien Didelot [MV88E6XXX_PORT_CTL0_STATE_DISABLED] = "Disabled", 627a89b433bSVivien Didelot [MV88E6XXX_PORT_CTL0_STATE_BLOCKING] = "Blocking/Listening", 628a89b433bSVivien Didelot [MV88E6XXX_PORT_CTL0_STATE_LEARNING] = "Learning", 629a89b433bSVivien Didelot [MV88E6XXX_PORT_CTL0_STATE_FORWARDING] = "Forwarding", 630e28def33SVivien Didelot }; 631e28def33SVivien Didelot 632e28def33SVivien Didelot int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state) 633e28def33SVivien Didelot { 634e28def33SVivien Didelot u16 reg; 635e28def33SVivien Didelot int err; 636e28def33SVivien Didelot 637a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 638e28def33SVivien Didelot if (err) 639e28def33SVivien Didelot return err; 640e28def33SVivien Didelot 641a89b433bSVivien Didelot reg &= ~MV88E6XXX_PORT_CTL0_STATE_MASK; 642f894c29cSVivien Didelot 643f894c29cSVivien Didelot switch (state) { 644f894c29cSVivien Didelot case BR_STATE_DISABLED: 645a89b433bSVivien Didelot state = MV88E6XXX_PORT_CTL0_STATE_DISABLED; 646f894c29cSVivien Didelot break; 647f894c29cSVivien Didelot case BR_STATE_BLOCKING: 648f894c29cSVivien Didelot case BR_STATE_LISTENING: 649a89b433bSVivien Didelot state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING; 650f894c29cSVivien Didelot break; 651f894c29cSVivien Didelot case BR_STATE_LEARNING: 652a89b433bSVivien Didelot state = MV88E6XXX_PORT_CTL0_STATE_LEARNING; 653f894c29cSVivien Didelot break; 654f894c29cSVivien Didelot case BR_STATE_FORWARDING: 655a89b433bSVivien Didelot state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 656f894c29cSVivien Didelot break; 657f894c29cSVivien Didelot default: 658f894c29cSVivien Didelot return -EINVAL; 659f894c29cSVivien Didelot } 660f894c29cSVivien Didelot 661e28def33SVivien Didelot reg |= state; 662e28def33SVivien Didelot 663a89b433bSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 664e28def33SVivien Didelot if (err) 665e28def33SVivien Didelot return err; 666e28def33SVivien Didelot 667774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: PortState set to %s\n", port, 668e28def33SVivien Didelot mv88e6xxx_port_state_names[state]); 669e28def33SVivien Didelot 670e28def33SVivien Didelot return 0; 671e28def33SVivien Didelot } 6725a7921f4SVivien Didelot 67356995cbcSAndrew Lunn int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port, 67431bef4e9SVivien Didelot enum mv88e6xxx_egress_mode mode) 67556995cbcSAndrew Lunn { 67656995cbcSAndrew Lunn int err; 67756995cbcSAndrew Lunn u16 reg; 67856995cbcSAndrew Lunn 679a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 68056995cbcSAndrew Lunn if (err) 68156995cbcSAndrew Lunn return err; 68256995cbcSAndrew Lunn 683a89b433bSVivien Didelot reg &= ~MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK; 68431bef4e9SVivien Didelot 68531bef4e9SVivien Didelot switch (mode) { 68631bef4e9SVivien Didelot case MV88E6XXX_EGRESS_MODE_UNMODIFIED: 687a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED; 68831bef4e9SVivien Didelot break; 68931bef4e9SVivien Didelot case MV88E6XXX_EGRESS_MODE_UNTAGGED: 690a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED; 69131bef4e9SVivien Didelot break; 69231bef4e9SVivien Didelot case MV88E6XXX_EGRESS_MODE_TAGGED: 693a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED; 69431bef4e9SVivien Didelot break; 69531bef4e9SVivien Didelot case MV88E6XXX_EGRESS_MODE_ETHERTYPE: 696a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA; 69731bef4e9SVivien Didelot break; 69831bef4e9SVivien Didelot default: 69931bef4e9SVivien Didelot return -EINVAL; 70031bef4e9SVivien Didelot } 70156995cbcSAndrew Lunn 702a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 70356995cbcSAndrew Lunn } 70456995cbcSAndrew Lunn 70556995cbcSAndrew Lunn int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, 70656995cbcSAndrew Lunn enum mv88e6xxx_frame_mode mode) 70756995cbcSAndrew Lunn { 70856995cbcSAndrew Lunn int err; 70956995cbcSAndrew Lunn u16 reg; 71056995cbcSAndrew Lunn 711a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 71256995cbcSAndrew Lunn if (err) 71356995cbcSAndrew Lunn return err; 71456995cbcSAndrew Lunn 715a89b433bSVivien Didelot reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK; 71656995cbcSAndrew Lunn 71756995cbcSAndrew Lunn switch (mode) { 71856995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_NORMAL: 719a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL; 72056995cbcSAndrew Lunn break; 72156995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_DSA: 722a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA; 72356995cbcSAndrew Lunn break; 72456995cbcSAndrew Lunn default: 72556995cbcSAndrew Lunn return -EINVAL; 72656995cbcSAndrew Lunn } 72756995cbcSAndrew Lunn 728a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 72956995cbcSAndrew Lunn } 73056995cbcSAndrew Lunn 73156995cbcSAndrew Lunn int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, 73256995cbcSAndrew Lunn enum mv88e6xxx_frame_mode mode) 73356995cbcSAndrew Lunn { 73456995cbcSAndrew Lunn int err; 73556995cbcSAndrew Lunn u16 reg; 73656995cbcSAndrew Lunn 737a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 73856995cbcSAndrew Lunn if (err) 73956995cbcSAndrew Lunn return err; 74056995cbcSAndrew Lunn 741a89b433bSVivien Didelot reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK; 74256995cbcSAndrew Lunn 74356995cbcSAndrew Lunn switch (mode) { 74456995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_NORMAL: 745a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL; 74656995cbcSAndrew Lunn break; 74756995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_DSA: 748a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA; 74956995cbcSAndrew Lunn break; 75056995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_PROVIDER: 751a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_PROVIDER; 75256995cbcSAndrew Lunn break; 75356995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_ETHERTYPE: 754a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_ETHER_TYPE_DSA; 75556995cbcSAndrew Lunn break; 75656995cbcSAndrew Lunn default: 75756995cbcSAndrew Lunn return -EINVAL; 75856995cbcSAndrew Lunn } 75956995cbcSAndrew Lunn 760a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 76156995cbcSAndrew Lunn } 76256995cbcSAndrew Lunn 763601aeed3SVivien Didelot static int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip, 764601aeed3SVivien Didelot int port, bool unicast) 76556995cbcSAndrew Lunn { 76656995cbcSAndrew Lunn int err; 76756995cbcSAndrew Lunn u16 reg; 76856995cbcSAndrew Lunn 769a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 77056995cbcSAndrew Lunn if (err) 77156995cbcSAndrew Lunn return err; 77256995cbcSAndrew Lunn 773601aeed3SVivien Didelot if (unicast) 774a89b433bSVivien Didelot reg |= MV88E6185_PORT_CTL0_FORWARD_UNKNOWN; 77556995cbcSAndrew Lunn else 776a89b433bSVivien Didelot reg &= ~MV88E6185_PORT_CTL0_FORWARD_UNKNOWN; 77756995cbcSAndrew Lunn 778a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 77956995cbcSAndrew Lunn } 78056995cbcSAndrew Lunn 781601aeed3SVivien Didelot int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, 782601aeed3SVivien Didelot bool unicast, bool multicast) 78356995cbcSAndrew Lunn { 78456995cbcSAndrew Lunn int err; 78556995cbcSAndrew Lunn u16 reg; 78656995cbcSAndrew Lunn 787a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 78856995cbcSAndrew Lunn if (err) 78956995cbcSAndrew Lunn return err; 79056995cbcSAndrew Lunn 791a89b433bSVivien Didelot reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MASK; 792601aeed3SVivien Didelot 793601aeed3SVivien Didelot if (unicast && multicast) 794a89b433bSVivien Didelot reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_ALL_UNKNOWN_DA; 795601aeed3SVivien Didelot else if (unicast) 796a89b433bSVivien Didelot reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_MC_DA; 797601aeed3SVivien Didelot else if (multicast) 798a89b433bSVivien Didelot reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_UC_DA; 79956995cbcSAndrew Lunn else 800a89b433bSVivien Didelot reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_DA; 80156995cbcSAndrew Lunn 802a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 80356995cbcSAndrew Lunn } 80456995cbcSAndrew Lunn 805b4e48c50SVivien Didelot /* Offset 0x05: Port Control 1 */ 806b4e48c50SVivien Didelot 807ea698f4fSVivien Didelot int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port, 808ea698f4fSVivien Didelot bool message_port) 809ea698f4fSVivien Didelot { 810ea698f4fSVivien Didelot u16 val; 811ea698f4fSVivien Didelot int err; 812ea698f4fSVivien Didelot 813cd985bbfSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val); 814ea698f4fSVivien Didelot if (err) 815ea698f4fSVivien Didelot return err; 816ea698f4fSVivien Didelot 817ea698f4fSVivien Didelot if (message_port) 818cd985bbfSVivien Didelot val |= MV88E6XXX_PORT_CTL1_MESSAGE_PORT; 819ea698f4fSVivien Didelot else 820cd985bbfSVivien Didelot val &= ~MV88E6XXX_PORT_CTL1_MESSAGE_PORT; 821ea698f4fSVivien Didelot 822cd985bbfSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val); 823ea698f4fSVivien Didelot } 824ea698f4fSVivien Didelot 8255a7921f4SVivien Didelot /* Offset 0x06: Port Based VLAN Map */ 8265a7921f4SVivien Didelot 8275a7921f4SVivien Didelot int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map) 8285a7921f4SVivien Didelot { 8294d294af2SVivien Didelot const u16 mask = mv88e6xxx_port_mask(chip); 8305a7921f4SVivien Didelot u16 reg; 8315a7921f4SVivien Didelot int err; 8325a7921f4SVivien Didelot 8337e5cc5f1SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®); 8345a7921f4SVivien Didelot if (err) 8355a7921f4SVivien Didelot return err; 8365a7921f4SVivien Didelot 8375a7921f4SVivien Didelot reg &= ~mask; 8385a7921f4SVivien Didelot reg |= map & mask; 8395a7921f4SVivien Didelot 8407e5cc5f1SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg); 8415a7921f4SVivien Didelot if (err) 8425a7921f4SVivien Didelot return err; 8435a7921f4SVivien Didelot 844774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: VLANTable set to %.3x\n", port, map); 8455a7921f4SVivien Didelot 8465a7921f4SVivien Didelot return 0; 8475a7921f4SVivien Didelot } 848b4e48c50SVivien Didelot 849b4e48c50SVivien Didelot int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid) 850b4e48c50SVivien Didelot { 851b4e48c50SVivien Didelot const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4; 852b4e48c50SVivien Didelot u16 reg; 853b4e48c50SVivien Didelot int err; 854b4e48c50SVivien Didelot 855b4e48c50SVivien Didelot /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */ 8567e5cc5f1SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®); 857b4e48c50SVivien Didelot if (err) 858b4e48c50SVivien Didelot return err; 859b4e48c50SVivien Didelot 860b4e48c50SVivien Didelot *fid = (reg & 0xf000) >> 12; 861b4e48c50SVivien Didelot 862b4e48c50SVivien Didelot /* Port's default FID upper bits are located in reg 0x05, offset 0 */ 863b4e48c50SVivien Didelot if (upper_mask) { 864cd985bbfSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, 865cd985bbfSVivien Didelot ®); 866b4e48c50SVivien Didelot if (err) 867b4e48c50SVivien Didelot return err; 868b4e48c50SVivien Didelot 869b4e48c50SVivien Didelot *fid |= (reg & upper_mask) << 4; 870b4e48c50SVivien Didelot } 871b4e48c50SVivien Didelot 872b4e48c50SVivien Didelot return 0; 873b4e48c50SVivien Didelot } 874b4e48c50SVivien Didelot 875b4e48c50SVivien Didelot int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid) 876b4e48c50SVivien Didelot { 877b4e48c50SVivien Didelot const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4; 878b4e48c50SVivien Didelot u16 reg; 879b4e48c50SVivien Didelot int err; 880b4e48c50SVivien Didelot 881b4e48c50SVivien Didelot if (fid >= mv88e6xxx_num_databases(chip)) 882b4e48c50SVivien Didelot return -EINVAL; 883b4e48c50SVivien Didelot 884b4e48c50SVivien Didelot /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */ 8857e5cc5f1SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®); 886b4e48c50SVivien Didelot if (err) 887b4e48c50SVivien Didelot return err; 888b4e48c50SVivien Didelot 889b4e48c50SVivien Didelot reg &= 0x0fff; 890b4e48c50SVivien Didelot reg |= (fid & 0x000f) << 12; 891b4e48c50SVivien Didelot 8927e5cc5f1SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg); 893b4e48c50SVivien Didelot if (err) 894b4e48c50SVivien Didelot return err; 895b4e48c50SVivien Didelot 896b4e48c50SVivien Didelot /* Port's default FID upper bits are located in reg 0x05, offset 0 */ 897b4e48c50SVivien Didelot if (upper_mask) { 898cd985bbfSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, 899cd985bbfSVivien Didelot ®); 900b4e48c50SVivien Didelot if (err) 901b4e48c50SVivien Didelot return err; 902b4e48c50SVivien Didelot 903b4e48c50SVivien Didelot reg &= ~upper_mask; 904b4e48c50SVivien Didelot reg |= (fid >> 4) & upper_mask; 905b4e48c50SVivien Didelot 906cd985bbfSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, 907cd985bbfSVivien Didelot reg); 908b4e48c50SVivien Didelot if (err) 909b4e48c50SVivien Didelot return err; 910b4e48c50SVivien Didelot } 911b4e48c50SVivien Didelot 912774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: FID set to %u\n", port, fid); 913b4e48c50SVivien Didelot 914b4e48c50SVivien Didelot return 0; 915b4e48c50SVivien Didelot } 91677064f37SVivien Didelot 91777064f37SVivien Didelot /* Offset 0x07: Default Port VLAN ID & Priority */ 91877064f37SVivien Didelot 91977064f37SVivien Didelot int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid) 92077064f37SVivien Didelot { 92177064f37SVivien Didelot u16 reg; 92277064f37SVivien Didelot int err; 92377064f37SVivien Didelot 924b7929fb3SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 925b7929fb3SVivien Didelot ®); 92677064f37SVivien Didelot if (err) 92777064f37SVivien Didelot return err; 92877064f37SVivien Didelot 929b7929fb3SVivien Didelot *pvid = reg & MV88E6XXX_PORT_DEFAULT_VLAN_MASK; 93077064f37SVivien Didelot 93177064f37SVivien Didelot return 0; 93277064f37SVivien Didelot } 93377064f37SVivien Didelot 93477064f37SVivien Didelot int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid) 93577064f37SVivien Didelot { 93677064f37SVivien Didelot u16 reg; 93777064f37SVivien Didelot int err; 93877064f37SVivien Didelot 939b7929fb3SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 940b7929fb3SVivien Didelot ®); 94177064f37SVivien Didelot if (err) 94277064f37SVivien Didelot return err; 94377064f37SVivien Didelot 944b7929fb3SVivien Didelot reg &= ~MV88E6XXX_PORT_DEFAULT_VLAN_MASK; 945b7929fb3SVivien Didelot reg |= pvid & MV88E6XXX_PORT_DEFAULT_VLAN_MASK; 94677064f37SVivien Didelot 947b7929fb3SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 948b7929fb3SVivien Didelot reg); 94977064f37SVivien Didelot if (err) 95077064f37SVivien Didelot return err; 95177064f37SVivien Didelot 952774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: DefaultVID set to %u\n", port, pvid); 95377064f37SVivien Didelot 95477064f37SVivien Didelot return 0; 95577064f37SVivien Didelot } 956385a0995SVivien Didelot 957385a0995SVivien Didelot /* Offset 0x08: Port Control 2 Register */ 958385a0995SVivien Didelot 959385a0995SVivien Didelot static const char * const mv88e6xxx_port_8021q_mode_names[] = { 96081c6edb2SVivien Didelot [MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED] = "Disabled", 96181c6edb2SVivien Didelot [MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK] = "Fallback", 96281c6edb2SVivien Didelot [MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK] = "Check", 96381c6edb2SVivien Didelot [MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure", 964385a0995SVivien Didelot }; 965385a0995SVivien Didelot 966601aeed3SVivien Didelot static int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip, 967601aeed3SVivien Didelot int port, bool multicast) 968a23b2961SAndrew Lunn { 969a23b2961SAndrew Lunn int err; 970a23b2961SAndrew Lunn u16 reg; 971a23b2961SAndrew Lunn 97281c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 973a23b2961SAndrew Lunn if (err) 974a23b2961SAndrew Lunn return err; 975a23b2961SAndrew Lunn 976601aeed3SVivien Didelot if (multicast) 97781c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD; 978a23b2961SAndrew Lunn else 97981c6edb2SVivien Didelot reg &= ~MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD; 980a23b2961SAndrew Lunn 98181c6edb2SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 982a23b2961SAndrew Lunn } 983a23b2961SAndrew Lunn 984601aeed3SVivien Didelot int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, 985601aeed3SVivien Didelot bool unicast, bool multicast) 986601aeed3SVivien Didelot { 987601aeed3SVivien Didelot int err; 988601aeed3SVivien Didelot 989601aeed3SVivien Didelot err = mv88e6185_port_set_forward_unknown(chip, port, unicast); 990601aeed3SVivien Didelot if (err) 991601aeed3SVivien Didelot return err; 992601aeed3SVivien Didelot 993601aeed3SVivien Didelot return mv88e6185_port_set_default_forward(chip, port, multicast); 994601aeed3SVivien Didelot } 995601aeed3SVivien Didelot 996a23b2961SAndrew Lunn int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port, 997a23b2961SAndrew Lunn int upstream_port) 998a23b2961SAndrew Lunn { 999a23b2961SAndrew Lunn int err; 1000a23b2961SAndrew Lunn u16 reg; 1001a23b2961SAndrew Lunn 100281c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 1003a23b2961SAndrew Lunn if (err) 1004a23b2961SAndrew Lunn return err; 1005a23b2961SAndrew Lunn 100681c6edb2SVivien Didelot reg &= ~MV88E6095_PORT_CTL2_CPU_PORT_MASK; 1007a23b2961SAndrew Lunn reg |= upstream_port; 1008a23b2961SAndrew Lunn 100981c6edb2SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 1010a23b2961SAndrew Lunn } 1011a23b2961SAndrew Lunn 1012385a0995SVivien Didelot int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port, 1013385a0995SVivien Didelot u16 mode) 1014385a0995SVivien Didelot { 1015385a0995SVivien Didelot u16 reg; 1016385a0995SVivien Didelot int err; 1017385a0995SVivien Didelot 101881c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 1019385a0995SVivien Didelot if (err) 1020385a0995SVivien Didelot return err; 1021385a0995SVivien Didelot 102281c6edb2SVivien Didelot reg &= ~MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK; 102381c6edb2SVivien Didelot reg |= mode & MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK; 1024385a0995SVivien Didelot 102581c6edb2SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 1026385a0995SVivien Didelot if (err) 1027385a0995SVivien Didelot return err; 1028385a0995SVivien Didelot 1029774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: 802.1QMode set to %s\n", port, 1030385a0995SVivien Didelot mv88e6xxx_port_8021q_mode_names[mode]); 1031385a0995SVivien Didelot 1032385a0995SVivien Didelot return 0; 1033385a0995SVivien Didelot } 1034ef0a7318SAndrew Lunn 1035a23b2961SAndrew Lunn int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port) 1036a23b2961SAndrew Lunn { 1037a23b2961SAndrew Lunn u16 reg; 1038a23b2961SAndrew Lunn int err; 1039a23b2961SAndrew Lunn 104081c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 1041a23b2961SAndrew Lunn if (err) 1042a23b2961SAndrew Lunn return err; 1043a23b2961SAndrew Lunn 104481c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_MAP_DA; 1045a23b2961SAndrew Lunn 104681c6edb2SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 1047a23b2961SAndrew Lunn } 1048a23b2961SAndrew Lunn 1049cd782656SVivien Didelot int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port, 1050cd782656SVivien Didelot size_t size) 10515f436666SAndrew Lunn { 10525f436666SAndrew Lunn u16 reg; 10535f436666SAndrew Lunn int err; 10545f436666SAndrew Lunn 105581c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 10565f436666SAndrew Lunn if (err) 10575f436666SAndrew Lunn return err; 10585f436666SAndrew Lunn 105981c6edb2SVivien Didelot reg &= ~MV88E6XXX_PORT_CTL2_JUMBO_MODE_MASK; 1060cd782656SVivien Didelot 1061cd782656SVivien Didelot if (size <= 1522) 106281c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_1522; 1063cd782656SVivien Didelot else if (size <= 2048) 106481c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_2048; 1065cd782656SVivien Didelot else if (size <= 10240) 106681c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_10240; 1067cd782656SVivien Didelot else 1068cd782656SVivien Didelot return -ERANGE; 10695f436666SAndrew Lunn 107081c6edb2SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 10715f436666SAndrew Lunn } 10725f436666SAndrew Lunn 1073ef70b111SAndrew Lunn /* Offset 0x09: Port Rate Control */ 1074ef70b111SAndrew Lunn 1075ef70b111SAndrew Lunn int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port) 1076ef70b111SAndrew Lunn { 10772cb8cb14SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1, 10782cb8cb14SVivien Didelot 0x0000); 1079ef70b111SAndrew Lunn } 1080ef70b111SAndrew Lunn 1081ef70b111SAndrew Lunn int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port) 1082ef70b111SAndrew Lunn { 10832cb8cb14SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1, 10842cb8cb14SVivien Didelot 0x0001); 1085ef70b111SAndrew Lunn } 1086ef70b111SAndrew Lunn 1087c8c94891SVivien Didelot /* Offset 0x0C: Port ATU Control */ 1088c8c94891SVivien Didelot 1089c8c94891SVivien Didelot int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port) 1090c8c94891SVivien Didelot { 1091b8109594SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ATU_CTL, 0); 1092c8c94891SVivien Didelot } 1093c8c94891SVivien Didelot 10949dbfb4e1SVivien Didelot /* Offset 0x0D: (Priority) Override Register */ 10959dbfb4e1SVivien Didelot 10969dbfb4e1SVivien Didelot int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port) 10979dbfb4e1SVivien Didelot { 1098b8109594SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0); 10999dbfb4e1SVivien Didelot } 11009dbfb4e1SVivien Didelot 110156995cbcSAndrew Lunn /* Offset 0x0f: Port Ether type */ 110256995cbcSAndrew Lunn 110356995cbcSAndrew Lunn int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port, 110456995cbcSAndrew Lunn u16 etype) 110556995cbcSAndrew Lunn { 1106b8109594SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype); 110756995cbcSAndrew Lunn } 110856995cbcSAndrew Lunn 1109ef0a7318SAndrew Lunn /* Offset 0x18: Port IEEE Priority Remapping Registers [0-3] 1110ef0a7318SAndrew Lunn * Offset 0x19: Port IEEE Priority Remapping Registers [4-7] 1111ef0a7318SAndrew Lunn */ 1112ef0a7318SAndrew Lunn 1113ef0a7318SAndrew Lunn int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port) 1114ef0a7318SAndrew Lunn { 1115ef0a7318SAndrew Lunn int err; 1116ef0a7318SAndrew Lunn 1117ef0a7318SAndrew Lunn /* Use a direct priority mapping for all IEEE tagged frames */ 11188009df9eSVivien Didelot err = mv88e6xxx_port_write(chip, port, 11198009df9eSVivien Didelot MV88E6095_PORT_IEEE_PRIO_REMAP_0123, 11208009df9eSVivien Didelot 0x3210); 1121ef0a7318SAndrew Lunn if (err) 1122ef0a7318SAndrew Lunn return err; 1123ef0a7318SAndrew Lunn 11248009df9eSVivien Didelot return mv88e6xxx_port_write(chip, port, 11258009df9eSVivien Didelot MV88E6095_PORT_IEEE_PRIO_REMAP_4567, 11268009df9eSVivien Didelot 0x7654); 1127ef0a7318SAndrew Lunn } 1128ef0a7318SAndrew Lunn 1129ef0a7318SAndrew Lunn static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip, 1130ddcbabf4SVivien Didelot int port, u16 table, u8 ptr, u16 data) 1131ef0a7318SAndrew Lunn { 1132ef0a7318SAndrew Lunn u16 reg; 1133ef0a7318SAndrew Lunn 1134ddcbabf4SVivien Didelot reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE | table | 1135ddcbabf4SVivien Didelot (ptr << __bf_shf(MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_PTR_MASK)) | 1136ddcbabf4SVivien Didelot (data & MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_DATA_MASK); 1137ef0a7318SAndrew Lunn 11388009df9eSVivien Didelot return mv88e6xxx_port_write(chip, port, 11398009df9eSVivien Didelot MV88E6390_PORT_IEEE_PRIO_MAP_TABLE, reg); 1140ef0a7318SAndrew Lunn } 1141ef0a7318SAndrew Lunn 1142ef0a7318SAndrew Lunn int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port) 1143ef0a7318SAndrew Lunn { 1144ef0a7318SAndrew Lunn int err, i; 11458009df9eSVivien Didelot u16 table; 1146ef0a7318SAndrew Lunn 1147ef0a7318SAndrew Lunn for (i = 0; i <= 7; i++) { 11488009df9eSVivien Didelot table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP; 11498009df9eSVivien Didelot err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, 11508009df9eSVivien Didelot (i | i << 4)); 1151ef0a7318SAndrew Lunn if (err) 1152ef0a7318SAndrew Lunn return err; 1153ef0a7318SAndrew Lunn 11548009df9eSVivien Didelot table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP; 11558009df9eSVivien Didelot err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); 1156ef0a7318SAndrew Lunn if (err) 1157ef0a7318SAndrew Lunn return err; 1158ef0a7318SAndrew Lunn 11598009df9eSVivien Didelot table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP; 11608009df9eSVivien Didelot err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); 1161ef0a7318SAndrew Lunn if (err) 1162ef0a7318SAndrew Lunn return err; 1163ef0a7318SAndrew Lunn 11648009df9eSVivien Didelot table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP; 11658009df9eSVivien Didelot err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); 1166ef0a7318SAndrew Lunn if (err) 1167ef0a7318SAndrew Lunn return err; 1168ef0a7318SAndrew Lunn } 1169ef0a7318SAndrew Lunn 1170ef0a7318SAndrew Lunn return 0; 1171ef0a7318SAndrew Lunn } 1172