xref: /linux/drivers/net/dsa/mv88e6xxx/port.c (revision 12bc1494)
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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 					  &reg);
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, &reg);
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 					  &reg);
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 				  &reg);
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 				  &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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 				  &reg);
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 				  &reg);
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, &reg);
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, &reg);
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