xref: /OK3568_Linux_fs/kernel/drivers/net/dsa/mv88e6xxx/port.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Marvell 88E6xxx Switch Port Registers support
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2008 Marvell Semiconductor
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
8*4882a593Smuzhiyun  *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/bitfield.h>
12*4882a593Smuzhiyun #include <linux/if_bridge.h>
13*4882a593Smuzhiyun #include <linux/phy.h>
14*4882a593Smuzhiyun #include <linux/phylink.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include "chip.h"
17*4882a593Smuzhiyun #include "port.h"
18*4882a593Smuzhiyun #include "serdes.h"
19*4882a593Smuzhiyun 
mv88e6xxx_port_read(struct mv88e6xxx_chip * chip,int port,int reg,u16 * val)20*4882a593Smuzhiyun int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
21*4882a593Smuzhiyun 			u16 *val)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun 	int addr = chip->info->port_base_addr + port;
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	return mv88e6xxx_read(chip, addr, reg, val);
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun 
mv88e6xxx_port_write(struct mv88e6xxx_chip * chip,int port,int reg,u16 val)28*4882a593Smuzhiyun int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
29*4882a593Smuzhiyun 			 u16 val)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun 	int addr = chip->info->port_base_addr + port;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	return mv88e6xxx_write(chip, addr, reg, val);
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /* Offset 0x00: MAC (or PCS or Physical) Status Register
37*4882a593Smuzhiyun  *
38*4882a593Smuzhiyun  * For most devices, this is read only. However the 6185 has the MyPause
39*4882a593Smuzhiyun  * bit read/write.
40*4882a593Smuzhiyun  */
mv88e6185_port_set_pause(struct mv88e6xxx_chip * chip,int port,int pause)41*4882a593Smuzhiyun int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
42*4882a593Smuzhiyun 			     int pause)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun 	u16 reg;
45*4882a593Smuzhiyun 	int err;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
48*4882a593Smuzhiyun 	if (err)
49*4882a593Smuzhiyun 		return err;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	if (pause)
52*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_STS_MY_PAUSE;
53*4882a593Smuzhiyun 	else
54*4882a593Smuzhiyun 		reg &= ~MV88E6XXX_PORT_STS_MY_PAUSE;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /* Offset 0x01: MAC (or PCS or Physical) Control Register
60*4882a593Smuzhiyun  *
61*4882a593Smuzhiyun  * Link, Duplex and Flow Control have one force bit, one value bit.
62*4882a593Smuzhiyun  *
63*4882a593Smuzhiyun  * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value.
64*4882a593Smuzhiyun  * Alternative values require the 200BASE (or AltSpeed) bit 12 set.
65*4882a593Smuzhiyun  * Newer chips need a ForcedSpd bit 13 set to consider the value.
66*4882a593Smuzhiyun  */
67*4882a593Smuzhiyun 
mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)68*4882a593Smuzhiyun static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
69*4882a593Smuzhiyun 					  phy_interface_t mode)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun 	u16 reg;
72*4882a593Smuzhiyun 	int err;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
75*4882a593Smuzhiyun 	if (err)
76*4882a593Smuzhiyun 		return err;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	reg &= ~(MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
79*4882a593Smuzhiyun 		 MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	switch (mode) {
82*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_RGMII_RXID:
83*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK;
84*4882a593Smuzhiyun 		break;
85*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_RGMII_TXID:
86*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
87*4882a593Smuzhiyun 		break;
88*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_RGMII_ID:
89*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
90*4882a593Smuzhiyun 			MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
91*4882a593Smuzhiyun 		break;
92*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_RGMII:
93*4882a593Smuzhiyun 		break;
94*4882a593Smuzhiyun 	default:
95*4882a593Smuzhiyun 		return 0;
96*4882a593Smuzhiyun 	}
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
99*4882a593Smuzhiyun 	if (err)
100*4882a593Smuzhiyun 		return err;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	dev_dbg(chip->dev, "p%d: delay RXCLK %s, TXCLK %s\n", port,
103*4882a593Smuzhiyun 		reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK ? "yes" : "no",
104*4882a593Smuzhiyun 		reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK ? "yes" : "no");
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	return 0;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)109*4882a593Smuzhiyun int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
110*4882a593Smuzhiyun 				   phy_interface_t mode)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	if (port < 5)
113*4882a593Smuzhiyun 		return -EOPNOTSUPP;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)118*4882a593Smuzhiyun int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
119*4882a593Smuzhiyun 				   phy_interface_t mode)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	if (port != 0)
122*4882a593Smuzhiyun 		return -EOPNOTSUPP;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
mv88e6xxx_port_set_link(struct mv88e6xxx_chip * chip,int port,int link)127*4882a593Smuzhiyun int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	u16 reg;
130*4882a593Smuzhiyun 	int err;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
133*4882a593Smuzhiyun 	if (err)
134*4882a593Smuzhiyun 		return err;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
137*4882a593Smuzhiyun 		 MV88E6XXX_PORT_MAC_CTL_LINK_UP);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	switch (link) {
140*4882a593Smuzhiyun 	case LINK_FORCED_DOWN:
141*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK;
142*4882a593Smuzhiyun 		break;
143*4882a593Smuzhiyun 	case LINK_FORCED_UP:
144*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
145*4882a593Smuzhiyun 			MV88E6XXX_PORT_MAC_CTL_LINK_UP;
146*4882a593Smuzhiyun 		break;
147*4882a593Smuzhiyun 	case LINK_UNFORCED:
148*4882a593Smuzhiyun 		/* normal link detection */
149*4882a593Smuzhiyun 		break;
150*4882a593Smuzhiyun 	default:
151*4882a593Smuzhiyun 		return -EINVAL;
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
155*4882a593Smuzhiyun 	if (err)
156*4882a593Smuzhiyun 		return err;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	dev_dbg(chip->dev, "p%d: %s link %s\n", port,
159*4882a593Smuzhiyun 		reg & MV88E6XXX_PORT_MAC_CTL_FORCE_LINK ? "Force" : "Unforce",
160*4882a593Smuzhiyun 		reg & MV88E6XXX_PORT_MAC_CTL_LINK_UP ? "up" : "down");
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	return 0;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip * chip,int port,int speed,bool alt_bit,bool force_bit,int duplex)165*4882a593Smuzhiyun static int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip,
166*4882a593Smuzhiyun 					   int port, int speed, bool alt_bit,
167*4882a593Smuzhiyun 					   bool force_bit, int duplex)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	u16 reg, ctrl;
170*4882a593Smuzhiyun 	int err;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	switch (speed) {
173*4882a593Smuzhiyun 	case 10:
174*4882a593Smuzhiyun 		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;
175*4882a593Smuzhiyun 		break;
176*4882a593Smuzhiyun 	case 100:
177*4882a593Smuzhiyun 		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;
178*4882a593Smuzhiyun 		break;
179*4882a593Smuzhiyun 	case 200:
180*4882a593Smuzhiyun 		if (alt_bit)
181*4882a593Smuzhiyun 			ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |
182*4882a593Smuzhiyun 				MV88E6390_PORT_MAC_CTL_ALTSPEED;
183*4882a593Smuzhiyun 		else
184*4882a593Smuzhiyun 			ctrl = MV88E6065_PORT_MAC_CTL_SPEED_200;
185*4882a593Smuzhiyun 		break;
186*4882a593Smuzhiyun 	case 1000:
187*4882a593Smuzhiyun 		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;
188*4882a593Smuzhiyun 		break;
189*4882a593Smuzhiyun 	case 2500:
190*4882a593Smuzhiyun 		if (alt_bit)
191*4882a593Smuzhiyun 			ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
192*4882a593Smuzhiyun 				MV88E6390_PORT_MAC_CTL_ALTSPEED;
193*4882a593Smuzhiyun 		else
194*4882a593Smuzhiyun 			ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000;
195*4882a593Smuzhiyun 		break;
196*4882a593Smuzhiyun 	case 10000:
197*4882a593Smuzhiyun 		/* all bits set, fall through... */
198*4882a593Smuzhiyun 	case SPEED_UNFORCED:
199*4882a593Smuzhiyun 		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;
200*4882a593Smuzhiyun 		break;
201*4882a593Smuzhiyun 	default:
202*4882a593Smuzhiyun 		return -EOPNOTSUPP;
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	switch (duplex) {
206*4882a593Smuzhiyun 	case DUPLEX_HALF:
207*4882a593Smuzhiyun 		ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;
208*4882a593Smuzhiyun 		break;
209*4882a593Smuzhiyun 	case DUPLEX_FULL:
210*4882a593Smuzhiyun 		ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
211*4882a593Smuzhiyun 			MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;
212*4882a593Smuzhiyun 		break;
213*4882a593Smuzhiyun 	case DUPLEX_UNFORCED:
214*4882a593Smuzhiyun 		/* normal duplex detection */
215*4882a593Smuzhiyun 		break;
216*4882a593Smuzhiyun 	default:
217*4882a593Smuzhiyun 		return -EOPNOTSUPP;
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
221*4882a593Smuzhiyun 	if (err)
222*4882a593Smuzhiyun 		return err;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |
225*4882a593Smuzhiyun 		 MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
226*4882a593Smuzhiyun 		 MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	if (alt_bit)
229*4882a593Smuzhiyun 		reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED;
230*4882a593Smuzhiyun 	if (force_bit) {
231*4882a593Smuzhiyun 		reg &= ~MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
232*4882a593Smuzhiyun 		if (speed != SPEED_UNFORCED)
233*4882a593Smuzhiyun 			ctrl |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
234*4882a593Smuzhiyun 	}
235*4882a593Smuzhiyun 	reg |= ctrl;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
238*4882a593Smuzhiyun 	if (err)
239*4882a593Smuzhiyun 		return err;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	if (speed)
242*4882a593Smuzhiyun 		dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);
243*4882a593Smuzhiyun 	else
244*4882a593Smuzhiyun 		dev_dbg(chip->dev, "p%d: Speed unforced\n", port);
245*4882a593Smuzhiyun 	dev_dbg(chip->dev, "p%d: %s %s duplex\n", port,
246*4882a593Smuzhiyun 		reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce",
247*4882a593Smuzhiyun 		reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half");
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	return 0;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun /* Support 10, 100, 200 Mbps (e.g. 88E6065 family) */
mv88e6065_port_set_speed_duplex(struct mv88e6xxx_chip * chip,int port,int speed,int duplex)253*4882a593Smuzhiyun int mv88e6065_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
254*4882a593Smuzhiyun 				    int speed, int duplex)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun 	if (speed == SPEED_MAX)
257*4882a593Smuzhiyun 		speed = 200;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	if (speed > 200)
260*4882a593Smuzhiyun 		return -EOPNOTSUPP;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	/* Setting 200 Mbps on port 0 to 3 selects 100 Mbps */
263*4882a593Smuzhiyun 	return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false,
264*4882a593Smuzhiyun 					       duplex);
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun /* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */
mv88e6185_port_set_speed_duplex(struct mv88e6xxx_chip * chip,int port,int speed,int duplex)268*4882a593Smuzhiyun int mv88e6185_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
269*4882a593Smuzhiyun 				    int speed, int duplex)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	if (speed == SPEED_MAX)
272*4882a593Smuzhiyun 		speed = 1000;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	if (speed == 200 || speed > 1000)
275*4882a593Smuzhiyun 		return -EOPNOTSUPP;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false,
278*4882a593Smuzhiyun 					       duplex);
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun /* Support 10, 100 Mbps (e.g. 88E6250 family) */
mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip * chip,int port,int speed,int duplex)282*4882a593Smuzhiyun int mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
283*4882a593Smuzhiyun 				    int speed, int duplex)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	if (speed == SPEED_MAX)
286*4882a593Smuzhiyun 		speed = 100;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	if (speed > 100)
289*4882a593Smuzhiyun 		return -EOPNOTSUPP;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false,
292*4882a593Smuzhiyun 					       duplex);
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun /* 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)296*4882a593Smuzhiyun int mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
297*4882a593Smuzhiyun 				    int speed, int duplex)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	if (speed == SPEED_MAX)
300*4882a593Smuzhiyun 		speed = port < 5 ? 1000 : 2500;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	if (speed > 2500)
303*4882a593Smuzhiyun 		return -EOPNOTSUPP;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	if (speed == 200 && port != 0)
306*4882a593Smuzhiyun 		return -EOPNOTSUPP;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	if (speed == 2500 && port < 5)
309*4882a593Smuzhiyun 		return -EOPNOTSUPP;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	return mv88e6xxx_port_set_speed_duplex(chip, port, speed, !port, true,
312*4882a593Smuzhiyun 					       duplex);
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
mv88e6341_port_max_speed_mode(int port)315*4882a593Smuzhiyun phy_interface_t mv88e6341_port_max_speed_mode(int port)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun 	if (port == 5)
318*4882a593Smuzhiyun 		return PHY_INTERFACE_MODE_2500BASEX;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	return PHY_INTERFACE_MODE_NA;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun /* 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)324*4882a593Smuzhiyun int mv88e6352_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
325*4882a593Smuzhiyun 				    int speed, int duplex)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun 	if (speed == SPEED_MAX)
328*4882a593Smuzhiyun 		speed = 1000;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	if (speed > 1000)
331*4882a593Smuzhiyun 		return -EOPNOTSUPP;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	if (speed == 200 && port < 5)
334*4882a593Smuzhiyun 		return -EOPNOTSUPP;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, false,
337*4882a593Smuzhiyun 					       duplex);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun /* 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)341*4882a593Smuzhiyun int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
342*4882a593Smuzhiyun 				    int speed, int duplex)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun 	if (speed == SPEED_MAX)
345*4882a593Smuzhiyun 		speed = port < 9 ? 1000 : 2500;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	if (speed > 2500)
348*4882a593Smuzhiyun 		return -EOPNOTSUPP;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	if (speed == 200 && port != 0)
351*4882a593Smuzhiyun 		return -EOPNOTSUPP;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	if (speed == 2500 && port < 9)
354*4882a593Smuzhiyun 		return -EOPNOTSUPP;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true,
357*4882a593Smuzhiyun 					       duplex);
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun 
mv88e6390_port_max_speed_mode(int port)360*4882a593Smuzhiyun phy_interface_t mv88e6390_port_max_speed_mode(int port)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun 	if (port == 9 || port == 10)
363*4882a593Smuzhiyun 		return PHY_INTERFACE_MODE_2500BASEX;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	return PHY_INTERFACE_MODE_NA;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun /* 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)369*4882a593Smuzhiyun int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
370*4882a593Smuzhiyun 				     int speed, int duplex)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	if (speed == SPEED_MAX)
373*4882a593Smuzhiyun 		speed = port < 9 ? 1000 : 10000;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	if (speed == 200 && port != 0)
376*4882a593Smuzhiyun 		return -EOPNOTSUPP;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	if (speed >= 2500 && port < 9)
379*4882a593Smuzhiyun 		return -EOPNOTSUPP;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true,
382*4882a593Smuzhiyun 					       duplex);
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun 
mv88e6390x_port_max_speed_mode(int port)385*4882a593Smuzhiyun phy_interface_t mv88e6390x_port_max_speed_mode(int port)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun 	if (port == 9 || port == 10)
388*4882a593Smuzhiyun 		return PHY_INTERFACE_MODE_XAUI;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	return PHY_INTERFACE_MODE_NA;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun 
mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode,bool force)393*4882a593Smuzhiyun static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
394*4882a593Smuzhiyun 				    phy_interface_t mode, bool force)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun 	u8 lane;
397*4882a593Smuzhiyun 	u16 cmode;
398*4882a593Smuzhiyun 	u16 reg;
399*4882a593Smuzhiyun 	int err;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	/* Default to a slow mode, so freeing up SERDES interfaces for
402*4882a593Smuzhiyun 	 * other ports which might use them for SFPs.
403*4882a593Smuzhiyun 	 */
404*4882a593Smuzhiyun 	if (mode == PHY_INTERFACE_MODE_NA)
405*4882a593Smuzhiyun 		mode = PHY_INTERFACE_MODE_1000BASEX;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	switch (mode) {
408*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_1000BASEX:
409*4882a593Smuzhiyun 		cmode = MV88E6XXX_PORT_STS_CMODE_1000BASEX;
410*4882a593Smuzhiyun 		break;
411*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_SGMII:
412*4882a593Smuzhiyun 		cmode = MV88E6XXX_PORT_STS_CMODE_SGMII;
413*4882a593Smuzhiyun 		break;
414*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_2500BASEX:
415*4882a593Smuzhiyun 		cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
416*4882a593Smuzhiyun 		break;
417*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_XGMII:
418*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_XAUI:
419*4882a593Smuzhiyun 		cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
420*4882a593Smuzhiyun 		break;
421*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_RXAUI:
422*4882a593Smuzhiyun 		cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI;
423*4882a593Smuzhiyun 		break;
424*4882a593Smuzhiyun 	default:
425*4882a593Smuzhiyun 		cmode = 0;
426*4882a593Smuzhiyun 	}
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	/* cmode doesn't change, nothing to do for us unless forced */
429*4882a593Smuzhiyun 	if (cmode == chip->ports[port].cmode && !force)
430*4882a593Smuzhiyun 		return 0;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	lane = mv88e6xxx_serdes_get_lane(chip, port);
433*4882a593Smuzhiyun 	if (lane) {
434*4882a593Smuzhiyun 		if (chip->ports[port].serdes_irq) {
435*4882a593Smuzhiyun 			err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
436*4882a593Smuzhiyun 			if (err)
437*4882a593Smuzhiyun 				return err;
438*4882a593Smuzhiyun 		}
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 		err = mv88e6xxx_serdes_power_down(chip, port, lane);
441*4882a593Smuzhiyun 		if (err)
442*4882a593Smuzhiyun 			return err;
443*4882a593Smuzhiyun 	}
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	chip->ports[port].cmode = 0;
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	if (cmode) {
448*4882a593Smuzhiyun 		err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
449*4882a593Smuzhiyun 		if (err)
450*4882a593Smuzhiyun 			return err;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 		reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK;
453*4882a593Smuzhiyun 		reg |= cmode;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 		err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
456*4882a593Smuzhiyun 		if (err)
457*4882a593Smuzhiyun 			return err;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 		chip->ports[port].cmode = cmode;
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 		lane = mv88e6xxx_serdes_get_lane(chip, port);
462*4882a593Smuzhiyun 		if (!lane)
463*4882a593Smuzhiyun 			return -ENODEV;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 		err = mv88e6xxx_serdes_power_up(chip, port, lane);
466*4882a593Smuzhiyun 		if (err)
467*4882a593Smuzhiyun 			return err;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 		if (chip->ports[port].serdes_irq) {
470*4882a593Smuzhiyun 			err = mv88e6xxx_serdes_irq_enable(chip, port, lane);
471*4882a593Smuzhiyun 			if (err)
472*4882a593Smuzhiyun 				return err;
473*4882a593Smuzhiyun 		}
474*4882a593Smuzhiyun 	}
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	return 0;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun 
mv88e6390x_port_set_cmode(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)479*4882a593Smuzhiyun int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
480*4882a593Smuzhiyun 			      phy_interface_t mode)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun 	if (port != 9 && port != 10)
483*4882a593Smuzhiyun 		return -EOPNOTSUPP;
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	return mv88e6xxx_port_set_cmode(chip, port, mode, false);
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun 
mv88e6390_port_set_cmode(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)488*4882a593Smuzhiyun int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
489*4882a593Smuzhiyun 			     phy_interface_t mode)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun 	if (port != 9 && port != 10)
492*4882a593Smuzhiyun 		return -EOPNOTSUPP;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	switch (mode) {
495*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_NA:
496*4882a593Smuzhiyun 		return 0;
497*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_XGMII:
498*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_XAUI:
499*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_RXAUI:
500*4882a593Smuzhiyun 		return -EINVAL;
501*4882a593Smuzhiyun 	default:
502*4882a593Smuzhiyun 		break;
503*4882a593Smuzhiyun 	}
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	return mv88e6xxx_port_set_cmode(chip, port, mode, false);
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun 
mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip * chip,int port)508*4882a593Smuzhiyun static int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip,
509*4882a593Smuzhiyun 					     int port)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun 	int err, addr;
512*4882a593Smuzhiyun 	u16 reg, bits;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	if (port != 5)
515*4882a593Smuzhiyun 		return -EOPNOTSUPP;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	addr = chip->info->port_base_addr + port;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	err = mv88e6xxx_port_hidden_read(chip, 0x7, addr, 0, &reg);
520*4882a593Smuzhiyun 	if (err)
521*4882a593Smuzhiyun 		return err;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	bits = MV88E6341_PORT_RESERVED_1A_FORCE_CMODE |
524*4882a593Smuzhiyun 	       MV88E6341_PORT_RESERVED_1A_SGMII_AN;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	if ((reg & bits) == bits)
527*4882a593Smuzhiyun 		return 0;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	reg |= bits;
530*4882a593Smuzhiyun 	return mv88e6xxx_port_hidden_write(chip, 0x7, addr, 0, reg);
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun 
mv88e6341_port_set_cmode(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)533*4882a593Smuzhiyun int mv88e6341_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
534*4882a593Smuzhiyun 			     phy_interface_t mode)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun 	int err;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	if (port != 5)
539*4882a593Smuzhiyun 		return -EOPNOTSUPP;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	switch (mode) {
542*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_NA:
543*4882a593Smuzhiyun 		return 0;
544*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_XGMII:
545*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_XAUI:
546*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_RXAUI:
547*4882a593Smuzhiyun 		return -EINVAL;
548*4882a593Smuzhiyun 	default:
549*4882a593Smuzhiyun 		break;
550*4882a593Smuzhiyun 	}
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	err = mv88e6341_port_set_cmode_writable(chip, port);
553*4882a593Smuzhiyun 	if (err)
554*4882a593Smuzhiyun 		return err;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	return mv88e6xxx_port_set_cmode(chip, port, mode, true);
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun 
mv88e6185_port_get_cmode(struct mv88e6xxx_chip * chip,int port,u8 * cmode)559*4882a593Smuzhiyun int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun 	int err;
562*4882a593Smuzhiyun 	u16 reg;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
565*4882a593Smuzhiyun 	if (err)
566*4882a593Smuzhiyun 		return err;
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	*cmode = reg & MV88E6185_PORT_STS_CMODE_MASK;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	return 0;
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun 
mv88e6352_port_get_cmode(struct mv88e6xxx_chip * chip,int port,u8 * cmode)573*4882a593Smuzhiyun int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun 	int err;
576*4882a593Smuzhiyun 	u16 reg;
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
579*4882a593Smuzhiyun 	if (err)
580*4882a593Smuzhiyun 		return err;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	*cmode = reg & MV88E6XXX_PORT_STS_CMODE_MASK;
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	return 0;
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun /* Offset 0x02: Jamming Control
588*4882a593Smuzhiyun  *
589*4882a593Smuzhiyun  * Do not limit the period of time that this port can be paused for by
590*4882a593Smuzhiyun  * the remote end or the period of time that this port can pause the
591*4882a593Smuzhiyun  * remote end.
592*4882a593Smuzhiyun  */
mv88e6097_port_pause_limit(struct mv88e6xxx_chip * chip,int port,u8 in,u8 out)593*4882a593Smuzhiyun int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
594*4882a593Smuzhiyun 			       u8 out)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6097_PORT_JAM_CTL,
597*4882a593Smuzhiyun 				    out << 8 | in);
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun 
mv88e6390_port_pause_limit(struct mv88e6xxx_chip * chip,int port,u8 in,u8 out)600*4882a593Smuzhiyun int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
601*4882a593Smuzhiyun 			       u8 out)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun 	int err;
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	err = mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,
606*4882a593Smuzhiyun 				   MV88E6390_PORT_FLOW_CTL_UPDATE |
607*4882a593Smuzhiyun 				   MV88E6390_PORT_FLOW_CTL_LIMIT_IN | in);
608*4882a593Smuzhiyun 	if (err)
609*4882a593Smuzhiyun 		return err;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,
612*4882a593Smuzhiyun 				    MV88E6390_PORT_FLOW_CTL_UPDATE |
613*4882a593Smuzhiyun 				    MV88E6390_PORT_FLOW_CTL_LIMIT_OUT | out);
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun /* Offset 0x04: Port Control Register */
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun static const char * const mv88e6xxx_port_state_names[] = {
619*4882a593Smuzhiyun 	[MV88E6XXX_PORT_CTL0_STATE_DISABLED] = "Disabled",
620*4882a593Smuzhiyun 	[MV88E6XXX_PORT_CTL0_STATE_BLOCKING] = "Blocking/Listening",
621*4882a593Smuzhiyun 	[MV88E6XXX_PORT_CTL0_STATE_LEARNING] = "Learning",
622*4882a593Smuzhiyun 	[MV88E6XXX_PORT_CTL0_STATE_FORWARDING] = "Forwarding",
623*4882a593Smuzhiyun };
624*4882a593Smuzhiyun 
mv88e6xxx_port_set_state(struct mv88e6xxx_chip * chip,int port,u8 state)625*4882a593Smuzhiyun int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state)
626*4882a593Smuzhiyun {
627*4882a593Smuzhiyun 	u16 reg;
628*4882a593Smuzhiyun 	int err;
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
631*4882a593Smuzhiyun 	if (err)
632*4882a593Smuzhiyun 		return err;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	reg &= ~MV88E6XXX_PORT_CTL0_STATE_MASK;
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	switch (state) {
637*4882a593Smuzhiyun 	case BR_STATE_DISABLED:
638*4882a593Smuzhiyun 		state = MV88E6XXX_PORT_CTL0_STATE_DISABLED;
639*4882a593Smuzhiyun 		break;
640*4882a593Smuzhiyun 	case BR_STATE_BLOCKING:
641*4882a593Smuzhiyun 	case BR_STATE_LISTENING:
642*4882a593Smuzhiyun 		state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING;
643*4882a593Smuzhiyun 		break;
644*4882a593Smuzhiyun 	case BR_STATE_LEARNING:
645*4882a593Smuzhiyun 		state = MV88E6XXX_PORT_CTL0_STATE_LEARNING;
646*4882a593Smuzhiyun 		break;
647*4882a593Smuzhiyun 	case BR_STATE_FORWARDING:
648*4882a593Smuzhiyun 		state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
649*4882a593Smuzhiyun 		break;
650*4882a593Smuzhiyun 	default:
651*4882a593Smuzhiyun 		return -EINVAL;
652*4882a593Smuzhiyun 	}
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	reg |= state;
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
657*4882a593Smuzhiyun 	if (err)
658*4882a593Smuzhiyun 		return err;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	dev_dbg(chip->dev, "p%d: PortState set to %s\n", port,
661*4882a593Smuzhiyun 		mv88e6xxx_port_state_names[state]);
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	return 0;
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun 
mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip * chip,int port,enum mv88e6xxx_egress_mode mode)666*4882a593Smuzhiyun int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port,
667*4882a593Smuzhiyun 				   enum mv88e6xxx_egress_mode mode)
668*4882a593Smuzhiyun {
669*4882a593Smuzhiyun 	int err;
670*4882a593Smuzhiyun 	u16 reg;
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
673*4882a593Smuzhiyun 	if (err)
674*4882a593Smuzhiyun 		return err;
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	reg &= ~MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK;
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	switch (mode) {
679*4882a593Smuzhiyun 	case MV88E6XXX_EGRESS_MODE_UNMODIFIED:
680*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED;
681*4882a593Smuzhiyun 		break;
682*4882a593Smuzhiyun 	case MV88E6XXX_EGRESS_MODE_UNTAGGED:
683*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED;
684*4882a593Smuzhiyun 		break;
685*4882a593Smuzhiyun 	case MV88E6XXX_EGRESS_MODE_TAGGED:
686*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED;
687*4882a593Smuzhiyun 		break;
688*4882a593Smuzhiyun 	case MV88E6XXX_EGRESS_MODE_ETHERTYPE:
689*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA;
690*4882a593Smuzhiyun 		break;
691*4882a593Smuzhiyun 	default:
692*4882a593Smuzhiyun 		return -EINVAL;
693*4882a593Smuzhiyun 	}
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun 
mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip * chip,int port,enum mv88e6xxx_frame_mode mode)698*4882a593Smuzhiyun int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
699*4882a593Smuzhiyun 				  enum mv88e6xxx_frame_mode mode)
700*4882a593Smuzhiyun {
701*4882a593Smuzhiyun 	int err;
702*4882a593Smuzhiyun 	u16 reg;
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
705*4882a593Smuzhiyun 	if (err)
706*4882a593Smuzhiyun 		return err;
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	switch (mode) {
711*4882a593Smuzhiyun 	case MV88E6XXX_FRAME_MODE_NORMAL:
712*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;
713*4882a593Smuzhiyun 		break;
714*4882a593Smuzhiyun 	case MV88E6XXX_FRAME_MODE_DSA:
715*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;
716*4882a593Smuzhiyun 		break;
717*4882a593Smuzhiyun 	default:
718*4882a593Smuzhiyun 		return -EINVAL;
719*4882a593Smuzhiyun 	}
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun 
mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip * chip,int port,enum mv88e6xxx_frame_mode mode)724*4882a593Smuzhiyun int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
725*4882a593Smuzhiyun 				  enum mv88e6xxx_frame_mode mode)
726*4882a593Smuzhiyun {
727*4882a593Smuzhiyun 	int err;
728*4882a593Smuzhiyun 	u16 reg;
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
731*4882a593Smuzhiyun 	if (err)
732*4882a593Smuzhiyun 		return err;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	switch (mode) {
737*4882a593Smuzhiyun 	case MV88E6XXX_FRAME_MODE_NORMAL:
738*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;
739*4882a593Smuzhiyun 		break;
740*4882a593Smuzhiyun 	case MV88E6XXX_FRAME_MODE_DSA:
741*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;
742*4882a593Smuzhiyun 		break;
743*4882a593Smuzhiyun 	case MV88E6XXX_FRAME_MODE_PROVIDER:
744*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_PROVIDER;
745*4882a593Smuzhiyun 		break;
746*4882a593Smuzhiyun 	case MV88E6XXX_FRAME_MODE_ETHERTYPE:
747*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_ETHER_TYPE_DSA;
748*4882a593Smuzhiyun 		break;
749*4882a593Smuzhiyun 	default:
750*4882a593Smuzhiyun 		return -EINVAL;
751*4882a593Smuzhiyun 	}
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
754*4882a593Smuzhiyun }
755*4882a593Smuzhiyun 
mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip * chip,int port,bool unicast)756*4882a593Smuzhiyun static int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip,
757*4882a593Smuzhiyun 					      int port, bool unicast)
758*4882a593Smuzhiyun {
759*4882a593Smuzhiyun 	int err;
760*4882a593Smuzhiyun 	u16 reg;
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
763*4882a593Smuzhiyun 	if (err)
764*4882a593Smuzhiyun 		return err;
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	if (unicast)
767*4882a593Smuzhiyun 		reg |= MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;
768*4882a593Smuzhiyun 	else
769*4882a593Smuzhiyun 		reg &= ~MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
772*4882a593Smuzhiyun }
773*4882a593Smuzhiyun 
mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip * chip,int port,bool unicast,bool multicast)774*4882a593Smuzhiyun int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
775*4882a593Smuzhiyun 				     bool unicast, bool multicast)
776*4882a593Smuzhiyun {
777*4882a593Smuzhiyun 	int err;
778*4882a593Smuzhiyun 	u16 reg;
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
781*4882a593Smuzhiyun 	if (err)
782*4882a593Smuzhiyun 		return err;
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MASK;
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	if (unicast && multicast)
787*4882a593Smuzhiyun 		reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_ALL_UNKNOWN_DA;
788*4882a593Smuzhiyun 	else if (unicast)
789*4882a593Smuzhiyun 		reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_MC_DA;
790*4882a593Smuzhiyun 	else if (multicast)
791*4882a593Smuzhiyun 		reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_UC_DA;
792*4882a593Smuzhiyun 	else
793*4882a593Smuzhiyun 		reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_DA;
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
796*4882a593Smuzhiyun }
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun /* Offset 0x05: Port Control 1 */
799*4882a593Smuzhiyun 
mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip * chip,int port,bool message_port)800*4882a593Smuzhiyun int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,
801*4882a593Smuzhiyun 				    bool message_port)
802*4882a593Smuzhiyun {
803*4882a593Smuzhiyun 	u16 val;
804*4882a593Smuzhiyun 	int err;
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val);
807*4882a593Smuzhiyun 	if (err)
808*4882a593Smuzhiyun 		return err;
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	if (message_port)
811*4882a593Smuzhiyun 		val |= MV88E6XXX_PORT_CTL1_MESSAGE_PORT;
812*4882a593Smuzhiyun 	else
813*4882a593Smuzhiyun 		val &= ~MV88E6XXX_PORT_CTL1_MESSAGE_PORT;
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val);
816*4882a593Smuzhiyun }
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun /* Offset 0x06: Port Based VLAN Map */
819*4882a593Smuzhiyun 
mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip * chip,int port,u16 map)820*4882a593Smuzhiyun int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map)
821*4882a593Smuzhiyun {
822*4882a593Smuzhiyun 	const u16 mask = mv88e6xxx_port_mask(chip);
823*4882a593Smuzhiyun 	u16 reg;
824*4882a593Smuzhiyun 	int err;
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
827*4882a593Smuzhiyun 	if (err)
828*4882a593Smuzhiyun 		return err;
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	reg &= ~mask;
831*4882a593Smuzhiyun 	reg |= map & mask;
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);
834*4882a593Smuzhiyun 	if (err)
835*4882a593Smuzhiyun 		return err;
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	dev_dbg(chip->dev, "p%d: VLANTable set to %.3x\n", port, map);
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	return 0;
840*4882a593Smuzhiyun }
841*4882a593Smuzhiyun 
mv88e6xxx_port_get_fid(struct mv88e6xxx_chip * chip,int port,u16 * fid)842*4882a593Smuzhiyun int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid)
843*4882a593Smuzhiyun {
844*4882a593Smuzhiyun 	const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
845*4882a593Smuzhiyun 	u16 reg;
846*4882a593Smuzhiyun 	int err;
847*4882a593Smuzhiyun 
848*4882a593Smuzhiyun 	/* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
849*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
850*4882a593Smuzhiyun 	if (err)
851*4882a593Smuzhiyun 		return err;
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	*fid = (reg & 0xf000) >> 12;
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 	/* Port's default FID upper bits are located in reg 0x05, offset 0 */
856*4882a593Smuzhiyun 	if (upper_mask) {
857*4882a593Smuzhiyun 		err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,
858*4882a593Smuzhiyun 					  &reg);
859*4882a593Smuzhiyun 		if (err)
860*4882a593Smuzhiyun 			return err;
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun 		*fid |= (reg & upper_mask) << 4;
863*4882a593Smuzhiyun 	}
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun 	return 0;
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun 
mv88e6xxx_port_set_fid(struct mv88e6xxx_chip * chip,int port,u16 fid)868*4882a593Smuzhiyun int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid)
869*4882a593Smuzhiyun {
870*4882a593Smuzhiyun 	const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
871*4882a593Smuzhiyun 	u16 reg;
872*4882a593Smuzhiyun 	int err;
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 	if (fid >= mv88e6xxx_num_databases(chip))
875*4882a593Smuzhiyun 		return -EINVAL;
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun 	/* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
878*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
879*4882a593Smuzhiyun 	if (err)
880*4882a593Smuzhiyun 		return err;
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 	reg &= 0x0fff;
883*4882a593Smuzhiyun 	reg |= (fid & 0x000f) << 12;
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);
886*4882a593Smuzhiyun 	if (err)
887*4882a593Smuzhiyun 		return err;
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	/* Port's default FID upper bits are located in reg 0x05, offset 0 */
890*4882a593Smuzhiyun 	if (upper_mask) {
891*4882a593Smuzhiyun 		err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,
892*4882a593Smuzhiyun 					  &reg);
893*4882a593Smuzhiyun 		if (err)
894*4882a593Smuzhiyun 			return err;
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 		reg &= ~upper_mask;
897*4882a593Smuzhiyun 		reg |= (fid >> 4) & upper_mask;
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 		err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1,
900*4882a593Smuzhiyun 					   reg);
901*4882a593Smuzhiyun 		if (err)
902*4882a593Smuzhiyun 			return err;
903*4882a593Smuzhiyun 	}
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 	dev_dbg(chip->dev, "p%d: FID set to %u\n", port, fid);
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	return 0;
908*4882a593Smuzhiyun }
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun /* Offset 0x07: Default Port VLAN ID & Priority */
911*4882a593Smuzhiyun 
mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip * chip,int port,u16 * pvid)912*4882a593Smuzhiyun int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid)
913*4882a593Smuzhiyun {
914*4882a593Smuzhiyun 	u16 reg;
915*4882a593Smuzhiyun 	int err;
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
918*4882a593Smuzhiyun 				  &reg);
919*4882a593Smuzhiyun 	if (err)
920*4882a593Smuzhiyun 		return err;
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 	*pvid = reg & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	return 0;
925*4882a593Smuzhiyun }
926*4882a593Smuzhiyun 
mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip * chip,int port,u16 pvid)927*4882a593Smuzhiyun int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid)
928*4882a593Smuzhiyun {
929*4882a593Smuzhiyun 	u16 reg;
930*4882a593Smuzhiyun 	int err;
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
933*4882a593Smuzhiyun 				  &reg);
934*4882a593Smuzhiyun 	if (err)
935*4882a593Smuzhiyun 		return err;
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	reg &= ~MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
938*4882a593Smuzhiyun 	reg |= pvid & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
941*4882a593Smuzhiyun 				   reg);
942*4882a593Smuzhiyun 	if (err)
943*4882a593Smuzhiyun 		return err;
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun 	dev_dbg(chip->dev, "p%d: DefaultVID set to %u\n", port, pvid);
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 	return 0;
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun /* Offset 0x08: Port Control 2 Register */
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun static const char * const mv88e6xxx_port_8021q_mode_names[] = {
953*4882a593Smuzhiyun 	[MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED] = "Disabled",
954*4882a593Smuzhiyun 	[MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK] = "Fallback",
955*4882a593Smuzhiyun 	[MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK] = "Check",
956*4882a593Smuzhiyun 	[MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure",
957*4882a593Smuzhiyun };
958*4882a593Smuzhiyun 
mv88e6185_port_set_default_forward(struct mv88e6xxx_chip * chip,int port,bool multicast)959*4882a593Smuzhiyun static int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip,
960*4882a593Smuzhiyun 					      int port, bool multicast)
961*4882a593Smuzhiyun {
962*4882a593Smuzhiyun 	int err;
963*4882a593Smuzhiyun 	u16 reg;
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
966*4882a593Smuzhiyun 	if (err)
967*4882a593Smuzhiyun 		return err;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	if (multicast)
970*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;
971*4882a593Smuzhiyun 	else
972*4882a593Smuzhiyun 		reg &= ~MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
975*4882a593Smuzhiyun }
976*4882a593Smuzhiyun 
mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip * chip,int port,bool unicast,bool multicast)977*4882a593Smuzhiyun int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
978*4882a593Smuzhiyun 				     bool unicast, bool multicast)
979*4882a593Smuzhiyun {
980*4882a593Smuzhiyun 	int err;
981*4882a593Smuzhiyun 
982*4882a593Smuzhiyun 	err = mv88e6185_port_set_forward_unknown(chip, port, unicast);
983*4882a593Smuzhiyun 	if (err)
984*4882a593Smuzhiyun 		return err;
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 	return mv88e6185_port_set_default_forward(chip, port, multicast);
987*4882a593Smuzhiyun }
988*4882a593Smuzhiyun 
mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip * chip,int port,int upstream_port)989*4882a593Smuzhiyun int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
990*4882a593Smuzhiyun 				     int upstream_port)
991*4882a593Smuzhiyun {
992*4882a593Smuzhiyun 	int err;
993*4882a593Smuzhiyun 	u16 reg;
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
996*4882a593Smuzhiyun 	if (err)
997*4882a593Smuzhiyun 		return err;
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 	reg &= ~MV88E6095_PORT_CTL2_CPU_PORT_MASK;
1000*4882a593Smuzhiyun 	reg |= upstream_port;
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
1003*4882a593Smuzhiyun }
1004*4882a593Smuzhiyun 
mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip * chip,int port,enum mv88e6xxx_egress_direction direction,bool mirror)1005*4882a593Smuzhiyun int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
1006*4882a593Smuzhiyun 			      enum mv88e6xxx_egress_direction direction,
1007*4882a593Smuzhiyun 			      bool mirror)
1008*4882a593Smuzhiyun {
1009*4882a593Smuzhiyun 	bool *mirror_port;
1010*4882a593Smuzhiyun 	u16 reg;
1011*4882a593Smuzhiyun 	u16 bit;
1012*4882a593Smuzhiyun 	int err;
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
1015*4882a593Smuzhiyun 	if (err)
1016*4882a593Smuzhiyun 		return err;
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	switch (direction) {
1019*4882a593Smuzhiyun 	case MV88E6XXX_EGRESS_DIR_INGRESS:
1020*4882a593Smuzhiyun 		bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR;
1021*4882a593Smuzhiyun 		mirror_port = &chip->ports[port].mirror_ingress;
1022*4882a593Smuzhiyun 		break;
1023*4882a593Smuzhiyun 	case MV88E6XXX_EGRESS_DIR_EGRESS:
1024*4882a593Smuzhiyun 		bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR;
1025*4882a593Smuzhiyun 		mirror_port = &chip->ports[port].mirror_egress;
1026*4882a593Smuzhiyun 		break;
1027*4882a593Smuzhiyun 	default:
1028*4882a593Smuzhiyun 		return -EINVAL;
1029*4882a593Smuzhiyun 	}
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	reg &= ~bit;
1032*4882a593Smuzhiyun 	if (mirror)
1033*4882a593Smuzhiyun 		reg |= bit;
1034*4882a593Smuzhiyun 
1035*4882a593Smuzhiyun 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
1036*4882a593Smuzhiyun 	if (!err)
1037*4882a593Smuzhiyun 		*mirror_port = mirror;
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 	return err;
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun 
mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip * chip,int port,u16 mode)1042*4882a593Smuzhiyun int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
1043*4882a593Smuzhiyun 				  u16 mode)
1044*4882a593Smuzhiyun {
1045*4882a593Smuzhiyun 	u16 reg;
1046*4882a593Smuzhiyun 	int err;
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
1049*4882a593Smuzhiyun 	if (err)
1050*4882a593Smuzhiyun 		return err;
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun 	reg &= ~MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;
1053*4882a593Smuzhiyun 	reg |= mode & MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;
1054*4882a593Smuzhiyun 
1055*4882a593Smuzhiyun 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
1056*4882a593Smuzhiyun 	if (err)
1057*4882a593Smuzhiyun 		return err;
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun 	dev_dbg(chip->dev, "p%d: 802.1QMode set to %s\n", port,
1060*4882a593Smuzhiyun 		mv88e6xxx_port_8021q_mode_names[mode]);
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun 	return 0;
1063*4882a593Smuzhiyun }
1064*4882a593Smuzhiyun 
mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip * chip,int port)1065*4882a593Smuzhiyun int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port)
1066*4882a593Smuzhiyun {
1067*4882a593Smuzhiyun 	u16 reg;
1068*4882a593Smuzhiyun 	int err;
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
1071*4882a593Smuzhiyun 	if (err)
1072*4882a593Smuzhiyun 		return err;
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 	reg |= MV88E6XXX_PORT_CTL2_MAP_DA;
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
1077*4882a593Smuzhiyun }
1078*4882a593Smuzhiyun 
mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip * chip,int port,size_t size)1079*4882a593Smuzhiyun int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,
1080*4882a593Smuzhiyun 				  size_t size)
1081*4882a593Smuzhiyun {
1082*4882a593Smuzhiyun 	u16 reg;
1083*4882a593Smuzhiyun 	int err;
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 	size += VLAN_ETH_HLEN + ETH_FCS_LEN;
1086*4882a593Smuzhiyun 
1087*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
1088*4882a593Smuzhiyun 	if (err)
1089*4882a593Smuzhiyun 		return err;
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun 	reg &= ~MV88E6XXX_PORT_CTL2_JUMBO_MODE_MASK;
1092*4882a593Smuzhiyun 
1093*4882a593Smuzhiyun 	if (size <= 1522)
1094*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_1522;
1095*4882a593Smuzhiyun 	else if (size <= 2048)
1096*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_2048;
1097*4882a593Smuzhiyun 	else if (size <= 10240)
1098*4882a593Smuzhiyun 		reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_10240;
1099*4882a593Smuzhiyun 	else
1100*4882a593Smuzhiyun 		return -ERANGE;
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
1103*4882a593Smuzhiyun }
1104*4882a593Smuzhiyun 
1105*4882a593Smuzhiyun /* Offset 0x09: Port Rate Control */
1106*4882a593Smuzhiyun 
mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip * chip,int port)1107*4882a593Smuzhiyun int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
1108*4882a593Smuzhiyun {
1109*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,
1110*4882a593Smuzhiyun 				    0x0000);
1111*4882a593Smuzhiyun }
1112*4882a593Smuzhiyun 
mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip * chip,int port)1113*4882a593Smuzhiyun int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
1114*4882a593Smuzhiyun {
1115*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,
1116*4882a593Smuzhiyun 				    0x0001);
1117*4882a593Smuzhiyun }
1118*4882a593Smuzhiyun 
1119*4882a593Smuzhiyun /* Offset 0x0C: Port ATU Control */
1120*4882a593Smuzhiyun 
mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip * chip,int port)1121*4882a593Smuzhiyun int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port)
1122*4882a593Smuzhiyun {
1123*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ATU_CTL, 0);
1124*4882a593Smuzhiyun }
1125*4882a593Smuzhiyun 
1126*4882a593Smuzhiyun /* Offset 0x0D: (Priority) Override Register */
1127*4882a593Smuzhiyun 
mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip * chip,int port)1128*4882a593Smuzhiyun int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port)
1129*4882a593Smuzhiyun {
1130*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0);
1131*4882a593Smuzhiyun }
1132*4882a593Smuzhiyun 
1133*4882a593Smuzhiyun /* Offset 0x0f: Port Ether type */
1134*4882a593Smuzhiyun 
mv88e6351_port_set_ether_type(struct mv88e6xxx_chip * chip,int port,u16 etype)1135*4882a593Smuzhiyun int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
1136*4882a593Smuzhiyun 				  u16 etype)
1137*4882a593Smuzhiyun {
1138*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype);
1139*4882a593Smuzhiyun }
1140*4882a593Smuzhiyun 
1141*4882a593Smuzhiyun /* Offset 0x18: Port IEEE Priority Remapping Registers [0-3]
1142*4882a593Smuzhiyun  * Offset 0x19: Port IEEE Priority Remapping Registers [4-7]
1143*4882a593Smuzhiyun  */
1144*4882a593Smuzhiyun 
mv88e6095_port_tag_remap(struct mv88e6xxx_chip * chip,int port)1145*4882a593Smuzhiyun int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
1146*4882a593Smuzhiyun {
1147*4882a593Smuzhiyun 	int err;
1148*4882a593Smuzhiyun 
1149*4882a593Smuzhiyun 	/* Use a direct priority mapping for all IEEE tagged frames */
1150*4882a593Smuzhiyun 	err = mv88e6xxx_port_write(chip, port,
1151*4882a593Smuzhiyun 				   MV88E6095_PORT_IEEE_PRIO_REMAP_0123,
1152*4882a593Smuzhiyun 				   0x3210);
1153*4882a593Smuzhiyun 	if (err)
1154*4882a593Smuzhiyun 		return err;
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port,
1157*4882a593Smuzhiyun 				    MV88E6095_PORT_IEEE_PRIO_REMAP_4567,
1158*4882a593Smuzhiyun 				    0x7654);
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun 
mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip * chip,int port,u16 table,u8 ptr,u16 data)1161*4882a593Smuzhiyun static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip,
1162*4882a593Smuzhiyun 					int port, u16 table, u8 ptr, u16 data)
1163*4882a593Smuzhiyun {
1164*4882a593Smuzhiyun 	u16 reg;
1165*4882a593Smuzhiyun 
1166*4882a593Smuzhiyun 	reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE | table |
1167*4882a593Smuzhiyun 		(ptr << __bf_shf(MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_PTR_MASK)) |
1168*4882a593Smuzhiyun 		(data & MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_DATA_MASK);
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port,
1171*4882a593Smuzhiyun 				    MV88E6390_PORT_IEEE_PRIO_MAP_TABLE, reg);
1172*4882a593Smuzhiyun }
1173*4882a593Smuzhiyun 
mv88e6390_port_tag_remap(struct mv88e6xxx_chip * chip,int port)1174*4882a593Smuzhiyun int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
1175*4882a593Smuzhiyun {
1176*4882a593Smuzhiyun 	int err, i;
1177*4882a593Smuzhiyun 	u16 table;
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun 	for (i = 0; i <= 7; i++) {
1180*4882a593Smuzhiyun 		table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP;
1181*4882a593Smuzhiyun 		err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i,
1182*4882a593Smuzhiyun 						   (i | i << 4));
1183*4882a593Smuzhiyun 		if (err)
1184*4882a593Smuzhiyun 			return err;
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun 		table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP;
1187*4882a593Smuzhiyun 		err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
1188*4882a593Smuzhiyun 		if (err)
1189*4882a593Smuzhiyun 			return err;
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun 		table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP;
1192*4882a593Smuzhiyun 		err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
1193*4882a593Smuzhiyun 		if (err)
1194*4882a593Smuzhiyun 			return err;
1195*4882a593Smuzhiyun 
1196*4882a593Smuzhiyun 		table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP;
1197*4882a593Smuzhiyun 		err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
1198*4882a593Smuzhiyun 		if (err)
1199*4882a593Smuzhiyun 			return err;
1200*4882a593Smuzhiyun 	}
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	return 0;
1203*4882a593Smuzhiyun }
1204*4882a593Smuzhiyun 
1205*4882a593Smuzhiyun /* Offset 0x0E: Policy Control Register */
1206*4882a593Smuzhiyun 
mv88e6352_port_set_policy(struct mv88e6xxx_chip * chip,int port,enum mv88e6xxx_policy_mapping mapping,enum mv88e6xxx_policy_action action)1207*4882a593Smuzhiyun int mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port,
1208*4882a593Smuzhiyun 			      enum mv88e6xxx_policy_mapping mapping,
1209*4882a593Smuzhiyun 			      enum mv88e6xxx_policy_action action)
1210*4882a593Smuzhiyun {
1211*4882a593Smuzhiyun 	u16 reg, mask, val;
1212*4882a593Smuzhiyun 	int shift;
1213*4882a593Smuzhiyun 	int err;
1214*4882a593Smuzhiyun 
1215*4882a593Smuzhiyun 	switch (mapping) {
1216*4882a593Smuzhiyun 	case MV88E6XXX_POLICY_MAPPING_DA:
1217*4882a593Smuzhiyun 		shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_DA_MASK);
1218*4882a593Smuzhiyun 		mask = MV88E6XXX_PORT_POLICY_CTL_DA_MASK;
1219*4882a593Smuzhiyun 		break;
1220*4882a593Smuzhiyun 	case MV88E6XXX_POLICY_MAPPING_SA:
1221*4882a593Smuzhiyun 		shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_SA_MASK);
1222*4882a593Smuzhiyun 		mask = MV88E6XXX_PORT_POLICY_CTL_SA_MASK;
1223*4882a593Smuzhiyun 		break;
1224*4882a593Smuzhiyun 	case MV88E6XXX_POLICY_MAPPING_VTU:
1225*4882a593Smuzhiyun 		shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VTU_MASK);
1226*4882a593Smuzhiyun 		mask = MV88E6XXX_PORT_POLICY_CTL_VTU_MASK;
1227*4882a593Smuzhiyun 		break;
1228*4882a593Smuzhiyun 	case MV88E6XXX_POLICY_MAPPING_ETYPE:
1229*4882a593Smuzhiyun 		shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK);
1230*4882a593Smuzhiyun 		mask = MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK;
1231*4882a593Smuzhiyun 		break;
1232*4882a593Smuzhiyun 	case MV88E6XXX_POLICY_MAPPING_PPPOE:
1233*4882a593Smuzhiyun 		shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK);
1234*4882a593Smuzhiyun 		mask = MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK;
1235*4882a593Smuzhiyun 		break;
1236*4882a593Smuzhiyun 	case MV88E6XXX_POLICY_MAPPING_VBAS:
1237*4882a593Smuzhiyun 		shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK);
1238*4882a593Smuzhiyun 		mask = MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK;
1239*4882a593Smuzhiyun 		break;
1240*4882a593Smuzhiyun 	case MV88E6XXX_POLICY_MAPPING_OPT82:
1241*4882a593Smuzhiyun 		shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK);
1242*4882a593Smuzhiyun 		mask = MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK;
1243*4882a593Smuzhiyun 		break;
1244*4882a593Smuzhiyun 	case MV88E6XXX_POLICY_MAPPING_UDP:
1245*4882a593Smuzhiyun 		shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_UDP_MASK);
1246*4882a593Smuzhiyun 		mask = MV88E6XXX_PORT_POLICY_CTL_UDP_MASK;
1247*4882a593Smuzhiyun 		break;
1248*4882a593Smuzhiyun 	default:
1249*4882a593Smuzhiyun 		return -EOPNOTSUPP;
1250*4882a593Smuzhiyun 	}
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 	switch (action) {
1253*4882a593Smuzhiyun 	case MV88E6XXX_POLICY_ACTION_NORMAL:
1254*4882a593Smuzhiyun 		val = MV88E6XXX_PORT_POLICY_CTL_NORMAL;
1255*4882a593Smuzhiyun 		break;
1256*4882a593Smuzhiyun 	case MV88E6XXX_POLICY_ACTION_MIRROR:
1257*4882a593Smuzhiyun 		val = MV88E6XXX_PORT_POLICY_CTL_MIRROR;
1258*4882a593Smuzhiyun 		break;
1259*4882a593Smuzhiyun 	case MV88E6XXX_POLICY_ACTION_TRAP:
1260*4882a593Smuzhiyun 		val = MV88E6XXX_PORT_POLICY_CTL_TRAP;
1261*4882a593Smuzhiyun 		break;
1262*4882a593Smuzhiyun 	case MV88E6XXX_POLICY_ACTION_DISCARD:
1263*4882a593Smuzhiyun 		val = MV88E6XXX_PORT_POLICY_CTL_DISCARD;
1264*4882a593Smuzhiyun 		break;
1265*4882a593Smuzhiyun 	default:
1266*4882a593Smuzhiyun 		return -EOPNOTSUPP;
1267*4882a593Smuzhiyun 	}
1268*4882a593Smuzhiyun 
1269*4882a593Smuzhiyun 	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_POLICY_CTL, &reg);
1270*4882a593Smuzhiyun 	if (err)
1271*4882a593Smuzhiyun 		return err;
1272*4882a593Smuzhiyun 
1273*4882a593Smuzhiyun 	reg &= ~mask;
1274*4882a593Smuzhiyun 	reg |= (val << shift) & mask;
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_POLICY_CTL, reg);
1277*4882a593Smuzhiyun }
1278