blob: d8590025e75fb19d998aa960574de169e00f7bdd [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Vivien Didelot18abed22016-11-04 03:23:26 +01002/*
3 * Marvell 88E6xxx Switch Port Registers support
4 *
5 * Copyright (c) 2008 Marvell Semiconductor
6 *
Vivien Didelot4333d612017-03-28 15:10:36 -04007 * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
8 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Vivien Didelot18abed22016-11-04 03:23:26 +01009 */
10
Vivien Didelotddcbabf2017-06-17 23:07:14 -040011#include <linux/bitfield.h>
Vivien Didelotf894c292017-06-08 18:34:10 -040012#include <linux/if_bridge.h>
Andrew Lunnf39908d2017-02-04 20:02:50 +010013#include <linux/phy.h>
Russell Kingc9a23562018-05-10 13:17:35 -070014#include <linux/phylink.h>
Vivien Didelot4d5f2ba72017-06-02 17:06:15 -040015
16#include "chip.h"
Vivien Didelot18abed22016-11-04 03:23:26 +010017#include "port.h"
Andrew Lunn364e9d72018-08-09 15:38:46 +020018#include "serdes.h"
Vivien Didelot18abed22016-11-04 03:23:26 +010019
20int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
21 u16 *val)
22{
23 int addr = chip->info->port_base_addr + port;
24
25 return mv88e6xxx_read(chip, addr, reg, val);
26}
27
28int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
29 u16 val)
30{
31 int addr = chip->info->port_base_addr + port;
32
33 return mv88e6xxx_write(chip, addr, reg, val);
34}
Vivien Didelote28def332016-11-04 03:23:27 +010035
Andrew Lunn54186b92018-08-09 15:38:37 +020036/* Offset 0x00: MAC (or PCS or Physical) Status Register
37 *
38 * For most devices, this is read only. However the 6185 has the MyPause
39 * bit read/write.
40 */
41int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
42 int pause)
43{
44 u16 reg;
45 int err;
46
47 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
48 if (err)
49 return err;
50
51 if (pause)
52 reg |= MV88E6XXX_PORT_STS_MY_PAUSE;
53 else
54 reg &= ~MV88E6XXX_PORT_STS_MY_PAUSE;
55
56 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
57}
58
Vivien Didelot08ef7f12016-11-04 03:23:32 +010059/* Offset 0x01: MAC (or PCS or Physical) Control Register
60 *
61 * Link, Duplex and Flow Control have one force bit, one value bit.
Vivien Didelot96a2b402016-11-04 03:23:35 +010062 *
63 * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value.
64 * Alternative values require the 200BASE (or AltSpeed) bit 12 set.
65 * Newer chips need a ForcedSpd bit 13 set to consider the value.
Vivien Didelot08ef7f12016-11-04 03:23:32 +010066 */
67
Vivien Didelota0a0f622016-11-04 03:23:34 +010068static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
69 phy_interface_t mode)
70{
71 u16 reg;
72 int err;
73
Vivien Didelot5ee55572017-06-12 12:37:34 -040074 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelota0a0f622016-11-04 03:23:34 +010075 if (err)
76 return err;
77
Vivien Didelot5ee55572017-06-12 12:37:34 -040078 reg &= ~(MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
79 MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK);
Vivien Didelota0a0f622016-11-04 03:23:34 +010080
81 switch (mode) {
82 case PHY_INTERFACE_MODE_RGMII_RXID:
Vivien Didelot5ee55572017-06-12 12:37:34 -040083 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK;
Vivien Didelota0a0f622016-11-04 03:23:34 +010084 break;
85 case PHY_INTERFACE_MODE_RGMII_TXID:
Vivien Didelot5ee55572017-06-12 12:37:34 -040086 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
Vivien Didelota0a0f622016-11-04 03:23:34 +010087 break;
88 case PHY_INTERFACE_MODE_RGMII_ID:
Vivien Didelot5ee55572017-06-12 12:37:34 -040089 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
90 MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
Vivien Didelota0a0f622016-11-04 03:23:34 +010091 break;
Andrew Lunnfedf1862016-11-10 15:44:00 +010092 case PHY_INTERFACE_MODE_RGMII:
Vivien Didelota0a0f622016-11-04 03:23:34 +010093 break;
Andrew Lunnfedf1862016-11-10 15:44:00 +010094 default:
95 return 0;
Vivien Didelota0a0f622016-11-04 03:23:34 +010096 }
97
Vivien Didelot5ee55572017-06-12 12:37:34 -040098 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelota0a0f622016-11-04 03:23:34 +010099 if (err)
100 return err;
101
Vivien Didelot774439e52017-06-08 18:34:08 -0400102 dev_dbg(chip->dev, "p%d: delay RXCLK %s, TXCLK %s\n", port,
Vivien Didelot5ee55572017-06-12 12:37:34 -0400103 reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK ? "yes" : "no",
104 reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK ? "yes" : "no");
Vivien Didelota0a0f622016-11-04 03:23:34 +0100105
106 return 0;
107}
108
109int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
110 phy_interface_t mode)
111{
112 if (port < 5)
113 return -EOPNOTSUPP;
114
115 return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
116}
117
118int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
119 phy_interface_t mode)
120{
121 if (port != 0)
122 return -EOPNOTSUPP;
123
124 return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
125}
126
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100127int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link)
128{
129 u16 reg;
130 int err;
131
Vivien Didelot5ee55572017-06-12 12:37:34 -0400132 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100133 if (err)
134 return err;
135
Vivien Didelot5ee55572017-06-12 12:37:34 -0400136 reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
137 MV88E6XXX_PORT_MAC_CTL_LINK_UP);
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100138
139 switch (link) {
140 case LINK_FORCED_DOWN:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400141 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK;
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100142 break;
143 case LINK_FORCED_UP:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400144 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
145 MV88E6XXX_PORT_MAC_CTL_LINK_UP;
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100146 break;
147 case LINK_UNFORCED:
148 /* normal link detection */
149 break;
150 default:
151 return -EINVAL;
152 }
153
Vivien Didelot5ee55572017-06-12 12:37:34 -0400154 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100155 if (err)
156 return err;
157
Vivien Didelot774439e52017-06-08 18:34:08 -0400158 dev_dbg(chip->dev, "p%d: %s link %s\n", port,
Vivien Didelot5ee55572017-06-12 12:37:34 -0400159 reg & MV88E6XXX_PORT_MAC_CTL_FORCE_LINK ? "Force" : "Unforce",
160 reg & MV88E6XXX_PORT_MAC_CTL_LINK_UP ? "up" : "down");
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100161
162 return 0;
163}
164
Chris Packham4efe76622020-11-24 17:34:37 +1300165int mv88e6xxx_port_sync_link(struct mv88e6xxx_chip *chip, int port, unsigned int mode, bool isup)
166{
167 const struct mv88e6xxx_ops *ops = chip->info->ops;
168 int err = 0;
169 int link;
170
171 if (isup)
172 link = LINK_FORCED_UP;
173 else
174 link = LINK_FORCED_DOWN;
175
176 if (ops->port_set_link)
177 err = ops->port_set_link(chip, port, link);
178
179 return err;
180}
181
182int mv88e6185_port_sync_link(struct mv88e6xxx_chip *chip, int port, unsigned int mode, bool isup)
183{
184 const struct mv88e6xxx_ops *ops = chip->info->ops;
185 int err = 0;
186 int link;
187
188 if (mode == MLO_AN_INBAND)
189 link = LINK_UNFORCED;
190 else if (isup)
191 link = LINK_FORCED_UP;
192 else
193 link = LINK_FORCED_DOWN;
194
195 if (ops->port_set_link)
196 err = ops->port_set_link(chip, port, link);
197
198 return err;
199}
200
Russell Kingf365c6f2020-03-14 10:15:53 +0000201static int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip,
202 int port, int speed, bool alt_bit,
203 bool force_bit, int duplex)
Vivien Didelot96a2b402016-11-04 03:23:35 +0100204{
205 u16 reg, ctrl;
206 int err;
207
208 switch (speed) {
209 case 10:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400210 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100211 break;
212 case 100:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400213 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100214 break;
215 case 200:
216 if (alt_bit)
Vivien Didelot5ee55572017-06-12 12:37:34 -0400217 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |
218 MV88E6390_PORT_MAC_CTL_ALTSPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100219 else
Vivien Didelot5ee55572017-06-12 12:37:34 -0400220 ctrl = MV88E6065_PORT_MAC_CTL_SPEED_200;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100221 break;
222 case 1000:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400223 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100224 break;
225 case 2500:
Marek Behún26422342018-10-13 14:40:31 +0200226 if (alt_bit)
227 ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
228 MV88E6390_PORT_MAC_CTL_ALTSPEED;
229 else
230 ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100231 break;
232 case 10000:
233 /* all bits set, fall through... */
234 case SPEED_UNFORCED:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400235 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100236 break;
237 default:
238 return -EOPNOTSUPP;
239 }
240
Russell Kingf365c6f2020-03-14 10:15:53 +0000241 switch (duplex) {
242 case DUPLEX_HALF:
243 ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;
244 break;
245 case DUPLEX_FULL:
246 ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
247 MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;
248 break;
249 case DUPLEX_UNFORCED:
250 /* normal duplex detection */
251 break;
252 default:
253 return -EOPNOTSUPP;
254 }
255
Vivien Didelot5ee55572017-06-12 12:37:34 -0400256 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100257 if (err)
258 return err;
259
Russell Kingf365c6f2020-03-14 10:15:53 +0000260 reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |
261 MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
262 MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);
263
Vivien Didelot96a2b402016-11-04 03:23:35 +0100264 if (alt_bit)
Vivien Didelot5ee55572017-06-12 12:37:34 -0400265 reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100266 if (force_bit) {
Vivien Didelot5ee55572017-06-12 12:37:34 -0400267 reg &= ~MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
Andrew Lunn0b6e3d02016-11-16 04:26:48 +0100268 if (speed != SPEED_UNFORCED)
Vivien Didelot5ee55572017-06-12 12:37:34 -0400269 ctrl |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100270 }
271 reg |= ctrl;
272
Vivien Didelot5ee55572017-06-12 12:37:34 -0400273 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100274 if (err)
275 return err;
276
277 if (speed)
Vivien Didelot774439e52017-06-08 18:34:08 -0400278 dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100279 else
Vivien Didelot774439e52017-06-08 18:34:08 -0400280 dev_dbg(chip->dev, "p%d: Speed unforced\n", port);
Russell Kingf365c6f2020-03-14 10:15:53 +0000281 dev_dbg(chip->dev, "p%d: %s %s duplex\n", port,
282 reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce",
283 reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half");
Vivien Didelot96a2b402016-11-04 03:23:35 +0100284
285 return 0;
286}
287
288/* Support 10, 100, 200 Mbps (e.g. 88E6065 family) */
Russell Kingf365c6f2020-03-14 10:15:53 +0000289int mv88e6065_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
290 int speed, int duplex)
Vivien Didelot96a2b402016-11-04 03:23:35 +0100291{
292 if (speed == SPEED_MAX)
293 speed = 200;
294
295 if (speed > 200)
296 return -EOPNOTSUPP;
297
298 /* Setting 200 Mbps on port 0 to 3 selects 100 Mbps */
Russell Kingf365c6f2020-03-14 10:15:53 +0000299 return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false,
300 duplex);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100301}
302
303/* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */
Russell Kingf365c6f2020-03-14 10:15:53 +0000304int mv88e6185_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
305 int speed, int duplex)
Vivien Didelot96a2b402016-11-04 03:23:35 +0100306{
307 if (speed == SPEED_MAX)
308 speed = 1000;
309
310 if (speed == 200 || speed > 1000)
311 return -EOPNOTSUPP;
312
Russell Kingf365c6f2020-03-14 10:15:53 +0000313 return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false,
314 duplex);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100315}
316
Rasmus Villemoesa528e5b2019-06-04 07:34:29 +0000317/* Support 10, 100 Mbps (e.g. 88E6250 family) */
Russell Kingf365c6f2020-03-14 10:15:53 +0000318int mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
319 int speed, int duplex)
Rasmus Villemoesa528e5b2019-06-04 07:34:29 +0000320{
321 if (speed == SPEED_MAX)
322 speed = 100;
323
324 if (speed > 100)
325 return -EOPNOTSUPP;
326
Russell Kingf365c6f2020-03-14 10:15:53 +0000327 return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false,
328 duplex);
Rasmus Villemoesa528e5b2019-06-04 07:34:29 +0000329}
330
Marek Behún26422342018-10-13 14:40:31 +0200331/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6341) */
Russell Kingf365c6f2020-03-14 10:15:53 +0000332int mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
333 int speed, int duplex)
Marek Behún26422342018-10-13 14:40:31 +0200334{
335 if (speed == SPEED_MAX)
336 speed = port < 5 ? 1000 : 2500;
337
338 if (speed > 2500)
339 return -EOPNOTSUPP;
340
341 if (speed == 200 && port != 0)
342 return -EOPNOTSUPP;
343
344 if (speed == 2500 && port < 5)
345 return -EOPNOTSUPP;
346
Russell Kingf365c6f2020-03-14 10:15:53 +0000347 return mv88e6xxx_port_set_speed_duplex(chip, port, speed, !port, true,
348 duplex);
Marek Behún26422342018-10-13 14:40:31 +0200349}
350
Andrew Lunn7cbbee02019-03-08 01:21:27 +0100351phy_interface_t mv88e6341_port_max_speed_mode(int port)
352{
353 if (port == 5)
354 return PHY_INTERFACE_MODE_2500BASEX;
355
356 return PHY_INTERFACE_MODE_NA;
357}
358
Vivien Didelot96a2b402016-11-04 03:23:35 +0100359/* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */
Russell Kingf365c6f2020-03-14 10:15:53 +0000360int mv88e6352_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
361 int speed, int duplex)
Vivien Didelot96a2b402016-11-04 03:23:35 +0100362{
363 if (speed == SPEED_MAX)
364 speed = 1000;
365
366 if (speed > 1000)
367 return -EOPNOTSUPP;
368
369 if (speed == 200 && port < 5)
370 return -EOPNOTSUPP;
371
Russell Kingf365c6f2020-03-14 10:15:53 +0000372 return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, false,
373 duplex);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100374}
375
376/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */
Russell Kingf365c6f2020-03-14 10:15:53 +0000377int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
378 int speed, int duplex)
Vivien Didelot96a2b402016-11-04 03:23:35 +0100379{
380 if (speed == SPEED_MAX)
381 speed = port < 9 ? 1000 : 2500;
382
383 if (speed > 2500)
384 return -EOPNOTSUPP;
385
386 if (speed == 200 && port != 0)
387 return -EOPNOTSUPP;
388
389 if (speed == 2500 && port < 9)
390 return -EOPNOTSUPP;
391
Russell Kingf365c6f2020-03-14 10:15:53 +0000392 return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true,
393 duplex);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100394}
395
Andrew Lunn7cbbee02019-03-08 01:21:27 +0100396phy_interface_t mv88e6390_port_max_speed_mode(int port)
397{
398 if (port == 9 || port == 10)
399 return PHY_INTERFACE_MODE_2500BASEX;
400
401 return PHY_INTERFACE_MODE_NA;
402}
403
Vivien Didelot96a2b402016-11-04 03:23:35 +0100404/* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */
Russell Kingf365c6f2020-03-14 10:15:53 +0000405int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
406 int speed, int duplex)
Vivien Didelot96a2b402016-11-04 03:23:35 +0100407{
408 if (speed == SPEED_MAX)
409 speed = port < 9 ? 1000 : 10000;
410
411 if (speed == 200 && port != 0)
412 return -EOPNOTSUPP;
413
414 if (speed >= 2500 && port < 9)
415 return -EOPNOTSUPP;
416
Russell Kingf365c6f2020-03-14 10:15:53 +0000417 return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true,
418 duplex);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100419}
420
Andrew Lunn7cbbee02019-03-08 01:21:27 +0100421phy_interface_t mv88e6390x_port_max_speed_mode(int port)
422{
423 if (port == 9 || port == 10)
424 return PHY_INTERFACE_MODE_XAUI;
425
426 return PHY_INTERFACE_MODE_NA;
427}
428
Marek Behún7a3007d2019-08-26 23:31:55 +0200429static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
Baruch Siachf7a48b62019-12-19 11:48:22 +0200430 phy_interface_t mode, bool force)
Andrew Lunnf39908d2017-02-04 20:02:50 +0100431{
Andrew Lunnf39908d2017-02-04 20:02:50 +0100432 u16 cmode;
Pavana Sharma193c5b22021-03-17 14:46:40 +0100433 int lane;
Andrew Lunn734447d2018-08-09 15:38:49 +0200434 u16 reg;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100435 int err;
436
Andrew Lunn787799a2018-11-11 00:32:16 +0100437 /* Default to a slow mode, so freeing up SERDES interfaces for
438 * other ports which might use them for SFPs.
439 */
440 if (mode == PHY_INTERFACE_MODE_NA)
441 mode = PHY_INTERFACE_MODE_1000BASEX;
442
Andrew Lunnf39908d2017-02-04 20:02:50 +0100443 switch (mode) {
444 case PHY_INTERFACE_MODE_1000BASEX:
Marek Behún3bbb8862019-08-26 23:31:54 +0200445 cmode = MV88E6XXX_PORT_STS_CMODE_1000BASEX;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100446 break;
447 case PHY_INTERFACE_MODE_SGMII:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400448 cmode = MV88E6XXX_PORT_STS_CMODE_SGMII;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100449 break;
450 case PHY_INTERFACE_MODE_2500BASEX:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400451 cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100452 break;
453 case PHY_INTERFACE_MODE_XGMII:
Russell King2e51a8d2017-12-12 09:29:46 +0000454 case PHY_INTERFACE_MODE_XAUI:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400455 cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100456 break;
457 case PHY_INTERFACE_MODE_RXAUI:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400458 cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100459 break;
460 default:
461 cmode = 0;
462 }
463
Baruch Siachf7a48b62019-12-19 11:48:22 +0200464 /* cmode doesn't change, nothing to do for us unless forced */
465 if (cmode == chip->ports[port].cmode && !force)
Heiner Kallweited8fe202019-02-28 07:39:15 +0100466 return 0;
467
Vivien Didelot5122d4e2019-08-31 16:18:30 -0400468 lane = mv88e6xxx_serdes_get_lane(chip, port);
Pavana Sharma193c5b22021-03-17 14:46:40 +0100469 if (lane >= 0) {
Heiner Kallweit5ceaeb92019-03-23 19:41:32 +0100470 if (chip->ports[port].serdes_irq) {
Vivien Didelot61a46b42019-08-31 16:18:34 -0400471 err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
Heiner Kallweit5ceaeb92019-03-23 19:41:32 +0100472 if (err)
473 return err;
474 }
475
Vivien Didelotdc272f62019-08-31 16:18:33 -0400476 err = mv88e6xxx_serdes_power_down(chip, port, lane);
Andrew Lunn734447d2018-08-09 15:38:49 +0200477 if (err)
478 return err;
479 }
480
Heiner Kallweit5ceaeb92019-03-23 19:41:32 +0100481 chip->ports[port].cmode = 0;
Andrew Lunn364e9d72018-08-09 15:38:46 +0200482
Andrew Lunnf39908d2017-02-04 20:02:50 +0100483 if (cmode) {
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400484 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
Andrew Lunnf39908d2017-02-04 20:02:50 +0100485 if (err)
486 return err;
487
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400488 reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100489 reg |= cmode;
490
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400491 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
Andrew Lunnf39908d2017-02-04 20:02:50 +0100492 if (err)
493 return err;
Andrew Lunn364e9d72018-08-09 15:38:46 +0200494
Heiner Kallweit5ceaeb92019-03-23 19:41:32 +0100495 chip->ports[port].cmode = cmode;
496
Vivien Didelot5122d4e2019-08-31 16:18:30 -0400497 lane = mv88e6xxx_serdes_get_lane(chip, port);
Pavana Sharma193c5b22021-03-17 14:46:40 +0100498 if (lane < 0)
499 return lane;
Heiner Kallweit5ceaeb92019-03-23 19:41:32 +0100500
Vivien Didelotdc272f62019-08-31 16:18:33 -0400501 err = mv88e6xxx_serdes_power_up(chip, port, lane);
Andrew Lunn364e9d72018-08-09 15:38:46 +0200502 if (err)
503 return err;
Andrew Lunn734447d2018-08-09 15:38:49 +0200504
505 if (chip->ports[port].serdes_irq) {
Vivien Didelot61a46b42019-08-31 16:18:34 -0400506 err = mv88e6xxx_serdes_irq_enable(chip, port, lane);
Andrew Lunn734447d2018-08-09 15:38:49 +0200507 if (err)
508 return err;
509 }
Andrew Lunnf39908d2017-02-04 20:02:50 +0100510 }
511
512 return 0;
513}
514
Marek Behún7a3007d2019-08-26 23:31:55 +0200515int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
516 phy_interface_t mode)
517{
518 if (port != 9 && port != 10)
519 return -EOPNOTSUPP;
520
Baruch Siachf7a48b62019-12-19 11:48:22 +0200521 return mv88e6xxx_port_set_cmode(chip, port, mode, false);
Marek Behún7a3007d2019-08-26 23:31:55 +0200522}
523
Andrew Lunnfdc71ee2018-11-11 00:32:15 +0100524int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
525 phy_interface_t mode)
526{
Marek Behún7a3007d2019-08-26 23:31:55 +0200527 if (port != 9 && port != 10)
528 return -EOPNOTSUPP;
529
Andrew Lunnfdc71ee2018-11-11 00:32:15 +0100530 switch (mode) {
Marek Behún65b034c2019-02-25 12:39:54 +0100531 case PHY_INTERFACE_MODE_NA:
532 return 0;
Andrew Lunnfdc71ee2018-11-11 00:32:15 +0100533 case PHY_INTERFACE_MODE_XGMII:
534 case PHY_INTERFACE_MODE_XAUI:
535 case PHY_INTERFACE_MODE_RXAUI:
536 return -EINVAL;
537 default:
538 break;
539 }
540
Baruch Siachf7a48b62019-12-19 11:48:22 +0200541 return mv88e6xxx_port_set_cmode(chip, port, mode, false);
Marek Behún7a3007d2019-08-26 23:31:55 +0200542}
543
Vivien Didelot5d24da1e2019-08-28 12:26:59 -0400544static int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip,
545 int port)
Marek Behún7a3007d2019-08-26 23:31:55 +0200546{
547 int err, addr;
548 u16 reg, bits;
549
550 if (port != 5)
551 return -EOPNOTSUPP;
552
553 addr = chip->info->port_base_addr + port;
554
555 err = mv88e6xxx_port_hidden_read(chip, 0x7, addr, 0, &reg);
556 if (err)
557 return err;
558
559 bits = MV88E6341_PORT_RESERVED_1A_FORCE_CMODE |
560 MV88E6341_PORT_RESERVED_1A_SGMII_AN;
561
562 if ((reg & bits) == bits)
563 return 0;
564
565 reg |= bits;
566 return mv88e6xxx_port_hidden_write(chip, 0x7, addr, 0, reg);
567}
568
569int mv88e6341_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
570 phy_interface_t mode)
571{
Vivien Didelot5d24da1e2019-08-28 12:26:59 -0400572 int err;
573
Marek Behún7a3007d2019-08-26 23:31:55 +0200574 if (port != 5)
575 return -EOPNOTSUPP;
576
577 switch (mode) {
578 case PHY_INTERFACE_MODE_NA:
579 return 0;
580 case PHY_INTERFACE_MODE_XGMII:
581 case PHY_INTERFACE_MODE_XAUI:
582 case PHY_INTERFACE_MODE_RXAUI:
583 return -EINVAL;
584 default:
585 break;
586 }
587
Vivien Didelot5d24da1e2019-08-28 12:26:59 -0400588 err = mv88e6341_port_set_cmode_writable(chip, port);
589 if (err)
590 return err;
591
Baruch Siachf7a48b62019-12-19 11:48:22 +0200592 return mv88e6xxx_port_set_cmode(chip, port, mode, true);
Andrew Lunnfdc71ee2018-11-11 00:32:15 +0100593}
594
Andrew Lunn2d2e1dd2018-08-09 15:38:45 +0200595int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
Russell King6c422e32018-08-09 15:38:39 +0200596{
597 int err;
598 u16 reg;
599
600 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
601 if (err)
602 return err;
603
Andrew Lunn2d2e1dd2018-08-09 15:38:45 +0200604 *cmode = reg & MV88E6185_PORT_STS_CMODE_MASK;
605
606 return 0;
Russell King6c422e32018-08-09 15:38:39 +0200607}
608
Andrew Lunn2d2e1dd2018-08-09 15:38:45 +0200609int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
Andrew Lunnf39908d2017-02-04 20:02:50 +0100610{
611 int err;
612 u16 reg;
613
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400614 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
Andrew Lunnf39908d2017-02-04 20:02:50 +0100615 if (err)
616 return err;
617
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400618 *cmode = reg & MV88E6XXX_PORT_STS_CMODE_MASK;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100619
620 return 0;
621}
622
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400623/* Offset 0x02: Jamming Control
Andrew Lunnb35d322a2016-12-03 04:45:19 +0100624 *
625 * Do not limit the period of time that this port can be paused for by
626 * the remote end or the period of time that this port can pause the
627 * remote end.
628 */
Vivien Didelot08984322017-06-08 18:34:12 -0400629int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
630 u8 out)
Andrew Lunnb35d322a2016-12-03 04:45:19 +0100631{
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400632 return mv88e6xxx_port_write(chip, port, MV88E6097_PORT_JAM_CTL,
633 out << 8 | in);
Andrew Lunnb35d322a2016-12-03 04:45:19 +0100634}
635
Vivien Didelot08984322017-06-08 18:34:12 -0400636int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
637 u8 out)
Andrew Lunn3ce0e652016-12-03 04:45:20 +0100638{
639 int err;
640
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400641 err = mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,
642 MV88E6390_PORT_FLOW_CTL_UPDATE |
643 MV88E6390_PORT_FLOW_CTL_LIMIT_IN | in);
Andrew Lunn3ce0e652016-12-03 04:45:20 +0100644 if (err)
645 return err;
646
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400647 return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,
648 MV88E6390_PORT_FLOW_CTL_UPDATE |
649 MV88E6390_PORT_FLOW_CTL_LIMIT_OUT | out);
Andrew Lunn3ce0e652016-12-03 04:45:20 +0100650}
651
Vivien Didelote28def332016-11-04 03:23:27 +0100652/* Offset 0x04: Port Control Register */
653
654static const char * const mv88e6xxx_port_state_names[] = {
Vivien Didelota89b433be2017-06-12 12:37:37 -0400655 [MV88E6XXX_PORT_CTL0_STATE_DISABLED] = "Disabled",
656 [MV88E6XXX_PORT_CTL0_STATE_BLOCKING] = "Blocking/Listening",
657 [MV88E6XXX_PORT_CTL0_STATE_LEARNING] = "Learning",
658 [MV88E6XXX_PORT_CTL0_STATE_FORWARDING] = "Forwarding",
Vivien Didelote28def332016-11-04 03:23:27 +0100659};
660
661int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state)
662{
663 u16 reg;
664 int err;
665
Vivien Didelota89b433be2017-06-12 12:37:37 -0400666 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Vivien Didelote28def332016-11-04 03:23:27 +0100667 if (err)
668 return err;
669
Vivien Didelota89b433be2017-06-12 12:37:37 -0400670 reg &= ~MV88E6XXX_PORT_CTL0_STATE_MASK;
Vivien Didelotf894c292017-06-08 18:34:10 -0400671
672 switch (state) {
673 case BR_STATE_DISABLED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400674 state = MV88E6XXX_PORT_CTL0_STATE_DISABLED;
Vivien Didelotf894c292017-06-08 18:34:10 -0400675 break;
676 case BR_STATE_BLOCKING:
677 case BR_STATE_LISTENING:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400678 state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING;
Vivien Didelotf894c292017-06-08 18:34:10 -0400679 break;
680 case BR_STATE_LEARNING:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400681 state = MV88E6XXX_PORT_CTL0_STATE_LEARNING;
Vivien Didelotf894c292017-06-08 18:34:10 -0400682 break;
683 case BR_STATE_FORWARDING:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400684 state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
Vivien Didelotf894c292017-06-08 18:34:10 -0400685 break;
686 default:
687 return -EINVAL;
688 }
689
Vivien Didelote28def332016-11-04 03:23:27 +0100690 reg |= state;
691
Vivien Didelota89b433be2017-06-12 12:37:37 -0400692 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Vivien Didelote28def332016-11-04 03:23:27 +0100693 if (err)
694 return err;
695
Vivien Didelot774439e52017-06-08 18:34:08 -0400696 dev_dbg(chip->dev, "p%d: PortState set to %s\n", port,
697 mv88e6xxx_port_state_names[state]);
Vivien Didelote28def332016-11-04 03:23:27 +0100698
699 return 0;
700}
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100701
Andrew Lunn56995cb2016-12-03 04:35:19 +0100702int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port,
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400703 enum mv88e6xxx_egress_mode mode)
Andrew Lunn56995cb2016-12-03 04:35:19 +0100704{
705 int err;
706 u16 reg;
707
Vivien Didelota89b433be2017-06-12 12:37:37 -0400708 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100709 if (err)
710 return err;
711
Vivien Didelota89b433be2017-06-12 12:37:37 -0400712 reg &= ~MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400713
714 switch (mode) {
715 case MV88E6XXX_EGRESS_MODE_UNMODIFIED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400716 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400717 break;
718 case MV88E6XXX_EGRESS_MODE_UNTAGGED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400719 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400720 break;
721 case MV88E6XXX_EGRESS_MODE_TAGGED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400722 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400723 break;
724 case MV88E6XXX_EGRESS_MODE_ETHERTYPE:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400725 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400726 break;
727 default:
728 return -EINVAL;
729 }
Andrew Lunn56995cb2016-12-03 04:35:19 +0100730
Vivien Didelota89b433be2017-06-12 12:37:37 -0400731 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100732}
733
734int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
735 enum mv88e6xxx_frame_mode mode)
736{
737 int err;
738 u16 reg;
739
Vivien Didelota89b433be2017-06-12 12:37:37 -0400740 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100741 if (err)
742 return err;
743
Vivien Didelota89b433be2017-06-12 12:37:37 -0400744 reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100745
746 switch (mode) {
747 case MV88E6XXX_FRAME_MODE_NORMAL:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400748 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100749 break;
750 case MV88E6XXX_FRAME_MODE_DSA:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400751 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100752 break;
753 default:
754 return -EINVAL;
755 }
756
Vivien Didelota89b433be2017-06-12 12:37:37 -0400757 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100758}
759
760int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
761 enum mv88e6xxx_frame_mode mode)
762{
763 int err;
764 u16 reg;
765
Vivien Didelota89b433be2017-06-12 12:37:37 -0400766 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100767 if (err)
768 return err;
769
Vivien Didelota89b433be2017-06-12 12:37:37 -0400770 reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100771
772 switch (mode) {
773 case MV88E6XXX_FRAME_MODE_NORMAL:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400774 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100775 break;
776 case MV88E6XXX_FRAME_MODE_DSA:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400777 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100778 break;
779 case MV88E6XXX_FRAME_MODE_PROVIDER:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400780 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_PROVIDER;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100781 break;
782 case MV88E6XXX_FRAME_MODE_ETHERTYPE:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400783 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_ETHER_TYPE_DSA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100784 break;
785 default:
786 return -EINVAL;
787 }
788
Vivien Didelota89b433be2017-06-12 12:37:37 -0400789 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100790}
791
Vladimir Olteana8b659e2021-02-12 17:15:56 +0200792int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip,
793 int port, bool unicast)
Andrew Lunn56995cb2016-12-03 04:35:19 +0100794{
795 int err;
796 u16 reg;
797
Vivien Didelota89b433be2017-06-12 12:37:37 -0400798 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100799 if (err)
800 return err;
801
Vivien Didelot601aeed2017-03-11 16:13:00 -0500802 if (unicast)
Vivien Didelota89b433be2017-06-12 12:37:37 -0400803 reg |= MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100804 else
Vivien Didelota89b433be2017-06-12 12:37:37 -0400805 reg &= ~MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100806
Vivien Didelota89b433be2017-06-12 12:37:37 -0400807 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100808}
809
Vladimir Olteana8b659e2021-02-12 17:15:56 +0200810int mv88e6352_port_set_ucast_flood(struct mv88e6xxx_chip *chip, int port,
811 bool unicast)
Andrew Lunn56995cb2016-12-03 04:35:19 +0100812{
813 int err;
814 u16 reg;
815
Vivien Didelota89b433be2017-06-12 12:37:37 -0400816 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100817 if (err)
818 return err;
819
Vladimir Olteana8b659e2021-02-12 17:15:56 +0200820 if (unicast)
821 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_UC;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100822 else
Vladimir Olteana8b659e2021-02-12 17:15:56 +0200823 reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_UC;
824
825 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
826}
827
828int mv88e6352_port_set_mcast_flood(struct mv88e6xxx_chip *chip, int port,
829 bool multicast)
830{
831 int err;
832 u16 reg;
833
834 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
835 if (err)
836 return err;
837
838 if (multicast)
839 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_MC;
840 else
841 reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MC;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100842
Vivien Didelota89b433be2017-06-12 12:37:37 -0400843 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100844}
845
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100846/* Offset 0x05: Port Control 1 */
847
Vivien Didelotea698f42017-03-11 16:12:50 -0500848int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,
849 bool message_port)
850{
851 u16 val;
852 int err;
853
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400854 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val);
Vivien Didelotea698f42017-03-11 16:12:50 -0500855 if (err)
856 return err;
857
858 if (message_port)
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400859 val |= MV88E6XXX_PORT_CTL1_MESSAGE_PORT;
Vivien Didelotea698f42017-03-11 16:12:50 -0500860 else
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400861 val &= ~MV88E6XXX_PORT_CTL1_MESSAGE_PORT;
Vivien Didelotea698f42017-03-11 16:12:50 -0500862
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400863 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val);
Vivien Didelotea698f42017-03-11 16:12:50 -0500864}
865
Tobias Waldekranz57e661a2021-01-13 09:42:54 +0100866int mv88e6xxx_port_set_trunk(struct mv88e6xxx_chip *chip, int port,
867 bool trunk, u8 id)
868{
869 u16 val;
870 int err;
871
872 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val);
873 if (err)
874 return err;
875
876 val &= ~MV88E6XXX_PORT_CTL1_TRUNK_ID_MASK;
877
878 if (trunk)
879 val |= MV88E6XXX_PORT_CTL1_TRUNK_PORT |
880 (id << MV88E6XXX_PORT_CTL1_TRUNK_ID_SHIFT);
881 else
882 val &= ~MV88E6XXX_PORT_CTL1_TRUNK_PORT;
883
884 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val);
885}
886
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100887/* Offset 0x06: Port Based VLAN Map */
888
889int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map)
890{
Vivien Didelot4d294af2017-03-11 16:12:47 -0500891 const u16 mask = mv88e6xxx_port_mask(chip);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100892 u16 reg;
893 int err;
894
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400895 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100896 if (err)
897 return err;
898
899 reg &= ~mask;
900 reg |= map & mask;
901
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400902 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100903 if (err)
904 return err;
905
Vivien Didelot774439e52017-06-08 18:34:08 -0400906 dev_dbg(chip->dev, "p%d: VLANTable set to %.3x\n", port, map);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100907
908 return 0;
909}
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100910
911int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid)
912{
913 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
914 u16 reg;
915 int err;
916
917 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400918 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100919 if (err)
920 return err;
921
922 *fid = (reg & 0xf000) >> 12;
923
924 /* Port's default FID upper bits are located in reg 0x05, offset 0 */
925 if (upper_mask) {
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400926 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,
927 &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100928 if (err)
929 return err;
930
931 *fid |= (reg & upper_mask) << 4;
932 }
933
934 return 0;
935}
936
937int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid)
938{
939 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
940 u16 reg;
941 int err;
942
943 if (fid >= mv88e6xxx_num_databases(chip))
944 return -EINVAL;
945
946 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400947 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100948 if (err)
949 return err;
950
951 reg &= 0x0fff;
952 reg |= (fid & 0x000f) << 12;
953
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400954 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100955 if (err)
956 return err;
957
958 /* Port's default FID upper bits are located in reg 0x05, offset 0 */
959 if (upper_mask) {
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400960 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,
961 &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100962 if (err)
963 return err;
964
965 reg &= ~upper_mask;
966 reg |= (fid >> 4) & upper_mask;
967
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400968 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1,
969 reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100970 if (err)
971 return err;
972 }
973
Vivien Didelot774439e52017-06-08 18:34:08 -0400974 dev_dbg(chip->dev, "p%d: FID set to %u\n", port, fid);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100975
976 return 0;
977}
Vivien Didelot77064f32016-11-04 03:23:30 +0100978
979/* Offset 0x07: Default Port VLAN ID & Priority */
980
981int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid)
982{
983 u16 reg;
984 int err;
985
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400986 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
987 &reg);
Vivien Didelot77064f32016-11-04 03:23:30 +0100988 if (err)
989 return err;
990
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400991 *pvid = reg & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
Vivien Didelot77064f32016-11-04 03:23:30 +0100992
993 return 0;
994}
995
996int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid)
997{
998 u16 reg;
999 int err;
1000
Vivien Didelotb7929fb2017-06-12 12:37:40 -04001001 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
1002 &reg);
Vivien Didelot77064f32016-11-04 03:23:30 +01001003 if (err)
1004 return err;
1005
Vivien Didelotb7929fb2017-06-12 12:37:40 -04001006 reg &= ~MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
1007 reg |= pvid & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
Vivien Didelot77064f32016-11-04 03:23:30 +01001008
Vivien Didelotb7929fb2017-06-12 12:37:40 -04001009 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
1010 reg);
Vivien Didelot77064f32016-11-04 03:23:30 +01001011 if (err)
1012 return err;
1013
Vivien Didelot774439e52017-06-08 18:34:08 -04001014 dev_dbg(chip->dev, "p%d: DefaultVID set to %u\n", port, pvid);
Vivien Didelot77064f32016-11-04 03:23:30 +01001015
1016 return 0;
1017}
Vivien Didelot385a0992016-11-04 03:23:31 +01001018
1019/* Offset 0x08: Port Control 2 Register */
1020
1021static const char * const mv88e6xxx_port_8021q_mode_names[] = {
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001022 [MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED] = "Disabled",
1023 [MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK] = "Fallback",
1024 [MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK] = "Check",
1025 [MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure",
Vivien Didelot385a0992016-11-04 03:23:31 +01001026};
1027
Vladimir Olteana8b659e2021-02-12 17:15:56 +02001028int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip,
1029 int port, bool multicast)
Andrew Lunna23b2962017-02-04 20:15:28 +01001030{
1031 int err;
1032 u16 reg;
1033
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001034 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunna23b2962017-02-04 20:15:28 +01001035 if (err)
1036 return err;
1037
Vivien Didelot601aeed2017-03-11 16:13:00 -05001038 if (multicast)
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001039 reg |= MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;
Andrew Lunna23b2962017-02-04 20:15:28 +01001040 else
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001041 reg &= ~MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;
Andrew Lunna23b2962017-02-04 20:15:28 +01001042
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001043 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunna23b2962017-02-04 20:15:28 +01001044}
1045
1046int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
1047 int upstream_port)
1048{
1049 int err;
1050 u16 reg;
1051
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001052 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunna23b2962017-02-04 20:15:28 +01001053 if (err)
1054 return err;
1055
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001056 reg &= ~MV88E6095_PORT_CTL2_CPU_PORT_MASK;
Andrew Lunna23b2962017-02-04 20:15:28 +01001057 reg |= upstream_port;
1058
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001059 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunna23b2962017-02-04 20:15:28 +01001060}
1061
Iwan R Timmerf0942e02019-11-07 22:11:14 +01001062int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
1063 enum mv88e6xxx_egress_direction direction,
1064 bool mirror)
1065{
1066 bool *mirror_port;
1067 u16 reg;
1068 u16 bit;
1069 int err;
1070
1071 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
1072 if (err)
1073 return err;
1074
1075 switch (direction) {
1076 case MV88E6XXX_EGRESS_DIR_INGRESS:
1077 bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR;
1078 mirror_port = &chip->ports[port].mirror_ingress;
1079 break;
1080 case MV88E6XXX_EGRESS_DIR_EGRESS:
1081 bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR;
1082 mirror_port = &chip->ports[port].mirror_egress;
1083 break;
1084 default:
1085 return -EINVAL;
1086 }
1087
1088 reg &= ~bit;
1089 if (mirror)
1090 reg |= bit;
1091
1092 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
1093 if (!err)
1094 *mirror_port = mirror;
1095
1096 return err;
1097}
1098
Vivien Didelot385a0992016-11-04 03:23:31 +01001099int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
1100 u16 mode)
1101{
1102 u16 reg;
1103 int err;
1104
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001105 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Vivien Didelot385a0992016-11-04 03:23:31 +01001106 if (err)
1107 return err;
1108
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001109 reg &= ~MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;
1110 reg |= mode & MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;
Vivien Didelot385a0992016-11-04 03:23:31 +01001111
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001112 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Vivien Didelot385a0992016-11-04 03:23:31 +01001113 if (err)
1114 return err;
1115
Vivien Didelot774439e52017-06-08 18:34:08 -04001116 dev_dbg(chip->dev, "p%d: 802.1QMode set to %s\n", port,
1117 mv88e6xxx_port_8021q_mode_names[mode]);
Vivien Didelot385a0992016-11-04 03:23:31 +01001118
1119 return 0;
1120}
Andrew Lunnef0a7312016-12-03 04:35:16 +01001121
Andrew Lunna23b2962017-02-04 20:15:28 +01001122int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port)
1123{
1124 u16 reg;
1125 int err;
1126
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001127 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunna23b2962017-02-04 20:15:28 +01001128 if (err)
1129 return err;
1130
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001131 reg |= MV88E6XXX_PORT_CTL2_MAP_DA;
Andrew Lunna23b2962017-02-04 20:15:28 +01001132
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001133 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunna23b2962017-02-04 20:15:28 +01001134}
1135
Vivien Didelotcd782652017-06-08 18:34:13 -04001136int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,
1137 size_t size)
Andrew Lunn5f436662016-12-03 04:45:17 +01001138{
1139 u16 reg;
1140 int err;
1141
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001142 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunn5f436662016-12-03 04:45:17 +01001143 if (err)
1144 return err;
1145
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001146 reg &= ~MV88E6XXX_PORT_CTL2_JUMBO_MODE_MASK;
Vivien Didelotcd782652017-06-08 18:34:13 -04001147
1148 if (size <= 1522)
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001149 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_1522;
Vivien Didelotcd782652017-06-08 18:34:13 -04001150 else if (size <= 2048)
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001151 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_2048;
Vivien Didelotcd782652017-06-08 18:34:13 -04001152 else if (size <= 10240)
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001153 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_10240;
Vivien Didelotcd782652017-06-08 18:34:13 -04001154 else
1155 return -ERANGE;
Andrew Lunn5f436662016-12-03 04:45:17 +01001156
Vivien Didelot81c6edb2017-06-12 12:37:41 -04001157 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunn5f436662016-12-03 04:45:17 +01001158}
1159
Andrew Lunnef70b112016-12-03 04:45:18 +01001160/* Offset 0x09: Port Rate Control */
1161
1162int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
1163{
Vivien Didelot2cb8cb12017-06-12 12:37:42 -04001164 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,
1165 0x0000);
Andrew Lunnef70b112016-12-03 04:45:18 +01001166}
1167
1168int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
1169{
Vivien Didelot2cb8cb12017-06-12 12:37:42 -04001170 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,
1171 0x0001);
Andrew Lunnef70b112016-12-03 04:45:18 +01001172}
1173
Vivien Didelotc8c94892017-03-11 16:13:01 -05001174/* Offset 0x0C: Port ATU Control */
1175
1176int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port)
1177{
Vivien Didelotb8109592017-06-12 12:37:45 -04001178 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ATU_CTL, 0);
Vivien Didelotc8c94892017-03-11 16:13:01 -05001179}
1180
Vivien Didelot9dbfb4e2017-03-11 16:13:02 -05001181/* Offset 0x0D: (Priority) Override Register */
1182
1183int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port)
1184{
Vivien Didelotb8109592017-06-12 12:37:45 -04001185 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0);
Vivien Didelot9dbfb4e2017-03-11 16:13:02 -05001186}
1187
Andrew Lunn56995cb2016-12-03 04:35:19 +01001188/* Offset 0x0f: Port Ether type */
1189
1190int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
1191 u16 etype)
1192{
Vivien Didelotb8109592017-06-12 12:37:45 -04001193 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype);
Andrew Lunn56995cb2016-12-03 04:35:19 +01001194}
1195
Andrew Lunnef0a7312016-12-03 04:35:16 +01001196/* Offset 0x18: Port IEEE Priority Remapping Registers [0-3]
1197 * Offset 0x19: Port IEEE Priority Remapping Registers [4-7]
1198 */
1199
1200int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
1201{
1202 int err;
1203
1204 /* Use a direct priority mapping for all IEEE tagged frames */
Vivien Didelot8009df92017-06-12 12:37:44 -04001205 err = mv88e6xxx_port_write(chip, port,
1206 MV88E6095_PORT_IEEE_PRIO_REMAP_0123,
1207 0x3210);
Andrew Lunnef0a7312016-12-03 04:35:16 +01001208 if (err)
1209 return err;
1210
Vivien Didelot8009df92017-06-12 12:37:44 -04001211 return mv88e6xxx_port_write(chip, port,
1212 MV88E6095_PORT_IEEE_PRIO_REMAP_4567,
1213 0x7654);
Andrew Lunnef0a7312016-12-03 04:35:16 +01001214}
1215
1216static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip,
Vivien Didelotddcbabf2017-06-17 23:07:14 -04001217 int port, u16 table, u8 ptr, u16 data)
Andrew Lunnef0a7312016-12-03 04:35:16 +01001218{
1219 u16 reg;
1220
Vivien Didelotddcbabf2017-06-17 23:07:14 -04001221 reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE | table |
1222 (ptr << __bf_shf(MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_PTR_MASK)) |
1223 (data & MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_DATA_MASK);
Andrew Lunnef0a7312016-12-03 04:35:16 +01001224
Vivien Didelot8009df92017-06-12 12:37:44 -04001225 return mv88e6xxx_port_write(chip, port,
1226 MV88E6390_PORT_IEEE_PRIO_MAP_TABLE, reg);
Andrew Lunnef0a7312016-12-03 04:35:16 +01001227}
1228
1229int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
1230{
1231 int err, i;
Vivien Didelot8009df92017-06-12 12:37:44 -04001232 u16 table;
Andrew Lunnef0a7312016-12-03 04:35:16 +01001233
1234 for (i = 0; i <= 7; i++) {
Vivien Didelot8009df92017-06-12 12:37:44 -04001235 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP;
1236 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i,
1237 (i | i << 4));
Andrew Lunnef0a7312016-12-03 04:35:16 +01001238 if (err)
1239 return err;
1240
Vivien Didelot8009df92017-06-12 12:37:44 -04001241 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP;
1242 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
Andrew Lunnef0a7312016-12-03 04:35:16 +01001243 if (err)
1244 return err;
1245
Vivien Didelot8009df92017-06-12 12:37:44 -04001246 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP;
1247 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
Andrew Lunnef0a7312016-12-03 04:35:16 +01001248 if (err)
1249 return err;
1250
Vivien Didelot8009df92017-06-12 12:37:44 -04001251 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP;
1252 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
Andrew Lunnef0a7312016-12-03 04:35:16 +01001253 if (err)
1254 return err;
1255 }
1256
1257 return 0;
1258}
Vivien Didelotf3a2cd32019-09-07 16:00:48 -04001259
1260/* Offset 0x0E: Policy Control Register */
1261
1262int mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port,
1263 enum mv88e6xxx_policy_mapping mapping,
1264 enum mv88e6xxx_policy_action action)
1265{
1266 u16 reg, mask, val;
1267 int shift;
1268 int err;
1269
1270 switch (mapping) {
1271 case MV88E6XXX_POLICY_MAPPING_DA:
1272 shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_DA_MASK);
1273 mask = MV88E6XXX_PORT_POLICY_CTL_DA_MASK;
1274 break;
1275 case MV88E6XXX_POLICY_MAPPING_SA:
1276 shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_SA_MASK);
1277 mask = MV88E6XXX_PORT_POLICY_CTL_SA_MASK;
1278 break;
1279 case MV88E6XXX_POLICY_MAPPING_VTU:
1280 shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VTU_MASK);
1281 mask = MV88E6XXX_PORT_POLICY_CTL_VTU_MASK;
1282 break;
1283 case MV88E6XXX_POLICY_MAPPING_ETYPE:
1284 shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK);
1285 mask = MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK;
1286 break;
1287 case MV88E6XXX_POLICY_MAPPING_PPPOE:
1288 shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK);
1289 mask = MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK;
1290 break;
1291 case MV88E6XXX_POLICY_MAPPING_VBAS:
1292 shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK);
1293 mask = MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK;
1294 break;
1295 case MV88E6XXX_POLICY_MAPPING_OPT82:
1296 shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK);
1297 mask = MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK;
1298 break;
1299 case MV88E6XXX_POLICY_MAPPING_UDP:
1300 shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_UDP_MASK);
1301 mask = MV88E6XXX_PORT_POLICY_CTL_UDP_MASK;
1302 break;
1303 default:
1304 return -EOPNOTSUPP;
1305 }
1306
1307 switch (action) {
1308 case MV88E6XXX_POLICY_ACTION_NORMAL:
1309 val = MV88E6XXX_PORT_POLICY_CTL_NORMAL;
1310 break;
1311 case MV88E6XXX_POLICY_ACTION_MIRROR:
1312 val = MV88E6XXX_PORT_POLICY_CTL_MIRROR;
1313 break;
1314 case MV88E6XXX_POLICY_ACTION_TRAP:
1315 val = MV88E6XXX_PORT_POLICY_CTL_TRAP;
1316 break;
1317 case MV88E6XXX_POLICY_ACTION_DISCARD:
1318 val = MV88E6XXX_PORT_POLICY_CTL_DISCARD;
1319 break;
1320 default:
1321 return -EOPNOTSUPP;
1322 }
1323
1324 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_POLICY_CTL, &reg);
1325 if (err)
1326 return err;
1327
1328 reg &= ~mask;
1329 reg |= (val << shift) & mask;
1330
1331 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_POLICY_CTL, reg);
1332}