blob: 73d825e08be386646eb7471b1bfe70ac2df9dfc0 [file] [log] [blame]
Vivien Didelot18abed22016-11-04 03:23:26 +01001/*
2 * Marvell 88E6xxx Switch Port Registers support
3 *
4 * Copyright (c) 2008 Marvell Semiconductor
5 *
Vivien Didelot4333d612017-03-28 15:10:36 -04006 * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
7 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Vivien Didelot18abed22016-11-04 03:23:26 +01008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 */
14
Vivien Didelotf894c292017-06-08 18:34:10 -040015#include <linux/if_bridge.h>
Andrew Lunnf39908d2017-02-04 20:02:50 +010016#include <linux/phy.h>
Vivien Didelot4d5f2ba72017-06-02 17:06:15 -040017
18#include "chip.h"
Vivien Didelot18abed22016-11-04 03:23:26 +010019#include "port.h"
20
21int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
22 u16 *val)
23{
24 int addr = chip->info->port_base_addr + port;
25
26 return mv88e6xxx_read(chip, addr, reg, val);
27}
28
29int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
30 u16 val)
31{
32 int addr = chip->info->port_base_addr + port;
33
34 return mv88e6xxx_write(chip, addr, reg, val);
35}
Vivien Didelote28def332016-11-04 03:23:27 +010036
Vivien Didelot08ef7f12016-11-04 03:23:32 +010037/* Offset 0x01: MAC (or PCS or Physical) Control Register
38 *
39 * Link, Duplex and Flow Control have one force bit, one value bit.
Vivien Didelot96a2b402016-11-04 03:23:35 +010040 *
41 * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value.
42 * Alternative values require the 200BASE (or AltSpeed) bit 12 set.
43 * Newer chips need a ForcedSpd bit 13 set to consider the value.
Vivien Didelot08ef7f12016-11-04 03:23:32 +010044 */
45
Vivien Didelota0a0f622016-11-04 03:23:34 +010046static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
47 phy_interface_t mode)
48{
49 u16 reg;
50 int err;
51
Vivien Didelot5ee55572017-06-12 12:37:34 -040052 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelota0a0f622016-11-04 03:23:34 +010053 if (err)
54 return err;
55
Vivien Didelot5ee55572017-06-12 12:37:34 -040056 reg &= ~(MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
57 MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK);
Vivien Didelota0a0f622016-11-04 03:23:34 +010058
59 switch (mode) {
60 case PHY_INTERFACE_MODE_RGMII_RXID:
Vivien Didelot5ee55572017-06-12 12:37:34 -040061 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK;
Vivien Didelota0a0f622016-11-04 03:23:34 +010062 break;
63 case PHY_INTERFACE_MODE_RGMII_TXID:
Vivien Didelot5ee55572017-06-12 12:37:34 -040064 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
Vivien Didelota0a0f622016-11-04 03:23:34 +010065 break;
66 case PHY_INTERFACE_MODE_RGMII_ID:
Vivien Didelot5ee55572017-06-12 12:37:34 -040067 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
68 MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
Vivien Didelota0a0f622016-11-04 03:23:34 +010069 break;
Andrew Lunnfedf1862016-11-10 15:44:00 +010070 case PHY_INTERFACE_MODE_RGMII:
Vivien Didelota0a0f622016-11-04 03:23:34 +010071 break;
Andrew Lunnfedf1862016-11-10 15:44:00 +010072 default:
73 return 0;
Vivien Didelota0a0f622016-11-04 03:23:34 +010074 }
75
Vivien Didelot5ee55572017-06-12 12:37:34 -040076 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelota0a0f622016-11-04 03:23:34 +010077 if (err)
78 return err;
79
Vivien Didelot774439e52017-06-08 18:34:08 -040080 dev_dbg(chip->dev, "p%d: delay RXCLK %s, TXCLK %s\n", port,
Vivien Didelot5ee55572017-06-12 12:37:34 -040081 reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK ? "yes" : "no",
82 reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK ? "yes" : "no");
Vivien Didelota0a0f622016-11-04 03:23:34 +010083
84 return 0;
85}
86
87int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
88 phy_interface_t mode)
89{
90 if (port < 5)
91 return -EOPNOTSUPP;
92
93 return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
94}
95
96int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
97 phy_interface_t mode)
98{
99 if (port != 0)
100 return -EOPNOTSUPP;
101
102 return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
103}
104
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100105int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link)
106{
107 u16 reg;
108 int err;
109
Vivien Didelot5ee55572017-06-12 12:37:34 -0400110 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100111 if (err)
112 return err;
113
Vivien Didelot5ee55572017-06-12 12:37:34 -0400114 reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
115 MV88E6XXX_PORT_MAC_CTL_LINK_UP);
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100116
117 switch (link) {
118 case LINK_FORCED_DOWN:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400119 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK;
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100120 break;
121 case LINK_FORCED_UP:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400122 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
123 MV88E6XXX_PORT_MAC_CTL_LINK_UP;
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100124 break;
125 case LINK_UNFORCED:
126 /* normal link detection */
127 break;
128 default:
129 return -EINVAL;
130 }
131
Vivien Didelot5ee55572017-06-12 12:37:34 -0400132 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100133 if (err)
134 return err;
135
Vivien Didelot774439e52017-06-08 18:34:08 -0400136 dev_dbg(chip->dev, "p%d: %s link %s\n", port,
Vivien Didelot5ee55572017-06-12 12:37:34 -0400137 reg & MV88E6XXX_PORT_MAC_CTL_FORCE_LINK ? "Force" : "Unforce",
138 reg & MV88E6XXX_PORT_MAC_CTL_LINK_UP ? "up" : "down");
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100139
140 return 0;
141}
142
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100143int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup)
144{
145 u16 reg;
146 int err;
147
Vivien Didelot5ee55572017-06-12 12:37:34 -0400148 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100149 if (err)
150 return err;
151
Vivien Didelot5ee55572017-06-12 12:37:34 -0400152 reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
153 MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100154
155 switch (dup) {
156 case DUPLEX_HALF:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400157 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100158 break;
159 case DUPLEX_FULL:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400160 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
161 MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100162 break;
163 case DUPLEX_UNFORCED:
164 /* normal duplex detection */
165 break;
166 default:
167 return -EINVAL;
168 }
169
Vivien Didelot5ee55572017-06-12 12:37:34 -0400170 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100171 if (err)
172 return err;
173
Vivien Didelot774439e52017-06-08 18:34:08 -0400174 dev_dbg(chip->dev, "p%d: %s %s duplex\n", port,
Vivien Didelot5ee55572017-06-12 12:37:34 -0400175 reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce",
176 reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half");
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100177
178 return 0;
179}
180
Vivien Didelot96a2b402016-11-04 03:23:35 +0100181static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port,
182 int speed, bool alt_bit, bool force_bit)
183{
184 u16 reg, ctrl;
185 int err;
186
187 switch (speed) {
188 case 10:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400189 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100190 break;
191 case 100:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400192 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100193 break;
194 case 200:
195 if (alt_bit)
Vivien Didelot5ee55572017-06-12 12:37:34 -0400196 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |
197 MV88E6390_PORT_MAC_CTL_ALTSPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100198 else
Vivien Didelot5ee55572017-06-12 12:37:34 -0400199 ctrl = MV88E6065_PORT_MAC_CTL_SPEED_200;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100200 break;
201 case 1000:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400202 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100203 break;
204 case 2500:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400205 ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
206 MV88E6390_PORT_MAC_CTL_ALTSPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100207 break;
208 case 10000:
209 /* all bits set, fall through... */
210 case SPEED_UNFORCED:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400211 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100212 break;
213 default:
214 return -EOPNOTSUPP;
215 }
216
Vivien Didelot5ee55572017-06-12 12:37:34 -0400217 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100218 if (err)
219 return err;
220
Vivien Didelot5ee55572017-06-12 12:37:34 -0400221 reg &= ~MV88E6XXX_PORT_MAC_CTL_SPEED_MASK;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100222 if (alt_bit)
Vivien Didelot5ee55572017-06-12 12:37:34 -0400223 reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100224 if (force_bit) {
Vivien Didelot5ee55572017-06-12 12:37:34 -0400225 reg &= ~MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
Andrew Lunn0b6e3d02016-11-16 04:26:48 +0100226 if (speed != SPEED_UNFORCED)
Vivien Didelot5ee55572017-06-12 12:37:34 -0400227 ctrl |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100228 }
229 reg |= ctrl;
230
Vivien Didelot5ee55572017-06-12 12:37:34 -0400231 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100232 if (err)
233 return err;
234
235 if (speed)
Vivien Didelot774439e52017-06-08 18:34:08 -0400236 dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100237 else
Vivien Didelot774439e52017-06-08 18:34:08 -0400238 dev_dbg(chip->dev, "p%d: Speed unforced\n", port);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100239
240 return 0;
241}
242
243/* Support 10, 100, 200 Mbps (e.g. 88E6065 family) */
244int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
245{
246 if (speed == SPEED_MAX)
247 speed = 200;
248
249 if (speed > 200)
250 return -EOPNOTSUPP;
251
252 /* Setting 200 Mbps on port 0 to 3 selects 100 Mbps */
253 return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
254}
255
256/* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */
257int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
258{
259 if (speed == SPEED_MAX)
260 speed = 1000;
261
262 if (speed == 200 || speed > 1000)
263 return -EOPNOTSUPP;
264
265 return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
266}
267
268/* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */
269int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
270{
271 if (speed == SPEED_MAX)
272 speed = 1000;
273
274 if (speed > 1000)
275 return -EOPNOTSUPP;
276
277 if (speed == 200 && port < 5)
278 return -EOPNOTSUPP;
279
280 return mv88e6xxx_port_set_speed(chip, port, speed, true, false);
281}
282
283/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */
284int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
285{
286 if (speed == SPEED_MAX)
287 speed = port < 9 ? 1000 : 2500;
288
289 if (speed > 2500)
290 return -EOPNOTSUPP;
291
292 if (speed == 200 && port != 0)
293 return -EOPNOTSUPP;
294
295 if (speed == 2500 && port < 9)
296 return -EOPNOTSUPP;
297
298 return mv88e6xxx_port_set_speed(chip, port, speed, true, true);
299}
300
301/* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */
302int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
303{
304 if (speed == SPEED_MAX)
305 speed = port < 9 ? 1000 : 10000;
306
307 if (speed == 200 && port != 0)
308 return -EOPNOTSUPP;
309
310 if (speed >= 2500 && port < 9)
311 return -EOPNOTSUPP;
312
313 return mv88e6xxx_port_set_speed(chip, port, speed, true, true);
314}
315
Andrew Lunnf39908d2017-02-04 20:02:50 +0100316int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
317 phy_interface_t mode)
318{
319 u16 reg;
320 u16 cmode;
321 int err;
322
323 if (mode == PHY_INTERFACE_MODE_NA)
324 return 0;
325
326 if (port != 9 && port != 10)
327 return -EOPNOTSUPP;
328
329 switch (mode) {
330 case PHY_INTERFACE_MODE_1000BASEX:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400331 cmode = MV88E6XXX_PORT_STS_CMODE_1000BASE_X;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100332 break;
333 case PHY_INTERFACE_MODE_SGMII:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400334 cmode = MV88E6XXX_PORT_STS_CMODE_SGMII;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100335 break;
336 case PHY_INTERFACE_MODE_2500BASEX:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400337 cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100338 break;
339 case PHY_INTERFACE_MODE_XGMII:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400340 cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100341 break;
342 case PHY_INTERFACE_MODE_RXAUI:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400343 cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100344 break;
345 default:
346 cmode = 0;
347 }
348
349 if (cmode) {
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400350 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
Andrew Lunnf39908d2017-02-04 20:02:50 +0100351 if (err)
352 return err;
353
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400354 reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100355 reg |= cmode;
356
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400357 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
Andrew Lunnf39908d2017-02-04 20:02:50 +0100358 if (err)
359 return err;
360 }
361
362 return 0;
363}
364
365int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
366{
367 int err;
368 u16 reg;
369
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400370 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
Andrew Lunnf39908d2017-02-04 20:02:50 +0100371 if (err)
372 return err;
373
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400374 *cmode = reg & MV88E6XXX_PORT_STS_CMODE_MASK;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100375
376 return 0;
377}
378
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400379/* Offset 0x02: Jamming Control
Andrew Lunnb35d322a2016-12-03 04:45:19 +0100380 *
381 * Do not limit the period of time that this port can be paused for by
382 * the remote end or the period of time that this port can pause the
383 * remote end.
384 */
Vivien Didelot08984322017-06-08 18:34:12 -0400385int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
386 u8 out)
Andrew Lunnb35d322a2016-12-03 04:45:19 +0100387{
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400388 return mv88e6xxx_port_write(chip, port, MV88E6097_PORT_JAM_CTL,
389 out << 8 | in);
Andrew Lunnb35d322a2016-12-03 04:45:19 +0100390}
391
Vivien Didelot08984322017-06-08 18:34:12 -0400392int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
393 u8 out)
Andrew Lunn3ce0e652016-12-03 04:45:20 +0100394{
395 int err;
396
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400397 err = mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,
398 MV88E6390_PORT_FLOW_CTL_UPDATE |
399 MV88E6390_PORT_FLOW_CTL_LIMIT_IN | in);
Andrew Lunn3ce0e652016-12-03 04:45:20 +0100400 if (err)
401 return err;
402
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400403 return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,
404 MV88E6390_PORT_FLOW_CTL_UPDATE |
405 MV88E6390_PORT_FLOW_CTL_LIMIT_OUT | out);
Andrew Lunn3ce0e652016-12-03 04:45:20 +0100406}
407
Vivien Didelote28def332016-11-04 03:23:27 +0100408/* Offset 0x04: Port Control Register */
409
410static const char * const mv88e6xxx_port_state_names[] = {
Vivien Didelota89b433be2017-06-12 12:37:37 -0400411 [MV88E6XXX_PORT_CTL0_STATE_DISABLED] = "Disabled",
412 [MV88E6XXX_PORT_CTL0_STATE_BLOCKING] = "Blocking/Listening",
413 [MV88E6XXX_PORT_CTL0_STATE_LEARNING] = "Learning",
414 [MV88E6XXX_PORT_CTL0_STATE_FORWARDING] = "Forwarding",
Vivien Didelote28def332016-11-04 03:23:27 +0100415};
416
417int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state)
418{
419 u16 reg;
420 int err;
421
Vivien Didelota89b433be2017-06-12 12:37:37 -0400422 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Vivien Didelote28def332016-11-04 03:23:27 +0100423 if (err)
424 return err;
425
Vivien Didelota89b433be2017-06-12 12:37:37 -0400426 reg &= ~MV88E6XXX_PORT_CTL0_STATE_MASK;
Vivien Didelotf894c292017-06-08 18:34:10 -0400427
428 switch (state) {
429 case BR_STATE_DISABLED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400430 state = MV88E6XXX_PORT_CTL0_STATE_DISABLED;
Vivien Didelotf894c292017-06-08 18:34:10 -0400431 break;
432 case BR_STATE_BLOCKING:
433 case BR_STATE_LISTENING:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400434 state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING;
Vivien Didelotf894c292017-06-08 18:34:10 -0400435 break;
436 case BR_STATE_LEARNING:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400437 state = MV88E6XXX_PORT_CTL0_STATE_LEARNING;
Vivien Didelotf894c292017-06-08 18:34:10 -0400438 break;
439 case BR_STATE_FORWARDING:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400440 state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
Vivien Didelotf894c292017-06-08 18:34:10 -0400441 break;
442 default:
443 return -EINVAL;
444 }
445
Vivien Didelote28def332016-11-04 03:23:27 +0100446 reg |= state;
447
Vivien Didelota89b433be2017-06-12 12:37:37 -0400448 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Vivien Didelote28def332016-11-04 03:23:27 +0100449 if (err)
450 return err;
451
Vivien Didelot774439e52017-06-08 18:34:08 -0400452 dev_dbg(chip->dev, "p%d: PortState set to %s\n", port,
453 mv88e6xxx_port_state_names[state]);
Vivien Didelote28def332016-11-04 03:23:27 +0100454
455 return 0;
456}
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100457
Andrew Lunn56995cb2016-12-03 04:35:19 +0100458int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port,
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400459 enum mv88e6xxx_egress_mode mode)
Andrew Lunn56995cb2016-12-03 04:35:19 +0100460{
461 int err;
462 u16 reg;
463
Vivien Didelota89b433be2017-06-12 12:37:37 -0400464 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100465 if (err)
466 return err;
467
Vivien Didelota89b433be2017-06-12 12:37:37 -0400468 reg &= ~MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400469
470 switch (mode) {
471 case MV88E6XXX_EGRESS_MODE_UNMODIFIED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400472 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400473 break;
474 case MV88E6XXX_EGRESS_MODE_UNTAGGED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400475 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400476 break;
477 case MV88E6XXX_EGRESS_MODE_TAGGED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400478 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400479 break;
480 case MV88E6XXX_EGRESS_MODE_ETHERTYPE:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400481 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400482 break;
483 default:
484 return -EINVAL;
485 }
Andrew Lunn56995cb2016-12-03 04:35:19 +0100486
Vivien Didelota89b433be2017-06-12 12:37:37 -0400487 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100488}
489
490int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
491 enum mv88e6xxx_frame_mode mode)
492{
493 int err;
494 u16 reg;
495
Vivien Didelota89b433be2017-06-12 12:37:37 -0400496 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100497 if (err)
498 return err;
499
Vivien Didelota89b433be2017-06-12 12:37:37 -0400500 reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100501
502 switch (mode) {
503 case MV88E6XXX_FRAME_MODE_NORMAL:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400504 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100505 break;
506 case MV88E6XXX_FRAME_MODE_DSA:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400507 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100508 break;
509 default:
510 return -EINVAL;
511 }
512
Vivien Didelota89b433be2017-06-12 12:37:37 -0400513 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100514}
515
516int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
517 enum mv88e6xxx_frame_mode mode)
518{
519 int err;
520 u16 reg;
521
Vivien Didelota89b433be2017-06-12 12:37:37 -0400522 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100523 if (err)
524 return err;
525
Vivien Didelota89b433be2017-06-12 12:37:37 -0400526 reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100527
528 switch (mode) {
529 case MV88E6XXX_FRAME_MODE_NORMAL:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400530 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100531 break;
532 case MV88E6XXX_FRAME_MODE_DSA:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400533 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100534 break;
535 case MV88E6XXX_FRAME_MODE_PROVIDER:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400536 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_PROVIDER;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100537 break;
538 case MV88E6XXX_FRAME_MODE_ETHERTYPE:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400539 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_ETHER_TYPE_DSA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100540 break;
541 default:
542 return -EINVAL;
543 }
544
Vivien Didelota89b433be2017-06-12 12:37:37 -0400545 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100546}
547
Vivien Didelot601aeed2017-03-11 16:13:00 -0500548static int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip,
549 int port, bool unicast)
Andrew Lunn56995cb2016-12-03 04:35:19 +0100550{
551 int err;
552 u16 reg;
553
Vivien Didelota89b433be2017-06-12 12:37:37 -0400554 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100555 if (err)
556 return err;
557
Vivien Didelot601aeed2017-03-11 16:13:00 -0500558 if (unicast)
Vivien Didelota89b433be2017-06-12 12:37:37 -0400559 reg |= MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100560 else
Vivien Didelota89b433be2017-06-12 12:37:37 -0400561 reg &= ~MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100562
Vivien Didelota89b433be2017-06-12 12:37:37 -0400563 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100564}
565
Vivien Didelot601aeed2017-03-11 16:13:00 -0500566int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
567 bool unicast, bool multicast)
Andrew Lunn56995cb2016-12-03 04:35:19 +0100568{
569 int err;
570 u16 reg;
571
Vivien Didelota89b433be2017-06-12 12:37:37 -0400572 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100573 if (err)
574 return err;
575
Vivien Didelota89b433be2017-06-12 12:37:37 -0400576 reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MASK;
Vivien Didelot601aeed2017-03-11 16:13:00 -0500577
578 if (unicast && multicast)
Vivien Didelota89b433be2017-06-12 12:37:37 -0400579 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_ALL_UNKNOWN_DA;
Vivien Didelot601aeed2017-03-11 16:13:00 -0500580 else if (unicast)
Vivien Didelota89b433be2017-06-12 12:37:37 -0400581 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_MC_DA;
Vivien Didelot601aeed2017-03-11 16:13:00 -0500582 else if (multicast)
Vivien Didelota89b433be2017-06-12 12:37:37 -0400583 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_UC_DA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100584 else
Vivien Didelota89b433be2017-06-12 12:37:37 -0400585 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_DA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100586
Vivien Didelota89b433be2017-06-12 12:37:37 -0400587 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100588}
589
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100590/* Offset 0x05: Port Control 1 */
591
Vivien Didelotea698f42017-03-11 16:12:50 -0500592int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,
593 bool message_port)
594{
595 u16 val;
596 int err;
597
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400598 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val);
Vivien Didelotea698f42017-03-11 16:12:50 -0500599 if (err)
600 return err;
601
602 if (message_port)
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400603 val |= MV88E6XXX_PORT_CTL1_MESSAGE_PORT;
Vivien Didelotea698f42017-03-11 16:12:50 -0500604 else
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400605 val &= ~MV88E6XXX_PORT_CTL1_MESSAGE_PORT;
Vivien Didelotea698f42017-03-11 16:12:50 -0500606
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400607 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val);
Vivien Didelotea698f42017-03-11 16:12:50 -0500608}
609
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100610/* Offset 0x06: Port Based VLAN Map */
611
612int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map)
613{
Vivien Didelot4d294af2017-03-11 16:12:47 -0500614 const u16 mask = mv88e6xxx_port_mask(chip);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100615 u16 reg;
616 int err;
617
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400618 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100619 if (err)
620 return err;
621
622 reg &= ~mask;
623 reg |= map & mask;
624
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400625 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100626 if (err)
627 return err;
628
Vivien Didelot774439e52017-06-08 18:34:08 -0400629 dev_dbg(chip->dev, "p%d: VLANTable set to %.3x\n", port, map);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100630
631 return 0;
632}
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100633
634int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid)
635{
636 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
637 u16 reg;
638 int err;
639
640 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400641 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100642 if (err)
643 return err;
644
645 *fid = (reg & 0xf000) >> 12;
646
647 /* Port's default FID upper bits are located in reg 0x05, offset 0 */
648 if (upper_mask) {
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400649 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,
650 &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100651 if (err)
652 return err;
653
654 *fid |= (reg & upper_mask) << 4;
655 }
656
657 return 0;
658}
659
660int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid)
661{
662 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
663 u16 reg;
664 int err;
665
666 if (fid >= mv88e6xxx_num_databases(chip))
667 return -EINVAL;
668
669 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400670 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100671 if (err)
672 return err;
673
674 reg &= 0x0fff;
675 reg |= (fid & 0x000f) << 12;
676
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400677 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100678 if (err)
679 return err;
680
681 /* Port's default FID upper bits are located in reg 0x05, offset 0 */
682 if (upper_mask) {
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400683 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,
684 &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100685 if (err)
686 return err;
687
688 reg &= ~upper_mask;
689 reg |= (fid >> 4) & upper_mask;
690
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400691 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1,
692 reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100693 if (err)
694 return err;
695 }
696
Vivien Didelot774439e52017-06-08 18:34:08 -0400697 dev_dbg(chip->dev, "p%d: FID set to %u\n", port, fid);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100698
699 return 0;
700}
Vivien Didelot77064f32016-11-04 03:23:30 +0100701
702/* Offset 0x07: Default Port VLAN ID & Priority */
703
704int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid)
705{
706 u16 reg;
707 int err;
708
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400709 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
710 &reg);
Vivien Didelot77064f32016-11-04 03:23:30 +0100711 if (err)
712 return err;
713
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400714 *pvid = reg & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
Vivien Didelot77064f32016-11-04 03:23:30 +0100715
716 return 0;
717}
718
719int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid)
720{
721 u16 reg;
722 int err;
723
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400724 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
725 &reg);
Vivien Didelot77064f32016-11-04 03:23:30 +0100726 if (err)
727 return err;
728
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400729 reg &= ~MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
730 reg |= pvid & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
Vivien Didelot77064f32016-11-04 03:23:30 +0100731
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400732 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
733 reg);
Vivien Didelot77064f32016-11-04 03:23:30 +0100734 if (err)
735 return err;
736
Vivien Didelot774439e52017-06-08 18:34:08 -0400737 dev_dbg(chip->dev, "p%d: DefaultVID set to %u\n", port, pvid);
Vivien Didelot77064f32016-11-04 03:23:30 +0100738
739 return 0;
740}
Vivien Didelot385a0992016-11-04 03:23:31 +0100741
742/* Offset 0x08: Port Control 2 Register */
743
744static const char * const mv88e6xxx_port_8021q_mode_names[] = {
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400745 [MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED] = "Disabled",
746 [MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK] = "Fallback",
747 [MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK] = "Check",
748 [MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure",
Vivien Didelot385a0992016-11-04 03:23:31 +0100749};
750
Vivien Didelot601aeed2017-03-11 16:13:00 -0500751static int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip,
752 int port, bool multicast)
Andrew Lunna23b2962017-02-04 20:15:28 +0100753{
754 int err;
755 u16 reg;
756
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400757 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100758 if (err)
759 return err;
760
Vivien Didelot601aeed2017-03-11 16:13:00 -0500761 if (multicast)
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400762 reg |= MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;
Andrew Lunna23b2962017-02-04 20:15:28 +0100763 else
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400764 reg &= ~MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;
Andrew Lunna23b2962017-02-04 20:15:28 +0100765
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400766 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100767}
768
Vivien Didelot601aeed2017-03-11 16:13:00 -0500769int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
770 bool unicast, bool multicast)
771{
772 int err;
773
774 err = mv88e6185_port_set_forward_unknown(chip, port, unicast);
775 if (err)
776 return err;
777
778 return mv88e6185_port_set_default_forward(chip, port, multicast);
779}
780
Andrew Lunna23b2962017-02-04 20:15:28 +0100781int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
782 int upstream_port)
783{
784 int err;
785 u16 reg;
786
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400787 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100788 if (err)
789 return err;
790
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400791 reg &= ~MV88E6095_PORT_CTL2_CPU_PORT_MASK;
Andrew Lunna23b2962017-02-04 20:15:28 +0100792 reg |= upstream_port;
793
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400794 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100795}
796
Vivien Didelot385a0992016-11-04 03:23:31 +0100797int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
798 u16 mode)
799{
800 u16 reg;
801 int err;
802
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400803 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Vivien Didelot385a0992016-11-04 03:23:31 +0100804 if (err)
805 return err;
806
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400807 reg &= ~MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;
808 reg |= mode & MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;
Vivien Didelot385a0992016-11-04 03:23:31 +0100809
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400810 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Vivien Didelot385a0992016-11-04 03:23:31 +0100811 if (err)
812 return err;
813
Vivien Didelot774439e52017-06-08 18:34:08 -0400814 dev_dbg(chip->dev, "p%d: 802.1QMode set to %s\n", port,
815 mv88e6xxx_port_8021q_mode_names[mode]);
Vivien Didelot385a0992016-11-04 03:23:31 +0100816
817 return 0;
818}
Andrew Lunnef0a7312016-12-03 04:35:16 +0100819
Andrew Lunna23b2962017-02-04 20:15:28 +0100820int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port)
821{
822 u16 reg;
823 int err;
824
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400825 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100826 if (err)
827 return err;
828
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400829 reg |= MV88E6XXX_PORT_CTL2_MAP_DA;
Andrew Lunna23b2962017-02-04 20:15:28 +0100830
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400831 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100832}
833
Vivien Didelotcd782652017-06-08 18:34:13 -0400834int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,
835 size_t size)
Andrew Lunn5f436662016-12-03 04:45:17 +0100836{
837 u16 reg;
838 int err;
839
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400840 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunn5f436662016-12-03 04:45:17 +0100841 if (err)
842 return err;
843
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400844 reg &= ~MV88E6XXX_PORT_CTL2_JUMBO_MODE_MASK;
Vivien Didelotcd782652017-06-08 18:34:13 -0400845
846 if (size <= 1522)
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400847 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_1522;
Vivien Didelotcd782652017-06-08 18:34:13 -0400848 else if (size <= 2048)
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400849 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_2048;
Vivien Didelotcd782652017-06-08 18:34:13 -0400850 else if (size <= 10240)
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400851 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_10240;
Vivien Didelotcd782652017-06-08 18:34:13 -0400852 else
853 return -ERANGE;
Andrew Lunn5f436662016-12-03 04:45:17 +0100854
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400855 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunn5f436662016-12-03 04:45:17 +0100856}
857
Andrew Lunnef70b112016-12-03 04:45:18 +0100858/* Offset 0x09: Port Rate Control */
859
860int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
861{
Vivien Didelot2cb8cb12017-06-12 12:37:42 -0400862 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,
863 0x0000);
Andrew Lunnef70b112016-12-03 04:45:18 +0100864}
865
866int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
867{
Vivien Didelot2cb8cb12017-06-12 12:37:42 -0400868 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,
869 0x0001);
Andrew Lunnef70b112016-12-03 04:45:18 +0100870}
871
Vivien Didelotc8c94892017-03-11 16:13:01 -0500872/* Offset 0x0C: Port ATU Control */
873
874int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port)
875{
Vivien Didelotb8109592017-06-12 12:37:45 -0400876 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ATU_CTL, 0);
Vivien Didelotc8c94892017-03-11 16:13:01 -0500877}
878
Vivien Didelot9dbfb4e2017-03-11 16:13:02 -0500879/* Offset 0x0D: (Priority) Override Register */
880
881int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port)
882{
Vivien Didelotb8109592017-06-12 12:37:45 -0400883 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0);
Vivien Didelot9dbfb4e2017-03-11 16:13:02 -0500884}
885
Andrew Lunn56995cb2016-12-03 04:35:19 +0100886/* Offset 0x0f: Port Ether type */
887
888int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
889 u16 etype)
890{
Vivien Didelotb8109592017-06-12 12:37:45 -0400891 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100892}
893
Andrew Lunnef0a7312016-12-03 04:35:16 +0100894/* Offset 0x18: Port IEEE Priority Remapping Registers [0-3]
895 * Offset 0x19: Port IEEE Priority Remapping Registers [4-7]
896 */
897
898int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
899{
900 int err;
901
902 /* Use a direct priority mapping for all IEEE tagged frames */
Vivien Didelot8009df92017-06-12 12:37:44 -0400903 err = mv88e6xxx_port_write(chip, port,
904 MV88E6095_PORT_IEEE_PRIO_REMAP_0123,
905 0x3210);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100906 if (err)
907 return err;
908
Vivien Didelot8009df92017-06-12 12:37:44 -0400909 return mv88e6xxx_port_write(chip, port,
910 MV88E6095_PORT_IEEE_PRIO_REMAP_4567,
911 0x7654);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100912}
913
914static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip,
915 int port, u16 table,
916 u8 pointer, u16 data)
917{
918 u16 reg;
919
Vivien Didelot8009df92017-06-12 12:37:44 -0400920 reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE |
Andrew Lunnef0a7312016-12-03 04:35:16 +0100921 table |
Vivien Didelot8009df92017-06-12 12:37:44 -0400922 (pointer << MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT) |
Andrew Lunnef0a7312016-12-03 04:35:16 +0100923 data;
924
Vivien Didelot8009df92017-06-12 12:37:44 -0400925 return mv88e6xxx_port_write(chip, port,
926 MV88E6390_PORT_IEEE_PRIO_MAP_TABLE, reg);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100927}
928
929int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
930{
931 int err, i;
Vivien Didelot8009df92017-06-12 12:37:44 -0400932 u16 table;
Andrew Lunnef0a7312016-12-03 04:35:16 +0100933
934 for (i = 0; i <= 7; i++) {
Vivien Didelot8009df92017-06-12 12:37:44 -0400935 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP;
936 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i,
937 (i | i << 4));
Andrew Lunnef0a7312016-12-03 04:35:16 +0100938 if (err)
939 return err;
940
Vivien Didelot8009df92017-06-12 12:37:44 -0400941 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP;
942 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100943 if (err)
944 return err;
945
Vivien Didelot8009df92017-06-12 12:37:44 -0400946 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP;
947 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100948 if (err)
949 return err;
950
Vivien Didelot8009df92017-06-12 12:37:44 -0400951 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP;
952 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100953 if (err)
954 return err;
955 }
956
957 return 0;
958}