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"
17de776d0dSPavana Sharma #include "global2.h"
1818abed21SVivien Didelot #include "port.h"
19364e9d77SAndrew Lunn #include "serdes.h"
2018abed21SVivien Didelot
mv88e6xxx_port_read(struct mv88e6xxx_chip * chip,int port,int reg,u16 * val)2118abed21SVivien Didelot int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
2218abed21SVivien Didelot u16 *val)
2318abed21SVivien Didelot {
2418abed21SVivien Didelot int addr = chip->info->port_base_addr + port;
2518abed21SVivien Didelot
2618abed21SVivien Didelot return mv88e6xxx_read(chip, addr, reg, val);
2718abed21SVivien Didelot }
2818abed21SVivien Didelot
mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip * chip,int port,int reg,int bit,int val)29de776d0dSPavana Sharma int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
30de776d0dSPavana Sharma int bit, int val)
31de776d0dSPavana Sharma {
32de776d0dSPavana Sharma int addr = chip->info->port_base_addr + port;
33de776d0dSPavana Sharma
34de776d0dSPavana Sharma return mv88e6xxx_wait_bit(chip, addr, reg, bit, val);
35de776d0dSPavana Sharma }
36de776d0dSPavana Sharma
mv88e6xxx_port_write(struct mv88e6xxx_chip * chip,int port,int reg,u16 val)3718abed21SVivien Didelot int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
3818abed21SVivien Didelot u16 val)
3918abed21SVivien Didelot {
4018abed21SVivien Didelot int addr = chip->info->port_base_addr + port;
4118abed21SVivien Didelot
4218abed21SVivien Didelot return mv88e6xxx_write(chip, addr, reg, val);
4318abed21SVivien Didelot }
44e28def33SVivien Didelot
4554186b91SAndrew Lunn /* Offset 0x00: MAC (or PCS or Physical) Status Register
4654186b91SAndrew Lunn *
4754186b91SAndrew Lunn * For most devices, this is read only. However the 6185 has the MyPause
4854186b91SAndrew Lunn * bit read/write.
4954186b91SAndrew Lunn */
mv88e6185_port_set_pause(struct mv88e6xxx_chip * chip,int port,int pause)5054186b91SAndrew Lunn int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
5154186b91SAndrew Lunn int pause)
5254186b91SAndrew Lunn {
5354186b91SAndrew Lunn u16 reg;
5454186b91SAndrew Lunn int err;
5554186b91SAndrew Lunn
5654186b91SAndrew Lunn err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®);
5754186b91SAndrew Lunn if (err)
5854186b91SAndrew Lunn return err;
5954186b91SAndrew Lunn
6054186b91SAndrew Lunn if (pause)
6154186b91SAndrew Lunn reg |= MV88E6XXX_PORT_STS_MY_PAUSE;
6254186b91SAndrew Lunn else
6354186b91SAndrew Lunn reg &= ~MV88E6XXX_PORT_STS_MY_PAUSE;
6454186b91SAndrew Lunn
6554186b91SAndrew Lunn return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
6654186b91SAndrew Lunn }
6754186b91SAndrew Lunn
6808ef7f10SVivien Didelot /* Offset 0x01: MAC (or PCS or Physical) Control Register
6908ef7f10SVivien Didelot *
7008ef7f10SVivien Didelot * Link, Duplex and Flow Control have one force bit, one value bit.
7196a2b40cSVivien Didelot *
7296a2b40cSVivien Didelot * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value.
7396a2b40cSVivien Didelot * Alternative values require the 200BASE (or AltSpeed) bit 12 set.
7496a2b40cSVivien Didelot * Newer chips need a ForcedSpd bit 13 set to consider the value.
7508ef7f10SVivien Didelot */
7608ef7f10SVivien Didelot
mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)77a0a0f622SVivien Didelot static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
78a0a0f622SVivien Didelot phy_interface_t mode)
79a0a0f622SVivien Didelot {
80a0a0f622SVivien Didelot u16 reg;
81a0a0f622SVivien Didelot int err;
82a0a0f622SVivien Didelot
835ee55577SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®);
84a0a0f622SVivien Didelot if (err)
85a0a0f622SVivien Didelot return err;
86a0a0f622SVivien Didelot
875ee55577SVivien Didelot reg &= ~(MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
885ee55577SVivien Didelot MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK);
89a0a0f622SVivien Didelot
90a0a0f622SVivien Didelot switch (mode) {
91a0a0f622SVivien Didelot case PHY_INTERFACE_MODE_RGMII_RXID:
925ee55577SVivien Didelot reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK;
93a0a0f622SVivien Didelot break;
94a0a0f622SVivien Didelot case PHY_INTERFACE_MODE_RGMII_TXID:
955ee55577SVivien Didelot reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
96a0a0f622SVivien Didelot break;
97a0a0f622SVivien Didelot case PHY_INTERFACE_MODE_RGMII_ID:
985ee55577SVivien Didelot reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
995ee55577SVivien Didelot MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
100a0a0f622SVivien Didelot break;
101fedf1865SAndrew Lunn case PHY_INTERFACE_MODE_RGMII:
102a0a0f622SVivien Didelot break;
103fedf1865SAndrew Lunn default:
104fedf1865SAndrew Lunn return 0;
105a0a0f622SVivien Didelot }
106a0a0f622SVivien Didelot
1075ee55577SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
108a0a0f622SVivien Didelot if (err)
109a0a0f622SVivien Didelot return err;
110a0a0f622SVivien Didelot
111774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: delay RXCLK %s, TXCLK %s\n", port,
1125ee55577SVivien Didelot reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK ? "yes" : "no",
1135ee55577SVivien Didelot reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK ? "yes" : "no");
114a0a0f622SVivien Didelot
115a0a0f622SVivien Didelot return 0;
116a0a0f622SVivien Didelot }
117a0a0f622SVivien Didelot
mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)118a0a0f622SVivien Didelot int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
119a0a0f622SVivien Didelot phy_interface_t mode)
120a0a0f622SVivien Didelot {
121a0a0f622SVivien Didelot if (port < 5)
122a0a0f622SVivien Didelot return -EOPNOTSUPP;
123a0a0f622SVivien Didelot
124a0a0f622SVivien Didelot return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
125a0a0f622SVivien Didelot }
126a0a0f622SVivien Didelot
mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)127a0a0f622SVivien Didelot int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
128a0a0f622SVivien Didelot phy_interface_t mode)
129a0a0f622SVivien Didelot {
130a0a0f622SVivien Didelot if (port != 0)
131a0a0f622SVivien Didelot return -EOPNOTSUPP;
132a0a0f622SVivien Didelot
133a0a0f622SVivien Didelot return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
134a0a0f622SVivien Didelot }
135a0a0f622SVivien Didelot
mv88e6320_port_set_rgmii_delay(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)13691e87045SSteffen Bätz int mv88e6320_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
13791e87045SSteffen Bätz phy_interface_t mode)
13891e87045SSteffen Bätz {
13991e87045SSteffen Bätz if (port != 2 && port != 5 && port != 6)
14091e87045SSteffen Bätz return -EOPNOTSUPP;
14191e87045SSteffen Bätz
14291e87045SSteffen Bätz return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
14391e87045SSteffen Bätz }
14491e87045SSteffen Bätz
mv88e6xxx_port_set_link(struct mv88e6xxx_chip * chip,int port,int link)14508ef7f10SVivien Didelot int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link)
14608ef7f10SVivien Didelot {
14708ef7f10SVivien Didelot u16 reg;
14808ef7f10SVivien Didelot int err;
14908ef7f10SVivien Didelot
1505ee55577SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®);
15108ef7f10SVivien Didelot if (err)
15208ef7f10SVivien Didelot return err;
15308ef7f10SVivien Didelot
1545ee55577SVivien Didelot reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
1555ee55577SVivien Didelot MV88E6XXX_PORT_MAC_CTL_LINK_UP);
15608ef7f10SVivien Didelot
15708ef7f10SVivien Didelot switch (link) {
15808ef7f10SVivien Didelot case LINK_FORCED_DOWN:
1595ee55577SVivien Didelot reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK;
16008ef7f10SVivien Didelot break;
16108ef7f10SVivien Didelot case LINK_FORCED_UP:
1625ee55577SVivien Didelot reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
1635ee55577SVivien Didelot MV88E6XXX_PORT_MAC_CTL_LINK_UP;
16408ef7f10SVivien Didelot break;
16508ef7f10SVivien Didelot case LINK_UNFORCED:
16608ef7f10SVivien Didelot /* normal link detection */
16708ef7f10SVivien Didelot break;
16808ef7f10SVivien Didelot default:
16908ef7f10SVivien Didelot return -EINVAL;
17008ef7f10SVivien Didelot }
17108ef7f10SVivien Didelot
1725ee55577SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
17308ef7f10SVivien Didelot if (err)
17408ef7f10SVivien Didelot return err;
17508ef7f10SVivien Didelot
176774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: %s link %s\n", port,
1775ee55577SVivien Didelot reg & MV88E6XXX_PORT_MAC_CTL_FORCE_LINK ? "Force" : "Unforce",
1785ee55577SVivien Didelot reg & MV88E6XXX_PORT_MAC_CTL_LINK_UP ? "up" : "down");
17908ef7f10SVivien Didelot
18008ef7f10SVivien Didelot return 0;
18108ef7f10SVivien Didelot }
18208ef7f10SVivien Didelot
mv88e6xxx_port_sync_link(struct mv88e6xxx_chip * chip,int port,unsigned int mode,bool isup)1834efe7662SChris Packham int mv88e6xxx_port_sync_link(struct mv88e6xxx_chip *chip, int port, unsigned int mode, bool isup)
1844efe7662SChris Packham {
1854efe7662SChris Packham const struct mv88e6xxx_ops *ops = chip->info->ops;
1864efe7662SChris Packham int err = 0;
1874efe7662SChris Packham int link;
1884efe7662SChris Packham
1894efe7662SChris Packham if (isup)
1904efe7662SChris Packham link = LINK_FORCED_UP;
1914efe7662SChris Packham else
1924efe7662SChris Packham link = LINK_FORCED_DOWN;
1934efe7662SChris Packham
1944efe7662SChris Packham if (ops->port_set_link)
1954efe7662SChris Packham err = ops->port_set_link(chip, port, link);
1964efe7662SChris Packham
1974efe7662SChris Packham return err;
1984efe7662SChris Packham }
1994efe7662SChris Packham
mv88e6185_port_sync_link(struct mv88e6xxx_chip * chip,int port,unsigned int mode,bool isup)2004efe7662SChris Packham int mv88e6185_port_sync_link(struct mv88e6xxx_chip *chip, int port, unsigned int mode, bool isup)
2014efe7662SChris Packham {
2024efe7662SChris Packham const struct mv88e6xxx_ops *ops = chip->info->ops;
2034efe7662SChris Packham int err = 0;
2044efe7662SChris Packham int link;
2054efe7662SChris Packham
2064efe7662SChris Packham if (mode == MLO_AN_INBAND)
2074efe7662SChris Packham link = LINK_UNFORCED;
2084efe7662SChris Packham else if (isup)
2094efe7662SChris Packham link = LINK_FORCED_UP;
2104efe7662SChris Packham else
2114efe7662SChris Packham link = LINK_FORCED_DOWN;
2124efe7662SChris Packham
2134efe7662SChris Packham if (ops->port_set_link)
2144efe7662SChris Packham err = ops->port_set_link(chip, port, link);
2154efe7662SChris Packham
2164efe7662SChris Packham return err;
2174efe7662SChris Packham }
2184efe7662SChris Packham
mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip * chip,int port,int speed,bool alt_bit,bool force_bit,int duplex)219f365c6f7SRussell King static int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip,
220f365c6f7SRussell King int port, int speed, bool alt_bit,
221f365c6f7SRussell King bool force_bit, int duplex)
22296a2b40cSVivien Didelot {
22396a2b40cSVivien Didelot u16 reg, ctrl;
22496a2b40cSVivien Didelot int err;
22596a2b40cSVivien Didelot
22696a2b40cSVivien Didelot switch (speed) {
22796a2b40cSVivien Didelot case 10:
2285ee55577SVivien Didelot ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;
22996a2b40cSVivien Didelot break;
23096a2b40cSVivien Didelot case 100:
2315ee55577SVivien Didelot ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;
23296a2b40cSVivien Didelot break;
23396a2b40cSVivien Didelot case 200:
23496a2b40cSVivien Didelot if (alt_bit)
2355ee55577SVivien Didelot ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |
2365ee55577SVivien Didelot MV88E6390_PORT_MAC_CTL_ALTSPEED;
23796a2b40cSVivien Didelot else
2385ee55577SVivien Didelot ctrl = MV88E6065_PORT_MAC_CTL_SPEED_200;
23996a2b40cSVivien Didelot break;
24096a2b40cSVivien Didelot case 1000:
2415ee55577SVivien Didelot ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;
24296a2b40cSVivien Didelot break;
24396a2b40cSVivien Didelot case 2500:
24426422340SMarek Behún if (alt_bit)
2455ee55577SVivien Didelot ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
2465ee55577SVivien Didelot MV88E6390_PORT_MAC_CTL_ALTSPEED;
24726422340SMarek Behún else
24826422340SMarek Behún ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000;
24996a2b40cSVivien Didelot break;
25096a2b40cSVivien Didelot case 10000:
25196a2b40cSVivien Didelot /* all bits set, fall through... */
25296a2b40cSVivien Didelot case SPEED_UNFORCED:
2535ee55577SVivien Didelot ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;
25496a2b40cSVivien Didelot break;
25596a2b40cSVivien Didelot default:
25696a2b40cSVivien Didelot return -EOPNOTSUPP;
25796a2b40cSVivien Didelot }
25896a2b40cSVivien Didelot
259f365c6f7SRussell King switch (duplex) {
260f365c6f7SRussell King case DUPLEX_HALF:
261f365c6f7SRussell King ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;
262f365c6f7SRussell King break;
263f365c6f7SRussell King case DUPLEX_FULL:
264f365c6f7SRussell King ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
265f365c6f7SRussell King MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;
266f365c6f7SRussell King break;
267f365c6f7SRussell King case DUPLEX_UNFORCED:
268f365c6f7SRussell King /* normal duplex detection */
269f365c6f7SRussell King break;
270f365c6f7SRussell King default:
271f365c6f7SRussell King return -EOPNOTSUPP;
272f365c6f7SRussell King }
273f365c6f7SRussell King
2745ee55577SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®);
27596a2b40cSVivien Didelot if (err)
27696a2b40cSVivien Didelot return err;
27796a2b40cSVivien Didelot
278f365c6f7SRussell King reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |
279f365c6f7SRussell King MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
280f365c6f7SRussell King MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);
281f365c6f7SRussell King
28296a2b40cSVivien Didelot if (alt_bit)
2835ee55577SVivien Didelot reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED;
28496a2b40cSVivien Didelot if (force_bit) {
2855ee55577SVivien Didelot reg &= ~MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
2860b6e3d03SAndrew Lunn if (speed != SPEED_UNFORCED)
2875ee55577SVivien Didelot ctrl |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
28896a2b40cSVivien Didelot }
28996a2b40cSVivien Didelot reg |= ctrl;
29096a2b40cSVivien Didelot
2915ee55577SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
29296a2b40cSVivien Didelot if (err)
29396a2b40cSVivien Didelot return err;
29496a2b40cSVivien Didelot
295e08cdf63SAndrey Eremeev if (speed != SPEED_UNFORCED)
296774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);
29796a2b40cSVivien Didelot else
298774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: Speed unforced\n", port);
299f365c6f7SRussell King dev_dbg(chip->dev, "p%d: %s %s duplex\n", port,
300f365c6f7SRussell King reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce",
301f365c6f7SRussell King reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half");
30296a2b40cSVivien Didelot
30396a2b40cSVivien Didelot return 0;
30496a2b40cSVivien Didelot }
30596a2b40cSVivien Didelot
30696a2b40cSVivien Didelot /* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */
mv88e6185_port_set_speed_duplex(struct mv88e6xxx_chip * chip,int port,int speed,int duplex)307f365c6f7SRussell King int mv88e6185_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
308f365c6f7SRussell King int speed, int duplex)
30996a2b40cSVivien Didelot {
31096a2b40cSVivien Didelot if (speed == 200 || speed > 1000)
31196a2b40cSVivien Didelot return -EOPNOTSUPP;
31296a2b40cSVivien Didelot
313f365c6f7SRussell King return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false,
314f365c6f7SRussell King duplex);
31596a2b40cSVivien Didelot }
31696a2b40cSVivien Didelot
317a528e5beSRasmus Villemoes /* Support 10, 100 Mbps (e.g. 88E6250 family) */
mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip * chip,int port,int speed,int duplex)318f365c6f7SRussell King int mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
319f365c6f7SRussell King int speed, int duplex)
320a528e5beSRasmus Villemoes {
321a528e5beSRasmus Villemoes if (speed > 100)
322a528e5beSRasmus Villemoes return -EOPNOTSUPP;
323a528e5beSRasmus Villemoes
324f365c6f7SRussell King return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false,
325f365c6f7SRussell King duplex);
326a528e5beSRasmus Villemoes }
327a528e5beSRasmus Villemoes
32826422340SMarek Behún /* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6341) */
mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip * chip,int port,int speed,int duplex)329f365c6f7SRussell King int mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
330f365c6f7SRussell King int speed, int duplex)
33126422340SMarek Behún {
33226422340SMarek Behún if (speed > 2500)
33326422340SMarek Behún return -EOPNOTSUPP;
33426422340SMarek Behún
33526422340SMarek Behún if (speed == 200 && port != 0)
33626422340SMarek Behún return -EOPNOTSUPP;
33726422340SMarek Behún
33826422340SMarek Behún if (speed == 2500 && port < 5)
33926422340SMarek Behún return -EOPNOTSUPP;
34026422340SMarek Behún
341f365c6f7SRussell King return mv88e6xxx_port_set_speed_duplex(chip, port, speed, !port, true,
342f365c6f7SRussell King duplex);
34326422340SMarek Behún }
34426422340SMarek Behún
mv88e6341_port_max_speed_mode(struct mv88e6xxx_chip * chip,int port)34518e1b742SAlexis Lothoré phy_interface_t mv88e6341_port_max_speed_mode(struct mv88e6xxx_chip *chip,
34618e1b742SAlexis Lothoré int port)
3477cbbee05SAndrew Lunn {
3487cbbee05SAndrew Lunn if (port == 5)
3497cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_2500BASEX;
3507cbbee05SAndrew Lunn
3517cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_NA;
3527cbbee05SAndrew Lunn }
3537cbbee05SAndrew Lunn
35496a2b40cSVivien Didelot /* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */
mv88e6352_port_set_speed_duplex(struct mv88e6xxx_chip * chip,int port,int speed,int duplex)355f365c6f7SRussell King int mv88e6352_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
356f365c6f7SRussell King int speed, int duplex)
35796a2b40cSVivien Didelot {
35896a2b40cSVivien Didelot if (speed > 1000)
35996a2b40cSVivien Didelot return -EOPNOTSUPP;
36096a2b40cSVivien Didelot
36196a2b40cSVivien Didelot if (speed == 200 && port < 5)
36296a2b40cSVivien Didelot return -EOPNOTSUPP;
36396a2b40cSVivien Didelot
364f365c6f7SRussell King return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, false,
365f365c6f7SRussell King duplex);
36696a2b40cSVivien Didelot }
36796a2b40cSVivien Didelot
36896a2b40cSVivien Didelot /* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */
mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip * chip,int port,int speed,int duplex)369f365c6f7SRussell King int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
370f365c6f7SRussell King int speed, int duplex)
37196a2b40cSVivien Didelot {
37296a2b40cSVivien Didelot if (speed > 2500)
37396a2b40cSVivien Didelot return -EOPNOTSUPP;
37496a2b40cSVivien Didelot
37596a2b40cSVivien Didelot if (speed == 200 && port != 0)
37696a2b40cSVivien Didelot return -EOPNOTSUPP;
37796a2b40cSVivien Didelot
37896a2b40cSVivien Didelot if (speed == 2500 && port < 9)
37996a2b40cSVivien Didelot return -EOPNOTSUPP;
38096a2b40cSVivien Didelot
381f365c6f7SRussell King return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true,
382f365c6f7SRussell King duplex);
38396a2b40cSVivien Didelot }
38496a2b40cSVivien Didelot
mv88e6390_port_max_speed_mode(struct mv88e6xxx_chip * chip,int port)38518e1b742SAlexis Lothoré phy_interface_t mv88e6390_port_max_speed_mode(struct mv88e6xxx_chip *chip,
38618e1b742SAlexis Lothoré int port)
3877cbbee05SAndrew Lunn {
3887cbbee05SAndrew Lunn if (port == 9 || port == 10)
3897cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_2500BASEX;
3907cbbee05SAndrew Lunn
3917cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_NA;
3927cbbee05SAndrew Lunn }
3937cbbee05SAndrew Lunn
39496a2b40cSVivien Didelot /* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */
mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip * chip,int port,int speed,int duplex)395f365c6f7SRussell King int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
396f365c6f7SRussell King int speed, int duplex)
39796a2b40cSVivien Didelot {
39896a2b40cSVivien Didelot if (speed == 200 && port != 0)
39996a2b40cSVivien Didelot return -EOPNOTSUPP;
40096a2b40cSVivien Didelot
40196a2b40cSVivien Didelot if (speed >= 2500 && port < 9)
40296a2b40cSVivien Didelot return -EOPNOTSUPP;
40396a2b40cSVivien Didelot
404f365c6f7SRussell King return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true,
405f365c6f7SRussell King duplex);
40696a2b40cSVivien Didelot }
40796a2b40cSVivien Didelot
mv88e6390x_port_max_speed_mode(struct mv88e6xxx_chip * chip,int port)40818e1b742SAlexis Lothoré phy_interface_t mv88e6390x_port_max_speed_mode(struct mv88e6xxx_chip *chip,
40918e1b742SAlexis Lothoré int port)
4107cbbee05SAndrew Lunn {
4117cbbee05SAndrew Lunn if (port == 9 || port == 10)
4127cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_XAUI;
4137cbbee05SAndrew Lunn
4147cbbee05SAndrew Lunn return PHY_INTERFACE_MODE_NA;
4157cbbee05SAndrew Lunn }
4167cbbee05SAndrew Lunn
417de776d0dSPavana Sharma /* Support 10, 100, 200, 1000, 2500, 5000, 10000 Mbps (e.g. 88E6393X)
418de776d0dSPavana Sharma * Function mv88e6xxx_port_set_speed_duplex() can't be used as the register
419de776d0dSPavana Sharma * values for speeds 2500 & 5000 conflict.
420de776d0dSPavana Sharma */
mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip * chip,int port,int speed,int duplex)421de776d0dSPavana Sharma int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
422de776d0dSPavana Sharma int speed, int duplex)
423de776d0dSPavana Sharma {
424de776d0dSPavana Sharma u16 reg, ctrl;
425de776d0dSPavana Sharma int err;
426de776d0dSPavana Sharma
42712899f29SAlexis Lothoré if (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361 &&
42812899f29SAlexis Lothoré speed > 2500)
42912899f29SAlexis Lothoré return -EOPNOTSUPP;
43012899f29SAlexis Lothoré
431de776d0dSPavana Sharma if (speed == 200 && port != 0)
432de776d0dSPavana Sharma return -EOPNOTSUPP;
433de776d0dSPavana Sharma
434de776d0dSPavana Sharma if (speed >= 2500 && port > 0 && port < 9)
435de776d0dSPavana Sharma return -EOPNOTSUPP;
436de776d0dSPavana Sharma
437de776d0dSPavana Sharma switch (speed) {
438de776d0dSPavana Sharma case 10:
439de776d0dSPavana Sharma ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;
440de776d0dSPavana Sharma break;
441de776d0dSPavana Sharma case 100:
442de776d0dSPavana Sharma ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;
443de776d0dSPavana Sharma break;
444de776d0dSPavana Sharma case 200:
445de776d0dSPavana Sharma ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |
446de776d0dSPavana Sharma MV88E6390_PORT_MAC_CTL_ALTSPEED;
447de776d0dSPavana Sharma break;
448de776d0dSPavana Sharma case 1000:
449de776d0dSPavana Sharma ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;
450de776d0dSPavana Sharma break;
451de776d0dSPavana Sharma case 2500:
452de776d0dSPavana Sharma ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000 |
453de776d0dSPavana Sharma MV88E6390_PORT_MAC_CTL_ALTSPEED;
454de776d0dSPavana Sharma break;
455de776d0dSPavana Sharma case 5000:
456de776d0dSPavana Sharma ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
457de776d0dSPavana Sharma MV88E6390_PORT_MAC_CTL_ALTSPEED;
458de776d0dSPavana Sharma break;
459de776d0dSPavana Sharma case 10000:
460de776d0dSPavana Sharma case SPEED_UNFORCED:
461de776d0dSPavana Sharma ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;
462de776d0dSPavana Sharma break;
463de776d0dSPavana Sharma default:
464de776d0dSPavana Sharma return -EOPNOTSUPP;
465de776d0dSPavana Sharma }
466de776d0dSPavana Sharma
467de776d0dSPavana Sharma switch (duplex) {
468de776d0dSPavana Sharma case DUPLEX_HALF:
469de776d0dSPavana Sharma ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;
470de776d0dSPavana Sharma break;
471de776d0dSPavana Sharma case DUPLEX_FULL:
472de776d0dSPavana Sharma ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
473de776d0dSPavana Sharma MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;
474de776d0dSPavana Sharma break;
475de776d0dSPavana Sharma case DUPLEX_UNFORCED:
476de776d0dSPavana Sharma /* normal duplex detection */
477de776d0dSPavana Sharma break;
478de776d0dSPavana Sharma default:
479de776d0dSPavana Sharma return -EOPNOTSUPP;
480de776d0dSPavana Sharma }
481de776d0dSPavana Sharma
482de776d0dSPavana Sharma err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®);
483de776d0dSPavana Sharma if (err)
484de776d0dSPavana Sharma return err;
485de776d0dSPavana Sharma
486de776d0dSPavana Sharma reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |
487de776d0dSPavana Sharma MV88E6390_PORT_MAC_CTL_ALTSPEED |
488de776d0dSPavana Sharma MV88E6390_PORT_MAC_CTL_FORCE_SPEED);
489de776d0dSPavana Sharma
490de776d0dSPavana Sharma if (speed != SPEED_UNFORCED)
491de776d0dSPavana Sharma reg |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
492de776d0dSPavana Sharma
493de776d0dSPavana Sharma reg |= ctrl;
494de776d0dSPavana Sharma
495de776d0dSPavana Sharma err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
496de776d0dSPavana Sharma if (err)
497de776d0dSPavana Sharma return err;
498de776d0dSPavana Sharma
499e08cdf63SAndrey Eremeev if (speed != SPEED_UNFORCED)
500de776d0dSPavana Sharma dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);
501de776d0dSPavana Sharma else
502de776d0dSPavana Sharma dev_dbg(chip->dev, "p%d: Speed unforced\n", port);
503de776d0dSPavana Sharma dev_dbg(chip->dev, "p%d: %s %s duplex\n", port,
504de776d0dSPavana Sharma reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce",
505de776d0dSPavana Sharma reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half");
506de776d0dSPavana Sharma
507de776d0dSPavana Sharma return 0;
508de776d0dSPavana Sharma }
509de776d0dSPavana Sharma
mv88e6393x_port_max_speed_mode(struct mv88e6xxx_chip * chip,int port)51018e1b742SAlexis Lothoré phy_interface_t mv88e6393x_port_max_speed_mode(struct mv88e6xxx_chip *chip,
51118e1b742SAlexis Lothoré int port)
512de776d0dSPavana Sharma {
513de776d0dSPavana Sharma
51412899f29SAlexis Lothoré if (port != 0 && port != 9 && port != 10)
515de776d0dSPavana Sharma return PHY_INTERFACE_MODE_NA;
51612899f29SAlexis Lothoré
51712899f29SAlexis Lothoré if (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361)
51812899f29SAlexis Lothoré return PHY_INTERFACE_MODE_2500BASEX;
51912899f29SAlexis Lothoré
52012899f29SAlexis Lothoré return PHY_INTERFACE_MODE_10GBASER;
521de776d0dSPavana Sharma }
522de776d0dSPavana Sharma
mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode,bool force)5237a3007d2SMarek Behún static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
524f7a48b68SBaruch Siach phy_interface_t mode, bool force)
525f39908d3SAndrew Lunn {
526f39908d3SAndrew Lunn u16 cmode;
527734447d4SAndrew Lunn u16 reg;
528f39908d3SAndrew Lunn int err;
529f39908d3SAndrew Lunn
530787799a9SAndrew Lunn /* Default to a slow mode, so freeing up SERDES interfaces for
531787799a9SAndrew Lunn * other ports which might use them for SFPs.
532787799a9SAndrew Lunn */
533787799a9SAndrew Lunn if (mode == PHY_INTERFACE_MODE_NA)
534787799a9SAndrew Lunn mode = PHY_INTERFACE_MODE_1000BASEX;
535787799a9SAndrew Lunn
536f39908d3SAndrew Lunn switch (mode) {
53700202885SBaruch Siach case PHY_INTERFACE_MODE_RMII:
53800202885SBaruch Siach cmode = MV88E6XXX_PORT_STS_CMODE_RMII;
53900202885SBaruch Siach break;
5401d2577abSMarcus Carlberg case PHY_INTERFACE_MODE_RGMII:
5411d2577abSMarcus Carlberg case PHY_INTERFACE_MODE_RGMII_ID:
5421d2577abSMarcus Carlberg case PHY_INTERFACE_MODE_RGMII_RXID:
5431d2577abSMarcus Carlberg case PHY_INTERFACE_MODE_RGMII_TXID:
5441d2577abSMarcus Carlberg cmode = MV88E6XXX_PORT_STS_CMODE_RGMII;
5451d2577abSMarcus Carlberg break;
546f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_1000BASEX:
5473bbb8867SMarek Behún cmode = MV88E6XXX_PORT_STS_CMODE_1000BASEX;
548f39908d3SAndrew Lunn break;
549f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_SGMII:
5505f83dc93SVivien Didelot cmode = MV88E6XXX_PORT_STS_CMODE_SGMII;
551f39908d3SAndrew Lunn break;
552f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_2500BASEX:
5535f83dc93SVivien Didelot cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
554f39908d3SAndrew Lunn break;
555de776d0dSPavana Sharma case PHY_INTERFACE_MODE_5GBASER:
556de776d0dSPavana Sharma cmode = MV88E6393X_PORT_STS_CMODE_5GBASER;
557de776d0dSPavana Sharma break;
558f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_XGMII:
5592e51a8dcSRussell King case PHY_INTERFACE_MODE_XAUI:
5605f83dc93SVivien Didelot cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
561f39908d3SAndrew Lunn break;
562f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_RXAUI:
5635f83dc93SVivien Didelot cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI;
564f39908d3SAndrew Lunn break;
565de776d0dSPavana Sharma case PHY_INTERFACE_MODE_10GBASER:
566de776d0dSPavana Sharma cmode = MV88E6393X_PORT_STS_CMODE_10GBASER;
567de776d0dSPavana Sharma break;
5684a562127SMichal Smulski case PHY_INTERFACE_MODE_USXGMII:
5694a562127SMichal Smulski cmode = MV88E6393X_PORT_STS_CMODE_USXGMII;
5704a562127SMichal Smulski break;
571f39908d3SAndrew Lunn default:
572f39908d3SAndrew Lunn cmode = 0;
573f39908d3SAndrew Lunn }
574f39908d3SAndrew Lunn
575f7a48b68SBaruch Siach /* cmode doesn't change, nothing to do for us unless forced */
576f7a48b68SBaruch Siach if (cmode == chip->ports[port].cmode && !force)
577ed8fe202SHeiner Kallweit return 0;
578ed8fe202SHeiner Kallweit
5795ceaeb99SHeiner Kallweit chip->ports[port].cmode = 0;
580364e9d77SAndrew Lunn
581f39908d3SAndrew Lunn if (cmode) {
5825f83dc93SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®);
583f39908d3SAndrew Lunn if (err)
584f39908d3SAndrew Lunn return err;
585f39908d3SAndrew Lunn
5865f83dc93SVivien Didelot reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK;
587f39908d3SAndrew Lunn reg |= cmode;
588f39908d3SAndrew Lunn
5895f83dc93SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
590f39908d3SAndrew Lunn if (err)
591f39908d3SAndrew Lunn return err;
592364e9d77SAndrew Lunn
5935ceaeb99SHeiner Kallweit chip->ports[port].cmode = cmode;
594f39908d3SAndrew Lunn }
595f39908d3SAndrew Lunn
596f39908d3SAndrew Lunn return 0;
597f39908d3SAndrew Lunn }
598f39908d3SAndrew Lunn
mv88e6390x_port_set_cmode(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)5997a3007d2SMarek Behún int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
6007a3007d2SMarek Behún phy_interface_t mode)
6017a3007d2SMarek Behún {
6027a3007d2SMarek Behún if (port != 9 && port != 10)
6037a3007d2SMarek Behún return -EOPNOTSUPP;
6047a3007d2SMarek Behún
605f7a48b68SBaruch Siach return mv88e6xxx_port_set_cmode(chip, port, mode, false);
6067a3007d2SMarek Behún }
6077a3007d2SMarek Behún
mv88e6390_port_set_cmode(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)608fdc71eeaSAndrew Lunn int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
609fdc71eeaSAndrew Lunn phy_interface_t mode)
610fdc71eeaSAndrew Lunn {
6117a3007d2SMarek Behún if (port != 9 && port != 10)
6127a3007d2SMarek Behún return -EOPNOTSUPP;
6137a3007d2SMarek Behún
614fdc71eeaSAndrew Lunn switch (mode) {
61565b034cfSMarek Behún case PHY_INTERFACE_MODE_NA:
61665b034cfSMarek Behún return 0;
617fdc71eeaSAndrew Lunn case PHY_INTERFACE_MODE_XGMII:
618fdc71eeaSAndrew Lunn case PHY_INTERFACE_MODE_XAUI:
619fdc71eeaSAndrew Lunn case PHY_INTERFACE_MODE_RXAUI:
620fdc71eeaSAndrew Lunn return -EINVAL;
621fdc71eeaSAndrew Lunn default:
622fdc71eeaSAndrew Lunn break;
623fdc71eeaSAndrew Lunn }
624fdc71eeaSAndrew Lunn
625f7a48b68SBaruch Siach return mv88e6xxx_port_set_cmode(chip, port, mode, false);
6267a3007d2SMarek Behún }
6277a3007d2SMarek Behún
mv88e6393x_port_set_cmode(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)628de776d0dSPavana Sharma int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
629de776d0dSPavana Sharma phy_interface_t mode)
630de776d0dSPavana Sharma {
631de776d0dSPavana Sharma int err;
632de776d0dSPavana Sharma u16 reg;
633de776d0dSPavana Sharma
634de776d0dSPavana Sharma if (port != 0 && port != 9 && port != 10)
635de776d0dSPavana Sharma return -EOPNOTSUPP;
636de776d0dSPavana Sharma
6371d2577abSMarcus Carlberg if (port == 9 || port == 10) {
6381d2577abSMarcus Carlberg switch (mode) {
6391d2577abSMarcus Carlberg case PHY_INTERFACE_MODE_RMII:
6401d2577abSMarcus Carlberg case PHY_INTERFACE_MODE_RGMII:
6411d2577abSMarcus Carlberg case PHY_INTERFACE_MODE_RGMII_ID:
6421d2577abSMarcus Carlberg case PHY_INTERFACE_MODE_RGMII_RXID:
6431d2577abSMarcus Carlberg case PHY_INTERFACE_MODE_RGMII_TXID:
6441d2577abSMarcus Carlberg return -EINVAL;
6451d2577abSMarcus Carlberg default:
6461d2577abSMarcus Carlberg break;
6471d2577abSMarcus Carlberg }
6481d2577abSMarcus Carlberg }
6491d2577abSMarcus Carlberg
650de776d0dSPavana Sharma /* mv88e6393x errata 4.5: EEE should be disabled on SERDES ports */
651de776d0dSPavana Sharma err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®);
652de776d0dSPavana Sharma if (err)
653de776d0dSPavana Sharma return err;
654de776d0dSPavana Sharma
655de776d0dSPavana Sharma reg &= ~MV88E6XXX_PORT_MAC_CTL_EEE;
656de776d0dSPavana Sharma reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_EEE;
657de776d0dSPavana Sharma err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
658de776d0dSPavana Sharma if (err)
659de776d0dSPavana Sharma return err;
660de776d0dSPavana Sharma
661de776d0dSPavana Sharma return mv88e6xxx_port_set_cmode(chip, port, mode, false);
662de776d0dSPavana Sharma }
663de776d0dSPavana Sharma
mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip * chip,int port)6645d24da1eSVivien Didelot static int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip,
6655d24da1eSVivien Didelot int port)
6667a3007d2SMarek Behún {
6677a3007d2SMarek Behún int err, addr;
6687a3007d2SMarek Behún u16 reg, bits;
6697a3007d2SMarek Behún
6707a3007d2SMarek Behún if (port != 5)
6717a3007d2SMarek Behún return -EOPNOTSUPP;
6727a3007d2SMarek Behún
6737a3007d2SMarek Behún addr = chip->info->port_base_addr + port;
6747a3007d2SMarek Behún
6757a3007d2SMarek Behún err = mv88e6xxx_port_hidden_read(chip, 0x7, addr, 0, ®);
6767a3007d2SMarek Behún if (err)
6777a3007d2SMarek Behún return err;
6787a3007d2SMarek Behún
6797a3007d2SMarek Behún bits = MV88E6341_PORT_RESERVED_1A_FORCE_CMODE |
6807a3007d2SMarek Behún MV88E6341_PORT_RESERVED_1A_SGMII_AN;
6817a3007d2SMarek Behún
6827a3007d2SMarek Behún if ((reg & bits) == bits)
6837a3007d2SMarek Behún return 0;
6847a3007d2SMarek Behún
6857a3007d2SMarek Behún reg |= bits;
6867a3007d2SMarek Behún return mv88e6xxx_port_hidden_write(chip, 0x7, addr, 0, reg);
6877a3007d2SMarek Behún }
6887a3007d2SMarek Behún
mv88e6341_port_set_cmode(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)6897a3007d2SMarek Behún int mv88e6341_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
6907a3007d2SMarek Behún phy_interface_t mode)
6917a3007d2SMarek Behún {
6925d24da1eSVivien Didelot int err;
6935d24da1eSVivien Didelot
6947a3007d2SMarek Behún if (port != 5)
6957a3007d2SMarek Behún return -EOPNOTSUPP;
6967a3007d2SMarek Behún
6977a3007d2SMarek Behún switch (mode) {
6987a3007d2SMarek Behún case PHY_INTERFACE_MODE_NA:
6997a3007d2SMarek Behún return 0;
7007a3007d2SMarek Behún case PHY_INTERFACE_MODE_XGMII:
7017a3007d2SMarek Behún case PHY_INTERFACE_MODE_XAUI:
7027a3007d2SMarek Behún case PHY_INTERFACE_MODE_RXAUI:
7037a3007d2SMarek Behún return -EINVAL;
7047a3007d2SMarek Behún default:
7057a3007d2SMarek Behún break;
7067a3007d2SMarek Behún }
7077a3007d2SMarek Behún
7085d24da1eSVivien Didelot err = mv88e6341_port_set_cmode_writable(chip, port);
7095d24da1eSVivien Didelot if (err)
7105d24da1eSVivien Didelot return err;
7115d24da1eSVivien Didelot
712f7a48b68SBaruch Siach return mv88e6xxx_port_set_cmode(chip, port, mode, true);
713fdc71eeaSAndrew Lunn }
714fdc71eeaSAndrew Lunn
mv88e6185_port_get_cmode(struct mv88e6xxx_chip * chip,int port,u8 * cmode)7152d2e1dd2SAndrew Lunn int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
7166c422e34SRussell King {
7176c422e34SRussell King int err;
7186c422e34SRussell King u16 reg;
7196c422e34SRussell King
7206c422e34SRussell King err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®);
7216c422e34SRussell King if (err)
7226c422e34SRussell King return err;
7236c422e34SRussell King
7242d2e1dd2SAndrew Lunn *cmode = reg & MV88E6185_PORT_STS_CMODE_MASK;
7252d2e1dd2SAndrew Lunn
7262d2e1dd2SAndrew Lunn return 0;
7276c422e34SRussell King }
7286c422e34SRussell King
mv88e6352_port_get_cmode(struct mv88e6xxx_chip * chip,int port,u8 * cmode)7292d2e1dd2SAndrew Lunn int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
730f39908d3SAndrew Lunn {
731f39908d3SAndrew Lunn int err;
732f39908d3SAndrew Lunn u16 reg;
733f39908d3SAndrew Lunn
7345f83dc93SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®);
735f39908d3SAndrew Lunn if (err)
736f39908d3SAndrew Lunn return err;
737f39908d3SAndrew Lunn
7385f83dc93SVivien Didelot *cmode = reg & MV88E6XXX_PORT_STS_CMODE_MASK;
739f39908d3SAndrew Lunn
740f39908d3SAndrew Lunn return 0;
741f39908d3SAndrew Lunn }
742f39908d3SAndrew Lunn
7436c96bbfdSVivien Didelot /* Offset 0x02: Jamming Control
744b35d322aSAndrew Lunn *
745b35d322aSAndrew Lunn * Do not limit the period of time that this port can be paused for by
746b35d322aSAndrew Lunn * the remote end or the period of time that this port can pause the
747b35d322aSAndrew Lunn * remote end.
748b35d322aSAndrew Lunn */
mv88e6097_port_pause_limit(struct mv88e6xxx_chip * chip,int port,u8 in,u8 out)7490898432cSVivien Didelot int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
7500898432cSVivien Didelot u8 out)
751b35d322aSAndrew Lunn {
7526c96bbfdSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6097_PORT_JAM_CTL,
7536c96bbfdSVivien Didelot out << 8 | in);
754b35d322aSAndrew Lunn }
755b35d322aSAndrew Lunn
mv88e6390_port_pause_limit(struct mv88e6xxx_chip * chip,int port,u8 in,u8 out)7560898432cSVivien Didelot int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
7570898432cSVivien Didelot u8 out)
7583ce0e65eSAndrew Lunn {
7593ce0e65eSAndrew Lunn int err;
7603ce0e65eSAndrew Lunn
7616c96bbfdSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,
7626c96bbfdSVivien Didelot MV88E6390_PORT_FLOW_CTL_UPDATE |
7636c96bbfdSVivien Didelot MV88E6390_PORT_FLOW_CTL_LIMIT_IN | in);
7643ce0e65eSAndrew Lunn if (err)
7653ce0e65eSAndrew Lunn return err;
7663ce0e65eSAndrew Lunn
7676c96bbfdSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,
7686c96bbfdSVivien Didelot MV88E6390_PORT_FLOW_CTL_UPDATE |
7696c96bbfdSVivien Didelot MV88E6390_PORT_FLOW_CTL_LIMIT_OUT | out);
7703ce0e65eSAndrew Lunn }
7713ce0e65eSAndrew Lunn
772e28def33SVivien Didelot /* Offset 0x04: Port Control Register */
773e28def33SVivien Didelot
774e28def33SVivien Didelot static const char * const mv88e6xxx_port_state_names[] = {
775a89b433bSVivien Didelot [MV88E6XXX_PORT_CTL0_STATE_DISABLED] = "Disabled",
776a89b433bSVivien Didelot [MV88E6XXX_PORT_CTL0_STATE_BLOCKING] = "Blocking/Listening",
777a89b433bSVivien Didelot [MV88E6XXX_PORT_CTL0_STATE_LEARNING] = "Learning",
778a89b433bSVivien Didelot [MV88E6XXX_PORT_CTL0_STATE_FORWARDING] = "Forwarding",
779e28def33SVivien Didelot };
780e28def33SVivien Didelot
mv88e6xxx_port_set_state(struct mv88e6xxx_chip * chip,int port,u8 state)781e28def33SVivien Didelot int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state)
782e28def33SVivien Didelot {
783e28def33SVivien Didelot u16 reg;
784e28def33SVivien Didelot int err;
785e28def33SVivien Didelot
786a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);
787e28def33SVivien Didelot if (err)
788e28def33SVivien Didelot return err;
789e28def33SVivien Didelot
790a89b433bSVivien Didelot reg &= ~MV88E6XXX_PORT_CTL0_STATE_MASK;
791f894c29cSVivien Didelot
792f894c29cSVivien Didelot switch (state) {
793f894c29cSVivien Didelot case BR_STATE_DISABLED:
794a89b433bSVivien Didelot state = MV88E6XXX_PORT_CTL0_STATE_DISABLED;
795f894c29cSVivien Didelot break;
796f894c29cSVivien Didelot case BR_STATE_BLOCKING:
797f894c29cSVivien Didelot case BR_STATE_LISTENING:
798a89b433bSVivien Didelot state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING;
799f894c29cSVivien Didelot break;
800f894c29cSVivien Didelot case BR_STATE_LEARNING:
801a89b433bSVivien Didelot state = MV88E6XXX_PORT_CTL0_STATE_LEARNING;
802f894c29cSVivien Didelot break;
803f894c29cSVivien Didelot case BR_STATE_FORWARDING:
804a89b433bSVivien Didelot state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
805f894c29cSVivien Didelot break;
806f894c29cSVivien Didelot default:
807f894c29cSVivien Didelot return -EINVAL;
808f894c29cSVivien Didelot }
809f894c29cSVivien Didelot
810e28def33SVivien Didelot reg |= state;
811e28def33SVivien Didelot
812a89b433bSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
813e28def33SVivien Didelot if (err)
814e28def33SVivien Didelot return err;
815e28def33SVivien Didelot
816774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: PortState set to %s\n", port,
817e28def33SVivien Didelot mv88e6xxx_port_state_names[state]);
818e28def33SVivien Didelot
819e28def33SVivien Didelot return 0;
820e28def33SVivien Didelot }
8215a7921f4SVivien Didelot
mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip * chip,int port,enum mv88e6xxx_egress_mode mode)82256995cbcSAndrew Lunn int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port,
82331bef4e9SVivien Didelot enum mv88e6xxx_egress_mode mode)
82456995cbcSAndrew Lunn {
82556995cbcSAndrew Lunn int err;
82656995cbcSAndrew Lunn u16 reg;
82756995cbcSAndrew Lunn
828a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);
82956995cbcSAndrew Lunn if (err)
83056995cbcSAndrew Lunn return err;
83156995cbcSAndrew Lunn
832a89b433bSVivien Didelot reg &= ~MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK;
83331bef4e9SVivien Didelot
83431bef4e9SVivien Didelot switch (mode) {
83531bef4e9SVivien Didelot case MV88E6XXX_EGRESS_MODE_UNMODIFIED:
836a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED;
83731bef4e9SVivien Didelot break;
83831bef4e9SVivien Didelot case MV88E6XXX_EGRESS_MODE_UNTAGGED:
839a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED;
84031bef4e9SVivien Didelot break;
84131bef4e9SVivien Didelot case MV88E6XXX_EGRESS_MODE_TAGGED:
842a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED;
84331bef4e9SVivien Didelot break;
84431bef4e9SVivien Didelot case MV88E6XXX_EGRESS_MODE_ETHERTYPE:
845a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA;
84631bef4e9SVivien Didelot break;
84731bef4e9SVivien Didelot default:
84831bef4e9SVivien Didelot return -EINVAL;
84931bef4e9SVivien Didelot }
85056995cbcSAndrew Lunn
851a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
85256995cbcSAndrew Lunn }
85356995cbcSAndrew Lunn
mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip * chip,int port,enum mv88e6xxx_frame_mode mode)85456995cbcSAndrew Lunn int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
85556995cbcSAndrew Lunn enum mv88e6xxx_frame_mode mode)
85656995cbcSAndrew Lunn {
85756995cbcSAndrew Lunn int err;
85856995cbcSAndrew Lunn u16 reg;
85956995cbcSAndrew Lunn
860a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);
86156995cbcSAndrew Lunn if (err)
86256995cbcSAndrew Lunn return err;
86356995cbcSAndrew Lunn
864a89b433bSVivien Didelot reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;
86556995cbcSAndrew Lunn
86656995cbcSAndrew Lunn switch (mode) {
86756995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_NORMAL:
868a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;
86956995cbcSAndrew Lunn break;
87056995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_DSA:
871a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;
87256995cbcSAndrew Lunn break;
87356995cbcSAndrew Lunn default:
87456995cbcSAndrew Lunn return -EINVAL;
87556995cbcSAndrew Lunn }
87656995cbcSAndrew Lunn
877a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
87856995cbcSAndrew Lunn }
87956995cbcSAndrew Lunn
mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip * chip,int port,enum mv88e6xxx_frame_mode mode)88056995cbcSAndrew Lunn int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
88156995cbcSAndrew Lunn enum mv88e6xxx_frame_mode mode)
88256995cbcSAndrew Lunn {
88356995cbcSAndrew Lunn int err;
88456995cbcSAndrew Lunn u16 reg;
88556995cbcSAndrew Lunn
886a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);
88756995cbcSAndrew Lunn if (err)
88856995cbcSAndrew Lunn return err;
88956995cbcSAndrew Lunn
890a89b433bSVivien Didelot reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;
89156995cbcSAndrew Lunn
89256995cbcSAndrew Lunn switch (mode) {
89356995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_NORMAL:
894a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;
89556995cbcSAndrew Lunn break;
89656995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_DSA:
897a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;
89856995cbcSAndrew Lunn break;
89956995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_PROVIDER:
900a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_PROVIDER;
90156995cbcSAndrew Lunn break;
90256995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_ETHERTYPE:
903a89b433bSVivien Didelot reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_ETHER_TYPE_DSA;
90456995cbcSAndrew Lunn break;
90556995cbcSAndrew Lunn default:
90656995cbcSAndrew Lunn return -EINVAL;
90756995cbcSAndrew Lunn }
90856995cbcSAndrew Lunn
909a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
91056995cbcSAndrew Lunn }
91156995cbcSAndrew Lunn
mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip * chip,int port,bool unicast)912a8b659e7SVladimir Oltean int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip,
913601aeed3SVivien Didelot int port, bool unicast)
91456995cbcSAndrew Lunn {
91556995cbcSAndrew Lunn int err;
91656995cbcSAndrew Lunn u16 reg;
91756995cbcSAndrew Lunn
918a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);
91956995cbcSAndrew Lunn if (err)
92056995cbcSAndrew Lunn return err;
92156995cbcSAndrew Lunn
922601aeed3SVivien Didelot if (unicast)
923a89b433bSVivien Didelot reg |= MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;
92456995cbcSAndrew Lunn else
925a89b433bSVivien Didelot reg &= ~MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;
92656995cbcSAndrew Lunn
927a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
92856995cbcSAndrew Lunn }
92956995cbcSAndrew Lunn
mv88e6352_port_set_ucast_flood(struct mv88e6xxx_chip * chip,int port,bool unicast)930a8b659e7SVladimir Oltean int mv88e6352_port_set_ucast_flood(struct mv88e6xxx_chip *chip, int port,
931a8b659e7SVladimir Oltean bool unicast)
93256995cbcSAndrew Lunn {
93356995cbcSAndrew Lunn int err;
93456995cbcSAndrew Lunn u16 reg;
93556995cbcSAndrew Lunn
936a89b433bSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);
93756995cbcSAndrew Lunn if (err)
93856995cbcSAndrew Lunn return err;
93956995cbcSAndrew Lunn
940a8b659e7SVladimir Oltean if (unicast)
941a8b659e7SVladimir Oltean reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_UC;
94256995cbcSAndrew Lunn else
943a8b659e7SVladimir Oltean reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_UC;
944a8b659e7SVladimir Oltean
945a8b659e7SVladimir Oltean return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
946a8b659e7SVladimir Oltean }
947a8b659e7SVladimir Oltean
mv88e6352_port_set_mcast_flood(struct mv88e6xxx_chip * chip,int port,bool multicast)948a8b659e7SVladimir Oltean int mv88e6352_port_set_mcast_flood(struct mv88e6xxx_chip *chip, int port,
949a8b659e7SVladimir Oltean bool multicast)
950a8b659e7SVladimir Oltean {
951a8b659e7SVladimir Oltean int err;
952a8b659e7SVladimir Oltean u16 reg;
953a8b659e7SVladimir Oltean
954a8b659e7SVladimir Oltean err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);
955a8b659e7SVladimir Oltean if (err)
956a8b659e7SVladimir Oltean return err;
957a8b659e7SVladimir Oltean
958a8b659e7SVladimir Oltean if (multicast)
959a8b659e7SVladimir Oltean reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_MC;
960a8b659e7SVladimir Oltean else
961a8b659e7SVladimir Oltean reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MC;
96256995cbcSAndrew Lunn
963a89b433bSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
96456995cbcSAndrew Lunn }
96556995cbcSAndrew Lunn
966b4e48c50SVivien Didelot /* Offset 0x05: Port Control 1 */
967b4e48c50SVivien Didelot
mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip * chip,int port,bool message_port)968ea698f4fSVivien Didelot int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,
969ea698f4fSVivien Didelot bool message_port)
970ea698f4fSVivien Didelot {
971ea698f4fSVivien Didelot u16 val;
972ea698f4fSVivien Didelot int err;
973ea698f4fSVivien Didelot
974cd985bbfSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val);
975ea698f4fSVivien Didelot if (err)
976ea698f4fSVivien Didelot return err;
977ea698f4fSVivien Didelot
978ea698f4fSVivien Didelot if (message_port)
979cd985bbfSVivien Didelot val |= MV88E6XXX_PORT_CTL1_MESSAGE_PORT;
980ea698f4fSVivien Didelot else
981cd985bbfSVivien Didelot val &= ~MV88E6XXX_PORT_CTL1_MESSAGE_PORT;
982ea698f4fSVivien Didelot
983cd985bbfSVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val);
984ea698f4fSVivien Didelot }
985ea698f4fSVivien Didelot
mv88e6xxx_port_set_trunk(struct mv88e6xxx_chip * chip,int port,bool trunk,u8 id)98657e661aaSTobias Waldekranz int mv88e6xxx_port_set_trunk(struct mv88e6xxx_chip *chip, int port,
98757e661aaSTobias Waldekranz bool trunk, u8 id)
98857e661aaSTobias Waldekranz {
98957e661aaSTobias Waldekranz u16 val;
99057e661aaSTobias Waldekranz int err;
99157e661aaSTobias Waldekranz
99257e661aaSTobias Waldekranz err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val);
99357e661aaSTobias Waldekranz if (err)
99457e661aaSTobias Waldekranz return err;
99557e661aaSTobias Waldekranz
99657e661aaSTobias Waldekranz val &= ~MV88E6XXX_PORT_CTL1_TRUNK_ID_MASK;
99757e661aaSTobias Waldekranz
99857e661aaSTobias Waldekranz if (trunk)
99957e661aaSTobias Waldekranz val |= MV88E6XXX_PORT_CTL1_TRUNK_PORT |
100057e661aaSTobias Waldekranz (id << MV88E6XXX_PORT_CTL1_TRUNK_ID_SHIFT);
100157e661aaSTobias Waldekranz else
100257e661aaSTobias Waldekranz val &= ~MV88E6XXX_PORT_CTL1_TRUNK_PORT;
100357e661aaSTobias Waldekranz
100457e661aaSTobias Waldekranz return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val);
100557e661aaSTobias Waldekranz }
100657e661aaSTobias Waldekranz
10075a7921f4SVivien Didelot /* Offset 0x06: Port Based VLAN Map */
10085a7921f4SVivien Didelot
mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip * chip,int port,u16 map)10095a7921f4SVivien Didelot int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map)
10105a7921f4SVivien Didelot {
10114d294af2SVivien Didelot const u16 mask = mv88e6xxx_port_mask(chip);
10125a7921f4SVivien Didelot u16 reg;
10135a7921f4SVivien Didelot int err;
10145a7921f4SVivien Didelot
10157e5cc5f1SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®);
10165a7921f4SVivien Didelot if (err)
10175a7921f4SVivien Didelot return err;
10185a7921f4SVivien Didelot
10195a7921f4SVivien Didelot reg &= ~mask;
10205a7921f4SVivien Didelot reg |= map & mask;
10215a7921f4SVivien Didelot
10227e5cc5f1SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);
10235a7921f4SVivien Didelot if (err)
10245a7921f4SVivien Didelot return err;
10255a7921f4SVivien Didelot
1026774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: VLANTable set to %.3x\n", port, map);
10275a7921f4SVivien Didelot
10285a7921f4SVivien Didelot return 0;
10295a7921f4SVivien Didelot }
1030b4e48c50SVivien Didelot
mv88e6xxx_port_get_fid(struct mv88e6xxx_chip * chip,int port,u16 * fid)1031b4e48c50SVivien Didelot int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid)
1032b4e48c50SVivien Didelot {
1033b4e48c50SVivien Didelot const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
1034b4e48c50SVivien Didelot u16 reg;
1035b4e48c50SVivien Didelot int err;
1036b4e48c50SVivien Didelot
1037b4e48c50SVivien Didelot /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
10387e5cc5f1SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®);
1039b4e48c50SVivien Didelot if (err)
1040b4e48c50SVivien Didelot return err;
1041b4e48c50SVivien Didelot
1042b4e48c50SVivien Didelot *fid = (reg & 0xf000) >> 12;
1043b4e48c50SVivien Didelot
1044b4e48c50SVivien Didelot /* Port's default FID upper bits are located in reg 0x05, offset 0 */
1045b4e48c50SVivien Didelot if (upper_mask) {
1046cd985bbfSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,
1047cd985bbfSVivien Didelot ®);
1048b4e48c50SVivien Didelot if (err)
1049b4e48c50SVivien Didelot return err;
1050b4e48c50SVivien Didelot
1051b4e48c50SVivien Didelot *fid |= (reg & upper_mask) << 4;
1052b4e48c50SVivien Didelot }
1053b4e48c50SVivien Didelot
1054b4e48c50SVivien Didelot return 0;
1055b4e48c50SVivien Didelot }
1056b4e48c50SVivien Didelot
mv88e6xxx_port_set_fid(struct mv88e6xxx_chip * chip,int port,u16 fid)1057b4e48c50SVivien Didelot int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid)
1058b4e48c50SVivien Didelot {
1059b4e48c50SVivien Didelot const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
1060b4e48c50SVivien Didelot u16 reg;
1061b4e48c50SVivien Didelot int err;
1062b4e48c50SVivien Didelot
1063b4e48c50SVivien Didelot if (fid >= mv88e6xxx_num_databases(chip))
1064b4e48c50SVivien Didelot return -EINVAL;
1065b4e48c50SVivien Didelot
1066b4e48c50SVivien Didelot /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
10677e5cc5f1SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®);
1068b4e48c50SVivien Didelot if (err)
1069b4e48c50SVivien Didelot return err;
1070b4e48c50SVivien Didelot
1071b4e48c50SVivien Didelot reg &= 0x0fff;
1072b4e48c50SVivien Didelot reg |= (fid & 0x000f) << 12;
1073b4e48c50SVivien Didelot
10747e5cc5f1SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);
1075b4e48c50SVivien Didelot if (err)
1076b4e48c50SVivien Didelot return err;
1077b4e48c50SVivien Didelot
1078b4e48c50SVivien Didelot /* Port's default FID upper bits are located in reg 0x05, offset 0 */
1079b4e48c50SVivien Didelot if (upper_mask) {
1080cd985bbfSVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,
1081cd985bbfSVivien Didelot ®);
1082b4e48c50SVivien Didelot if (err)
1083b4e48c50SVivien Didelot return err;
1084b4e48c50SVivien Didelot
1085b4e48c50SVivien Didelot reg &= ~upper_mask;
1086b4e48c50SVivien Didelot reg |= (fid >> 4) & upper_mask;
1087b4e48c50SVivien Didelot
1088cd985bbfSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1,
1089cd985bbfSVivien Didelot reg);
1090b4e48c50SVivien Didelot if (err)
1091b4e48c50SVivien Didelot return err;
1092b4e48c50SVivien Didelot }
1093b4e48c50SVivien Didelot
1094774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: FID set to %u\n", port, fid);
1095b4e48c50SVivien Didelot
1096b4e48c50SVivien Didelot return 0;
1097b4e48c50SVivien Didelot }
109877064f37SVivien Didelot
109977064f37SVivien Didelot /* Offset 0x07: Default Port VLAN ID & Priority */
110077064f37SVivien Didelot
mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip * chip,int port,u16 * pvid)110177064f37SVivien Didelot int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid)
110277064f37SVivien Didelot {
110377064f37SVivien Didelot u16 reg;
110477064f37SVivien Didelot int err;
110577064f37SVivien Didelot
1106b7929fb3SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
1107b7929fb3SVivien Didelot ®);
110877064f37SVivien Didelot if (err)
110977064f37SVivien Didelot return err;
111077064f37SVivien Didelot
1111b7929fb3SVivien Didelot *pvid = reg & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
111277064f37SVivien Didelot
111377064f37SVivien Didelot return 0;
111477064f37SVivien Didelot }
111577064f37SVivien Didelot
mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip * chip,int port,u16 pvid)111677064f37SVivien Didelot int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid)
111777064f37SVivien Didelot {
111877064f37SVivien Didelot u16 reg;
111977064f37SVivien Didelot int err;
112077064f37SVivien Didelot
1121b7929fb3SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
1122b7929fb3SVivien Didelot ®);
112377064f37SVivien Didelot if (err)
112477064f37SVivien Didelot return err;
112577064f37SVivien Didelot
1126b7929fb3SVivien Didelot reg &= ~MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
1127b7929fb3SVivien Didelot reg |= pvid & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
112877064f37SVivien Didelot
1129b7929fb3SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
1130b7929fb3SVivien Didelot reg);
113177064f37SVivien Didelot if (err)
113277064f37SVivien Didelot return err;
113377064f37SVivien Didelot
1134774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: DefaultVID set to %u\n", port, pvid);
113577064f37SVivien Didelot
113677064f37SVivien Didelot return 0;
113777064f37SVivien Didelot }
1138385a0995SVivien Didelot
1139385a0995SVivien Didelot /* Offset 0x08: Port Control 2 Register */
1140385a0995SVivien Didelot
1141385a0995SVivien Didelot static const char * const mv88e6xxx_port_8021q_mode_names[] = {
114281c6edb2SVivien Didelot [MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED] = "Disabled",
114381c6edb2SVivien Didelot [MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK] = "Fallback",
114481c6edb2SVivien Didelot [MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK] = "Check",
114581c6edb2SVivien Didelot [MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure",
1146385a0995SVivien Didelot };
1147385a0995SVivien Didelot
mv88e6185_port_set_default_forward(struct mv88e6xxx_chip * chip,int port,bool multicast)1148a8b659e7SVladimir Oltean int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip,
1149601aeed3SVivien Didelot int port, bool multicast)
1150a23b2961SAndrew Lunn {
1151a23b2961SAndrew Lunn int err;
1152a23b2961SAndrew Lunn u16 reg;
1153a23b2961SAndrew Lunn
115481c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®);
1155a23b2961SAndrew Lunn if (err)
1156a23b2961SAndrew Lunn return err;
1157a23b2961SAndrew Lunn
1158601aeed3SVivien Didelot if (multicast)
115981c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;
1160a23b2961SAndrew Lunn else
116181c6edb2SVivien Didelot reg &= ~MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;
1162a23b2961SAndrew Lunn
116381c6edb2SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
1164a23b2961SAndrew Lunn }
1165a23b2961SAndrew Lunn
mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip * chip,int port,int upstream_port)1166a23b2961SAndrew Lunn int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
1167a23b2961SAndrew Lunn int upstream_port)
1168a23b2961SAndrew Lunn {
1169a23b2961SAndrew Lunn int err;
1170a23b2961SAndrew Lunn u16 reg;
1171a23b2961SAndrew Lunn
117281c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®);
1173a23b2961SAndrew Lunn if (err)
1174a23b2961SAndrew Lunn return err;
1175a23b2961SAndrew Lunn
117681c6edb2SVivien Didelot reg &= ~MV88E6095_PORT_CTL2_CPU_PORT_MASK;
1177a23b2961SAndrew Lunn reg |= upstream_port;
1178a23b2961SAndrew Lunn
117981c6edb2SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
1180a23b2961SAndrew Lunn }
1181a23b2961SAndrew Lunn
mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip * chip,int port,enum mv88e6xxx_egress_direction direction,bool mirror)1182f0942e00SIwan R Timmer int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
1183f0942e00SIwan R Timmer enum mv88e6xxx_egress_direction direction,
1184f0942e00SIwan R Timmer bool mirror)
1185f0942e00SIwan R Timmer {
1186f0942e00SIwan R Timmer bool *mirror_port;
1187f0942e00SIwan R Timmer u16 reg;
1188f0942e00SIwan R Timmer u16 bit;
1189f0942e00SIwan R Timmer int err;
1190f0942e00SIwan R Timmer
1191f0942e00SIwan R Timmer err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®);
1192f0942e00SIwan R Timmer if (err)
1193f0942e00SIwan R Timmer return err;
1194f0942e00SIwan R Timmer
1195f0942e00SIwan R Timmer switch (direction) {
1196f0942e00SIwan R Timmer case MV88E6XXX_EGRESS_DIR_INGRESS:
1197f0942e00SIwan R Timmer bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR;
1198f0942e00SIwan R Timmer mirror_port = &chip->ports[port].mirror_ingress;
1199f0942e00SIwan R Timmer break;
1200f0942e00SIwan R Timmer case MV88E6XXX_EGRESS_DIR_EGRESS:
1201f0942e00SIwan R Timmer bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR;
1202f0942e00SIwan R Timmer mirror_port = &chip->ports[port].mirror_egress;
1203f0942e00SIwan R Timmer break;
1204f0942e00SIwan R Timmer default:
1205f0942e00SIwan R Timmer return -EINVAL;
1206f0942e00SIwan R Timmer }
1207f0942e00SIwan R Timmer
1208f0942e00SIwan R Timmer reg &= ~bit;
1209f0942e00SIwan R Timmer if (mirror)
1210f0942e00SIwan R Timmer reg |= bit;
1211f0942e00SIwan R Timmer
1212f0942e00SIwan R Timmer err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
1213f0942e00SIwan R Timmer if (!err)
1214f0942e00SIwan R Timmer *mirror_port = mirror;
1215f0942e00SIwan R Timmer
1216f0942e00SIwan R Timmer return err;
1217f0942e00SIwan R Timmer }
1218f0942e00SIwan R Timmer
mv88e6xxx_port_set_lock(struct mv88e6xxx_chip * chip,int port,bool locked)121934ea415fSHans Schultz int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,
122034ea415fSHans Schultz bool locked)
122134ea415fSHans Schultz {
122234ea415fSHans Schultz u16 reg;
122334ea415fSHans Schultz int err;
122434ea415fSHans Schultz
122534ea415fSHans Schultz err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®);
122634ea415fSHans Schultz if (err)
122734ea415fSHans Schultz return err;
122834ea415fSHans Schultz
122934ea415fSHans Schultz reg &= ~MV88E6XXX_PORT_CTL0_SA_FILT_MASK;
123034ea415fSHans Schultz if (locked)
123134ea415fSHans Schultz reg |= MV88E6XXX_PORT_CTL0_SA_FILT_DROP_ON_LOCK;
123234ea415fSHans Schultz
123334ea415fSHans Schultz err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
123434ea415fSHans Schultz if (err)
123534ea415fSHans Schultz return err;
123634ea415fSHans Schultz
123734ea415fSHans Schultz err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, ®);
123834ea415fSHans Schultz if (err)
123934ea415fSHans Schultz return err;
124034ea415fSHans Schultz
124134ea415fSHans Schultz reg &= ~MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;
124234ea415fSHans Schultz if (locked)
124334ea415fSHans Schultz reg |= MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;
124434ea415fSHans Schultz
124534ea415fSHans Schultz return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, reg);
124634ea415fSHans Schultz }
124734ea415fSHans Schultz
mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip * chip,int port,u16 mode)1248385a0995SVivien Didelot int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
1249385a0995SVivien Didelot u16 mode)
1250385a0995SVivien Didelot {
1251385a0995SVivien Didelot u16 reg;
1252385a0995SVivien Didelot int err;
1253385a0995SVivien Didelot
125481c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®);
1255385a0995SVivien Didelot if (err)
1256385a0995SVivien Didelot return err;
1257385a0995SVivien Didelot
125881c6edb2SVivien Didelot reg &= ~MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;
125981c6edb2SVivien Didelot reg |= mode & MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;
1260385a0995SVivien Didelot
126181c6edb2SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
1262385a0995SVivien Didelot if (err)
1263385a0995SVivien Didelot return err;
1264385a0995SVivien Didelot
1265774439e5SVivien Didelot dev_dbg(chip->dev, "p%d: 802.1QMode set to %s\n", port,
1266385a0995SVivien Didelot mv88e6xxx_port_8021q_mode_names[mode]);
1267385a0995SVivien Didelot
1268385a0995SVivien Didelot return 0;
1269385a0995SVivien Didelot }
1270ef0a7318SAndrew Lunn
mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip * chip,int port,bool drop_untagged)12718b6836d8SVladimir Oltean int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,
12728b6836d8SVladimir Oltean bool drop_untagged)
12738b6836d8SVladimir Oltean {
12748b6836d8SVladimir Oltean u16 old, new;
12758b6836d8SVladimir Oltean int err;
12768b6836d8SVladimir Oltean
12778b6836d8SVladimir Oltean err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &old);
12788b6836d8SVladimir Oltean if (err)
12798b6836d8SVladimir Oltean return err;
12808b6836d8SVladimir Oltean
12818b6836d8SVladimir Oltean if (drop_untagged)
12828b6836d8SVladimir Oltean new = old | MV88E6XXX_PORT_CTL2_DISCARD_UNTAGGED;
12838b6836d8SVladimir Oltean else
12848b6836d8SVladimir Oltean new = old & ~MV88E6XXX_PORT_CTL2_DISCARD_UNTAGGED;
12858b6836d8SVladimir Oltean
12868b6836d8SVladimir Oltean if (new == old)
12878b6836d8SVladimir Oltean return 0;
12888b6836d8SVladimir Oltean
12898b6836d8SVladimir Oltean return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, new);
12908b6836d8SVladimir Oltean }
12918b6836d8SVladimir Oltean
mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip * chip,int port,bool map)12927af4a361STobias Waldekranz int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port, bool map)
1293a23b2961SAndrew Lunn {
1294a23b2961SAndrew Lunn u16 reg;
1295a23b2961SAndrew Lunn int err;
1296a23b2961SAndrew Lunn
129781c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®);
1298a23b2961SAndrew Lunn if (err)
1299a23b2961SAndrew Lunn return err;
1300a23b2961SAndrew Lunn
13017af4a361STobias Waldekranz if (map)
130281c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_MAP_DA;
13037af4a361STobias Waldekranz else
13047af4a361STobias Waldekranz reg &= ~MV88E6XXX_PORT_CTL2_MAP_DA;
1305a23b2961SAndrew Lunn
130681c6edb2SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
1307a23b2961SAndrew Lunn }
1308a23b2961SAndrew Lunn
mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip * chip,int port,size_t size)1309cd782656SVivien Didelot int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,
1310cd782656SVivien Didelot size_t size)
13115f436666SAndrew Lunn {
13125f436666SAndrew Lunn u16 reg;
13135f436666SAndrew Lunn int err;
13145f436666SAndrew Lunn
1315b92ce2f5SAndrew Lunn size += VLAN_ETH_HLEN + ETH_FCS_LEN;
1316b92ce2f5SAndrew Lunn
131781c6edb2SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®);
13185f436666SAndrew Lunn if (err)
13195f436666SAndrew Lunn return err;
13205f436666SAndrew Lunn
132181c6edb2SVivien Didelot reg &= ~MV88E6XXX_PORT_CTL2_JUMBO_MODE_MASK;
1322cd782656SVivien Didelot
1323cd782656SVivien Didelot if (size <= 1522)
132481c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_1522;
1325cd782656SVivien Didelot else if (size <= 2048)
132681c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_2048;
1327cd782656SVivien Didelot else if (size <= 10240)
132881c6edb2SVivien Didelot reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_10240;
1329cd782656SVivien Didelot else
1330cd782656SVivien Didelot return -ERANGE;
13315f436666SAndrew Lunn
133281c6edb2SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
13335f436666SAndrew Lunn }
13345f436666SAndrew Lunn
1335ef70b111SAndrew Lunn /* Offset 0x09: Port Rate Control */
1336ef70b111SAndrew Lunn
mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip * chip,int port)1337ef70b111SAndrew Lunn int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
1338ef70b111SAndrew Lunn {
13392cb8cb14SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,
13402cb8cb14SVivien Didelot 0x0000);
1341ef70b111SAndrew Lunn }
1342ef70b111SAndrew Lunn
mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip * chip,int port)1343ef70b111SAndrew Lunn int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
1344ef70b111SAndrew Lunn {
13452cb8cb14SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,
13462cb8cb14SVivien Didelot 0x0001);
1347ef70b111SAndrew Lunn }
1348ef70b111SAndrew Lunn
1349041bd545STobias Waldekranz /* Offset 0x0B: Port Association Vector */
1350041bd545STobias Waldekranz
mv88e6xxx_port_set_assoc_vector(struct mv88e6xxx_chip * chip,int port,u16 pav)1351041bd545STobias Waldekranz int mv88e6xxx_port_set_assoc_vector(struct mv88e6xxx_chip *chip, int port,
1352041bd545STobias Waldekranz u16 pav)
1353041bd545STobias Waldekranz {
1354041bd545STobias Waldekranz u16 reg, mask;
1355041bd545STobias Waldekranz int err;
1356041bd545STobias Waldekranz
1357041bd545STobias Waldekranz err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
1358041bd545STobias Waldekranz ®);
1359041bd545STobias Waldekranz if (err)
1360041bd545STobias Waldekranz return err;
1361041bd545STobias Waldekranz
1362041bd545STobias Waldekranz mask = mv88e6xxx_port_mask(chip);
1363041bd545STobias Waldekranz reg &= ~mask;
1364041bd545STobias Waldekranz reg |= pav & mask;
1365041bd545STobias Waldekranz
1366041bd545STobias Waldekranz return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
1367041bd545STobias Waldekranz reg);
1368041bd545STobias Waldekranz }
1369041bd545STobias Waldekranz
1370c8c94891SVivien Didelot /* Offset 0x0C: Port ATU Control */
1371c8c94891SVivien Didelot
mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip * chip,int port)1372c8c94891SVivien Didelot int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port)
1373c8c94891SVivien Didelot {
1374b8109594SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ATU_CTL, 0);
1375c8c94891SVivien Didelot }
1376c8c94891SVivien Didelot
13779dbfb4e1SVivien Didelot /* Offset 0x0D: (Priority) Override Register */
13789dbfb4e1SVivien Didelot
mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip * chip,int port)13799dbfb4e1SVivien Didelot int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port)
13809dbfb4e1SVivien Didelot {
1381b8109594SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0);
13829dbfb4e1SVivien Didelot }
13839dbfb4e1SVivien Didelot
1384de776d0dSPavana Sharma /* Offset 0x0E: Policy & MGMT Control Register for FAMILY 6191X 6193X 6393X */
1385de776d0dSPavana Sharma
mv88e6393x_port_policy_read(struct mv88e6xxx_chip * chip,int port,u16 pointer,u8 * data)13866584b260SMarek Behún static int mv88e6393x_port_policy_read(struct mv88e6xxx_chip *chip, int port,
13876584b260SMarek Behún u16 pointer, u8 *data)
13886584b260SMarek Behún {
13896584b260SMarek Behún u16 reg;
13906584b260SMarek Behún int err;
13916584b260SMarek Behún
13926584b260SMarek Behún err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL,
13936584b260SMarek Behún pointer);
13946584b260SMarek Behún if (err)
13956584b260SMarek Behún return err;
13966584b260SMarek Behún
13976584b260SMarek Behún err = mv88e6xxx_port_read(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL,
13986584b260SMarek Behún ®);
13996584b260SMarek Behún if (err)
14006584b260SMarek Behún return err;
14016584b260SMarek Behún
14026584b260SMarek Behún *data = reg;
14036584b260SMarek Behún
14046584b260SMarek Behún return 0;
14056584b260SMarek Behún }
14066584b260SMarek Behún
mv88e6393x_port_policy_write(struct mv88e6xxx_chip * chip,int port,u16 pointer,u8 data)1407de776d0dSPavana Sharma static int mv88e6393x_port_policy_write(struct mv88e6xxx_chip *chip, int port,
1408de776d0dSPavana Sharma u16 pointer, u8 data)
1409de776d0dSPavana Sharma {
1410de776d0dSPavana Sharma u16 reg;
1411de776d0dSPavana Sharma
1412de776d0dSPavana Sharma reg = MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE | pointer | data;
1413de776d0dSPavana Sharma
1414de776d0dSPavana Sharma return mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL,
1415de776d0dSPavana Sharma reg);
1416de776d0dSPavana Sharma }
1417de776d0dSPavana Sharma
mv88e6393x_port_policy_write_all(struct mv88e6xxx_chip * chip,u16 pointer,u8 data)1418de776d0dSPavana Sharma static int mv88e6393x_port_policy_write_all(struct mv88e6xxx_chip *chip,
1419de776d0dSPavana Sharma u16 pointer, u8 data)
1420de776d0dSPavana Sharma {
1421de776d0dSPavana Sharma int err, port;
1422de776d0dSPavana Sharma
1423de776d0dSPavana Sharma for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
1424de776d0dSPavana Sharma if (dsa_is_unused_port(chip->ds, port))
1425de776d0dSPavana Sharma continue;
1426de776d0dSPavana Sharma
1427de776d0dSPavana Sharma err = mv88e6393x_port_policy_write(chip, port, pointer, data);
1428de776d0dSPavana Sharma if (err)
1429de776d0dSPavana Sharma return err;
1430de776d0dSPavana Sharma }
1431de776d0dSPavana Sharma
1432de776d0dSPavana Sharma return 0;
1433de776d0dSPavana Sharma }
1434de776d0dSPavana Sharma
mv88e6393x_set_egress_port(struct mv88e6xxx_chip * chip,enum mv88e6xxx_egress_direction direction,int port)1435de776d0dSPavana Sharma int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip,
1436de776d0dSPavana Sharma enum mv88e6xxx_egress_direction direction,
1437de776d0dSPavana Sharma int port)
1438de776d0dSPavana Sharma {
1439de776d0dSPavana Sharma u16 ptr;
1440de776d0dSPavana Sharma int err;
1441de776d0dSPavana Sharma
1442de776d0dSPavana Sharma switch (direction) {
1443de776d0dSPavana Sharma case MV88E6XXX_EGRESS_DIR_INGRESS:
1444de776d0dSPavana Sharma ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_INGRESS_DEST;
1445de776d0dSPavana Sharma err = mv88e6393x_port_policy_write_all(chip, ptr, port);
1446de776d0dSPavana Sharma if (err)
1447de776d0dSPavana Sharma return err;
1448de776d0dSPavana Sharma break;
1449de776d0dSPavana Sharma case MV88E6XXX_EGRESS_DIR_EGRESS:
1450de776d0dSPavana Sharma ptr = MV88E6393X_G2_EGRESS_MONITOR_DEST;
1451de776d0dSPavana Sharma err = mv88e6xxx_g2_write(chip, ptr, port);
1452de776d0dSPavana Sharma if (err)
1453de776d0dSPavana Sharma return err;
1454de776d0dSPavana Sharma break;
1455de776d0dSPavana Sharma }
1456de776d0dSPavana Sharma
1457de776d0dSPavana Sharma return 0;
1458de776d0dSPavana Sharma }
1459de776d0dSPavana Sharma
mv88e6393x_port_set_upstream_port(struct mv88e6xxx_chip * chip,int port,int upstream_port)1460de776d0dSPavana Sharma int mv88e6393x_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
1461de776d0dSPavana Sharma int upstream_port)
1462de776d0dSPavana Sharma {
1463de776d0dSPavana Sharma u16 ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_CPU_DEST;
1464de776d0dSPavana Sharma u8 data = MV88E6393X_PORT_POLICY_MGMT_CTL_CPU_DEST_MGMTPRI |
1465de776d0dSPavana Sharma upstream_port;
1466de776d0dSPavana Sharma
1467de776d0dSPavana Sharma return mv88e6393x_port_policy_write(chip, port, ptr, data);
1468de776d0dSPavana Sharma }
1469de776d0dSPavana Sharma
mv88e6393x_port_mgmt_rsvd2cpu(struct mv88e6xxx_chip * chip)1470de776d0dSPavana Sharma int mv88e6393x_port_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
1471de776d0dSPavana Sharma {
1472de776d0dSPavana Sharma u16 ptr;
1473de776d0dSPavana Sharma int err;
1474de776d0dSPavana Sharma
1475de776d0dSPavana Sharma /* Consider the frames with reserved multicast destination
1476de776d0dSPavana Sharma * addresses matching 01:80:c2:00:00:00 and
1477de776d0dSPavana Sharma * 01:80:c2:00:00:02 as MGMT.
1478de776d0dSPavana Sharma */
1479de776d0dSPavana Sharma ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XLO;
1480de776d0dSPavana Sharma err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);
1481de776d0dSPavana Sharma if (err)
1482de776d0dSPavana Sharma return err;
1483de776d0dSPavana Sharma
1484de776d0dSPavana Sharma ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XHI;
1485de776d0dSPavana Sharma err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);
1486de776d0dSPavana Sharma if (err)
1487de776d0dSPavana Sharma return err;
1488de776d0dSPavana Sharma
1489de776d0dSPavana Sharma ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XLO;
1490de776d0dSPavana Sharma err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);
1491de776d0dSPavana Sharma if (err)
1492de776d0dSPavana Sharma return err;
1493de776d0dSPavana Sharma
1494de776d0dSPavana Sharma ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XHI;
1495de776d0dSPavana Sharma err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);
1496de776d0dSPavana Sharma if (err)
1497de776d0dSPavana Sharma return err;
1498de776d0dSPavana Sharma
1499de776d0dSPavana Sharma return 0;
1500de776d0dSPavana Sharma }
1501de776d0dSPavana Sharma
1502de776d0dSPavana Sharma /* Offset 0x10 & 0x11: EPC */
1503de776d0dSPavana Sharma
mv88e6393x_port_epc_wait_ready(struct mv88e6xxx_chip * chip,int port)1504de776d0dSPavana Sharma static int mv88e6393x_port_epc_wait_ready(struct mv88e6xxx_chip *chip, int port)
1505de776d0dSPavana Sharma {
1506de776d0dSPavana Sharma int bit = __bf_shf(MV88E6393X_PORT_EPC_CMD_BUSY);
1507de776d0dSPavana Sharma
1508de776d0dSPavana Sharma return mv88e6xxx_port_wait_bit(chip, port, MV88E6393X_PORT_EPC_CMD, bit, 0);
1509de776d0dSPavana Sharma }
1510de776d0dSPavana Sharma
1511de776d0dSPavana Sharma /* Port Ether type for 6393X family */
1512de776d0dSPavana Sharma
mv88e6393x_port_set_ether_type(struct mv88e6xxx_chip * chip,int port,u16 etype)1513de776d0dSPavana Sharma int mv88e6393x_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
1514de776d0dSPavana Sharma u16 etype)
1515de776d0dSPavana Sharma {
1516de776d0dSPavana Sharma u16 val;
1517de776d0dSPavana Sharma int err;
1518de776d0dSPavana Sharma
1519de776d0dSPavana Sharma err = mv88e6393x_port_epc_wait_ready(chip, port);
1520de776d0dSPavana Sharma if (err)
1521de776d0dSPavana Sharma return err;
1522de776d0dSPavana Sharma
1523de776d0dSPavana Sharma err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_DATA, etype);
1524de776d0dSPavana Sharma if (err)
1525de776d0dSPavana Sharma return err;
1526de776d0dSPavana Sharma
1527de776d0dSPavana Sharma val = MV88E6393X_PORT_EPC_CMD_BUSY |
1528de776d0dSPavana Sharma MV88E6393X_PORT_EPC_CMD_WRITE |
1529de776d0dSPavana Sharma MV88E6393X_PORT_EPC_INDEX_PORT_ETYPE;
1530de776d0dSPavana Sharma
1531de776d0dSPavana Sharma return mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_CMD, val);
1532de776d0dSPavana Sharma }
1533de776d0dSPavana Sharma
153456995cbcSAndrew Lunn /* Offset 0x0f: Port Ether type */
153556995cbcSAndrew Lunn
mv88e6351_port_set_ether_type(struct mv88e6xxx_chip * chip,int port,u16 etype)153656995cbcSAndrew Lunn int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
153756995cbcSAndrew Lunn u16 etype)
153856995cbcSAndrew Lunn {
1539b8109594SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype);
154056995cbcSAndrew Lunn }
154156995cbcSAndrew Lunn
1542ef0a7318SAndrew Lunn /* Offset 0x18: Port IEEE Priority Remapping Registers [0-3]
1543ef0a7318SAndrew Lunn * Offset 0x19: Port IEEE Priority Remapping Registers [4-7]
1544ef0a7318SAndrew Lunn */
1545ef0a7318SAndrew Lunn
mv88e6095_port_tag_remap(struct mv88e6xxx_chip * chip,int port)1546ef0a7318SAndrew Lunn int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
1547ef0a7318SAndrew Lunn {
1548ef0a7318SAndrew Lunn int err;
1549ef0a7318SAndrew Lunn
1550ef0a7318SAndrew Lunn /* Use a direct priority mapping for all IEEE tagged frames */
15518009df9eSVivien Didelot err = mv88e6xxx_port_write(chip, port,
15528009df9eSVivien Didelot MV88E6095_PORT_IEEE_PRIO_REMAP_0123,
15538009df9eSVivien Didelot 0x3210);
1554ef0a7318SAndrew Lunn if (err)
1555ef0a7318SAndrew Lunn return err;
1556ef0a7318SAndrew Lunn
15578009df9eSVivien Didelot return mv88e6xxx_port_write(chip, port,
15588009df9eSVivien Didelot MV88E6095_PORT_IEEE_PRIO_REMAP_4567,
15598009df9eSVivien Didelot 0x7654);
1560ef0a7318SAndrew Lunn }
1561ef0a7318SAndrew Lunn
mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip * chip,int port,u16 table,u8 ptr,u16 data)1562ef0a7318SAndrew Lunn static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip,
1563ddcbabf4SVivien Didelot int port, u16 table, u8 ptr, u16 data)
1564ef0a7318SAndrew Lunn {
1565ef0a7318SAndrew Lunn u16 reg;
1566ef0a7318SAndrew Lunn
1567ddcbabf4SVivien Didelot reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE | table |
1568ddcbabf4SVivien Didelot (ptr << __bf_shf(MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_PTR_MASK)) |
1569ddcbabf4SVivien Didelot (data & MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_DATA_MASK);
1570ef0a7318SAndrew Lunn
15718009df9eSVivien Didelot return mv88e6xxx_port_write(chip, port,
15728009df9eSVivien Didelot MV88E6390_PORT_IEEE_PRIO_MAP_TABLE, reg);
1573ef0a7318SAndrew Lunn }
1574ef0a7318SAndrew Lunn
mv88e6390_port_tag_remap(struct mv88e6xxx_chip * chip,int port)1575ef0a7318SAndrew Lunn int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
1576ef0a7318SAndrew Lunn {
1577ef0a7318SAndrew Lunn int err, i;
15788009df9eSVivien Didelot u16 table;
1579ef0a7318SAndrew Lunn
1580ef0a7318SAndrew Lunn for (i = 0; i <= 7; i++) {
15818009df9eSVivien Didelot table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP;
15828009df9eSVivien Didelot err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i,
15838009df9eSVivien Didelot (i | i << 4));
1584ef0a7318SAndrew Lunn if (err)
1585ef0a7318SAndrew Lunn return err;
1586ef0a7318SAndrew Lunn
15878009df9eSVivien Didelot table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP;
15888009df9eSVivien Didelot err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
1589ef0a7318SAndrew Lunn if (err)
1590ef0a7318SAndrew Lunn return err;
1591ef0a7318SAndrew Lunn
15928009df9eSVivien Didelot table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP;
15938009df9eSVivien Didelot err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
1594ef0a7318SAndrew Lunn if (err)
1595ef0a7318SAndrew Lunn return err;
1596ef0a7318SAndrew Lunn
15978009df9eSVivien Didelot table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP;
15988009df9eSVivien Didelot err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
1599ef0a7318SAndrew Lunn if (err)
1600ef0a7318SAndrew Lunn return err;
1601ef0a7318SAndrew Lunn }
1602ef0a7318SAndrew Lunn
1603ef0a7318SAndrew Lunn return 0;
1604ef0a7318SAndrew Lunn }
1605f3a2cd32SVivien Didelot
1606f3a2cd32SVivien Didelot /* Offset 0x0E: Policy Control Register */
1607f3a2cd32SVivien Didelot
16086584b260SMarek Behún static int
mv88e6xxx_port_policy_mapping_get_pos(enum mv88e6xxx_policy_mapping mapping,enum mv88e6xxx_policy_action action,u16 * mask,u16 * val,int * shift)16096584b260SMarek Behún mv88e6xxx_port_policy_mapping_get_pos(enum mv88e6xxx_policy_mapping mapping,
16106584b260SMarek Behún enum mv88e6xxx_policy_action action,
16116584b260SMarek Behún u16 *mask, u16 *val, int *shift)
16126584b260SMarek Behún {
16136584b260SMarek Behún switch (mapping) {
16146584b260SMarek Behún case MV88E6XXX_POLICY_MAPPING_DA:
16156584b260SMarek Behún *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_DA_MASK);
16166584b260SMarek Behún *mask = MV88E6XXX_PORT_POLICY_CTL_DA_MASK;
16176584b260SMarek Behún break;
16186584b260SMarek Behún case MV88E6XXX_POLICY_MAPPING_SA:
16196584b260SMarek Behún *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_SA_MASK);
16206584b260SMarek Behún *mask = MV88E6XXX_PORT_POLICY_CTL_SA_MASK;
16216584b260SMarek Behún break;
16226584b260SMarek Behún case MV88E6XXX_POLICY_MAPPING_VTU:
16236584b260SMarek Behún *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VTU_MASK);
16246584b260SMarek Behún *mask = MV88E6XXX_PORT_POLICY_CTL_VTU_MASK;
16256584b260SMarek Behún break;
16266584b260SMarek Behún case MV88E6XXX_POLICY_MAPPING_ETYPE:
16276584b260SMarek Behún *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK);
16286584b260SMarek Behún *mask = MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK;
16296584b260SMarek Behún break;
16306584b260SMarek Behún case MV88E6XXX_POLICY_MAPPING_PPPOE:
16316584b260SMarek Behún *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK);
16326584b260SMarek Behún *mask = MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK;
16336584b260SMarek Behún break;
16346584b260SMarek Behún case MV88E6XXX_POLICY_MAPPING_VBAS:
16356584b260SMarek Behún *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK);
16366584b260SMarek Behún *mask = MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK;
16376584b260SMarek Behún break;
16386584b260SMarek Behún case MV88E6XXX_POLICY_MAPPING_OPT82:
16396584b260SMarek Behún *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK);
16406584b260SMarek Behún *mask = MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK;
16416584b260SMarek Behún break;
16426584b260SMarek Behún case MV88E6XXX_POLICY_MAPPING_UDP:
16436584b260SMarek Behún *shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_UDP_MASK);
16446584b260SMarek Behún *mask = MV88E6XXX_PORT_POLICY_CTL_UDP_MASK;
16456584b260SMarek Behún break;
16466584b260SMarek Behún default:
16476584b260SMarek Behún return -EOPNOTSUPP;
16486584b260SMarek Behún }
16496584b260SMarek Behún
16506584b260SMarek Behún switch (action) {
16516584b260SMarek Behún case MV88E6XXX_POLICY_ACTION_NORMAL:
16526584b260SMarek Behún *val = MV88E6XXX_PORT_POLICY_CTL_NORMAL;
16536584b260SMarek Behún break;
16546584b260SMarek Behún case MV88E6XXX_POLICY_ACTION_MIRROR:
16556584b260SMarek Behún *val = MV88E6XXX_PORT_POLICY_CTL_MIRROR;
16566584b260SMarek Behún break;
16576584b260SMarek Behún case MV88E6XXX_POLICY_ACTION_TRAP:
16586584b260SMarek Behún *val = MV88E6XXX_PORT_POLICY_CTL_TRAP;
16596584b260SMarek Behún break;
16606584b260SMarek Behún case MV88E6XXX_POLICY_ACTION_DISCARD:
16616584b260SMarek Behún *val = MV88E6XXX_PORT_POLICY_CTL_DISCARD;
16626584b260SMarek Behún break;
16636584b260SMarek Behún default:
16646584b260SMarek Behún return -EOPNOTSUPP;
16656584b260SMarek Behún }
16666584b260SMarek Behún
16676584b260SMarek Behún return 0;
16686584b260SMarek Behún }
16696584b260SMarek Behún
mv88e6352_port_set_policy(struct mv88e6xxx_chip * chip,int port,enum mv88e6xxx_policy_mapping mapping,enum mv88e6xxx_policy_action action)1670f3a2cd32SVivien Didelot int mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port,
1671f3a2cd32SVivien Didelot enum mv88e6xxx_policy_mapping mapping,
1672f3a2cd32SVivien Didelot enum mv88e6xxx_policy_action action)
1673f3a2cd32SVivien Didelot {
1674f3a2cd32SVivien Didelot u16 reg, mask, val;
1675f3a2cd32SVivien Didelot int shift;
1676f3a2cd32SVivien Didelot int err;
1677f3a2cd32SVivien Didelot
16786584b260SMarek Behún err = mv88e6xxx_port_policy_mapping_get_pos(mapping, action, &mask,
16796584b260SMarek Behún &val, &shift);
16806584b260SMarek Behún if (err)
16816584b260SMarek Behún return err;
1682f3a2cd32SVivien Didelot
1683f3a2cd32SVivien Didelot err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_POLICY_CTL, ®);
1684f3a2cd32SVivien Didelot if (err)
1685f3a2cd32SVivien Didelot return err;
1686f3a2cd32SVivien Didelot
1687f3a2cd32SVivien Didelot reg &= ~mask;
1688f3a2cd32SVivien Didelot reg |= (val << shift) & mask;
1689f3a2cd32SVivien Didelot
1690f3a2cd32SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_POLICY_CTL, reg);
1691f3a2cd32SVivien Didelot }
16926584b260SMarek Behún
mv88e6393x_port_set_policy(struct mv88e6xxx_chip * chip,int port,enum mv88e6xxx_policy_mapping mapping,enum mv88e6xxx_policy_action action)16936584b260SMarek Behún int mv88e6393x_port_set_policy(struct mv88e6xxx_chip *chip, int port,
16946584b260SMarek Behún enum mv88e6xxx_policy_mapping mapping,
16956584b260SMarek Behún enum mv88e6xxx_policy_action action)
16966584b260SMarek Behún {
16976584b260SMarek Behún u16 mask, val;
16986584b260SMarek Behún int shift;
16996584b260SMarek Behún int err;
17006584b260SMarek Behún u16 ptr;
17016584b260SMarek Behún u8 reg;
17026584b260SMarek Behún
17036584b260SMarek Behún err = mv88e6xxx_port_policy_mapping_get_pos(mapping, action, &mask,
17046584b260SMarek Behún &val, &shift);
17056584b260SMarek Behún if (err)
17066584b260SMarek Behún return err;
17076584b260SMarek Behún
17086584b260SMarek Behún /* The 16-bit Port Policy CTL register from older chips is on 6393x
17096584b260SMarek Behún * changed to Port Policy MGMT CTL, which can access more data, but
17106584b260SMarek Behún * indirectly. The original 16-bit value is divided into two 8-bit
17116584b260SMarek Behún * registers.
17126584b260SMarek Behún */
17136584b260SMarek Behún ptr = shift / 8;
17146584b260SMarek Behún shift %= 8;
17156584b260SMarek Behún mask >>= ptr * 8;
1716*12bc1494SPeter Rashleigh ptr <<= 8;
17176584b260SMarek Behún
17186584b260SMarek Behún err = mv88e6393x_port_policy_read(chip, port, ptr, ®);
17196584b260SMarek Behún if (err)
17206584b260SMarek Behún return err;
17216584b260SMarek Behún
17226584b260SMarek Behún reg &= ~mask;
17236584b260SMarek Behún reg |= (val << shift) & mask;
17246584b260SMarek Behún
17256584b260SMarek Behún return mv88e6393x_port_policy_write(chip, port, ptr, reg);
17266584b260SMarek Behún }
1727