blob: a7801f6668a5d0e394fd01078bb10c50998cdf56 [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 Didelotddcbabf2017-06-17 23:07:14 -040015#include <linux/bitfield.h>
Vivien Didelotf894c292017-06-08 18:34:10 -040016#include <linux/if_bridge.h>
Andrew Lunnf39908d2017-02-04 20:02:50 +010017#include <linux/phy.h>
Vivien Didelot4d5f2ba72017-06-02 17:06:15 -040018
19#include "chip.h"
Vivien Didelot18abed22016-11-04 03:23:26 +010020#include "port.h"
21
22int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
23 u16 *val)
24{
25 int addr = chip->info->port_base_addr + port;
26
27 return mv88e6xxx_read(chip, addr, reg, val);
28}
29
30int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
31 u16 val)
32{
33 int addr = chip->info->port_base_addr + port;
34
35 return mv88e6xxx_write(chip, addr, reg, val);
36}
Vivien Didelote28def332016-11-04 03:23:27 +010037
Vivien Didelot08ef7f12016-11-04 03:23:32 +010038/* Offset 0x01: MAC (or PCS or Physical) Control Register
39 *
40 * Link, Duplex and Flow Control have one force bit, one value bit.
Vivien Didelot96a2b402016-11-04 03:23:35 +010041 *
42 * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value.
43 * Alternative values require the 200BASE (or AltSpeed) bit 12 set.
44 * Newer chips need a ForcedSpd bit 13 set to consider the value.
Vivien Didelot08ef7f12016-11-04 03:23:32 +010045 */
46
Vivien Didelota0a0f622016-11-04 03:23:34 +010047static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
48 phy_interface_t mode)
49{
50 u16 reg;
51 int err;
52
Vivien Didelot5ee55572017-06-12 12:37:34 -040053 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelota0a0f622016-11-04 03:23:34 +010054 if (err)
55 return err;
56
Vivien Didelot5ee55572017-06-12 12:37:34 -040057 reg &= ~(MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
58 MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK);
Vivien Didelota0a0f622016-11-04 03:23:34 +010059
60 switch (mode) {
61 case PHY_INTERFACE_MODE_RGMII_RXID:
Vivien Didelot5ee55572017-06-12 12:37:34 -040062 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK;
Vivien Didelota0a0f622016-11-04 03:23:34 +010063 break;
64 case PHY_INTERFACE_MODE_RGMII_TXID:
Vivien Didelot5ee55572017-06-12 12:37:34 -040065 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
Vivien Didelota0a0f622016-11-04 03:23:34 +010066 break;
67 case PHY_INTERFACE_MODE_RGMII_ID:
Vivien Didelot5ee55572017-06-12 12:37:34 -040068 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
69 MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
Vivien Didelota0a0f622016-11-04 03:23:34 +010070 break;
Andrew Lunnfedf1862016-11-10 15:44:00 +010071 case PHY_INTERFACE_MODE_RGMII:
Vivien Didelota0a0f622016-11-04 03:23:34 +010072 break;
Andrew Lunnfedf1862016-11-10 15:44:00 +010073 default:
74 return 0;
Vivien Didelota0a0f622016-11-04 03:23:34 +010075 }
76
Vivien Didelot5ee55572017-06-12 12:37:34 -040077 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelota0a0f622016-11-04 03:23:34 +010078 if (err)
79 return err;
80
Vivien Didelot774439e52017-06-08 18:34:08 -040081 dev_dbg(chip->dev, "p%d: delay RXCLK %s, TXCLK %s\n", port,
Vivien Didelot5ee55572017-06-12 12:37:34 -040082 reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK ? "yes" : "no",
83 reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK ? "yes" : "no");
Vivien Didelota0a0f622016-11-04 03:23:34 +010084
85 return 0;
86}
87
88int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
89 phy_interface_t mode)
90{
91 if (port < 5)
92 return -EOPNOTSUPP;
93
94 return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
95}
96
97int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
98 phy_interface_t mode)
99{
100 if (port != 0)
101 return -EOPNOTSUPP;
102
103 return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
104}
105
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100106int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link)
107{
108 u16 reg;
109 int err;
110
Vivien Didelot5ee55572017-06-12 12:37:34 -0400111 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100112 if (err)
113 return err;
114
Vivien Didelot5ee55572017-06-12 12:37:34 -0400115 reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
116 MV88E6XXX_PORT_MAC_CTL_LINK_UP);
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100117
118 switch (link) {
119 case LINK_FORCED_DOWN:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400120 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK;
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100121 break;
122 case LINK_FORCED_UP:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400123 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
124 MV88E6XXX_PORT_MAC_CTL_LINK_UP;
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100125 break;
126 case LINK_UNFORCED:
127 /* normal link detection */
128 break;
129 default:
130 return -EINVAL;
131 }
132
Vivien Didelot5ee55572017-06-12 12:37:34 -0400133 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100134 if (err)
135 return err;
136
Vivien Didelot774439e52017-06-08 18:34:08 -0400137 dev_dbg(chip->dev, "p%d: %s link %s\n", port,
Vivien Didelot5ee55572017-06-12 12:37:34 -0400138 reg & MV88E6XXX_PORT_MAC_CTL_FORCE_LINK ? "Force" : "Unforce",
139 reg & MV88E6XXX_PORT_MAC_CTL_LINK_UP ? "up" : "down");
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100140
141 return 0;
142}
143
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100144int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup)
145{
146 u16 reg;
147 int err;
148
Vivien Didelot5ee55572017-06-12 12:37:34 -0400149 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100150 if (err)
151 return err;
152
Vivien Didelot5ee55572017-06-12 12:37:34 -0400153 reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
154 MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100155
156 switch (dup) {
157 case DUPLEX_HALF:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400158 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100159 break;
160 case DUPLEX_FULL:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400161 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
162 MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100163 break;
164 case DUPLEX_UNFORCED:
165 /* normal duplex detection */
166 break;
167 default:
168 return -EINVAL;
169 }
170
Vivien Didelot5ee55572017-06-12 12:37:34 -0400171 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100172 if (err)
173 return err;
174
Vivien Didelot774439e52017-06-08 18:34:08 -0400175 dev_dbg(chip->dev, "p%d: %s %s duplex\n", port,
Vivien Didelot5ee55572017-06-12 12:37:34 -0400176 reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce",
177 reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half");
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100178
179 return 0;
180}
181
Vivien Didelot96a2b402016-11-04 03:23:35 +0100182static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port,
183 int speed, bool alt_bit, bool force_bit)
184{
185 u16 reg, ctrl;
186 int err;
187
188 switch (speed) {
189 case 10:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400190 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100191 break;
192 case 100:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400193 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100194 break;
195 case 200:
196 if (alt_bit)
Vivien Didelot5ee55572017-06-12 12:37:34 -0400197 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |
198 MV88E6390_PORT_MAC_CTL_ALTSPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100199 else
Vivien Didelot5ee55572017-06-12 12:37:34 -0400200 ctrl = MV88E6065_PORT_MAC_CTL_SPEED_200;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100201 break;
202 case 1000:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400203 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100204 break;
205 case 2500:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400206 ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
207 MV88E6390_PORT_MAC_CTL_ALTSPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100208 break;
209 case 10000:
210 /* all bits set, fall through... */
211 case SPEED_UNFORCED:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400212 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100213 break;
214 default:
215 return -EOPNOTSUPP;
216 }
217
Vivien Didelot5ee55572017-06-12 12:37:34 -0400218 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100219 if (err)
220 return err;
221
Vivien Didelot5ee55572017-06-12 12:37:34 -0400222 reg &= ~MV88E6XXX_PORT_MAC_CTL_SPEED_MASK;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100223 if (alt_bit)
Vivien Didelot5ee55572017-06-12 12:37:34 -0400224 reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100225 if (force_bit) {
Vivien Didelot5ee55572017-06-12 12:37:34 -0400226 reg &= ~MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
Andrew Lunn0b6e3d02016-11-16 04:26:48 +0100227 if (speed != SPEED_UNFORCED)
Vivien Didelot5ee55572017-06-12 12:37:34 -0400228 ctrl |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100229 }
230 reg |= ctrl;
231
Vivien Didelot5ee55572017-06-12 12:37:34 -0400232 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100233 if (err)
234 return err;
235
236 if (speed)
Vivien Didelot774439e52017-06-08 18:34:08 -0400237 dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100238 else
Vivien Didelot774439e52017-06-08 18:34:08 -0400239 dev_dbg(chip->dev, "p%d: Speed unforced\n", port);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100240
241 return 0;
242}
243
244/* Support 10, 100, 200 Mbps (e.g. 88E6065 family) */
245int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
246{
247 if (speed == SPEED_MAX)
248 speed = 200;
249
250 if (speed > 200)
251 return -EOPNOTSUPP;
252
253 /* Setting 200 Mbps on port 0 to 3 selects 100 Mbps */
254 return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
255}
256
257/* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */
258int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
259{
260 if (speed == SPEED_MAX)
261 speed = 1000;
262
263 if (speed == 200 || speed > 1000)
264 return -EOPNOTSUPP;
265
266 return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
267}
268
269/* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */
270int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
271{
272 if (speed == SPEED_MAX)
273 speed = 1000;
274
275 if (speed > 1000)
276 return -EOPNOTSUPP;
277
278 if (speed == 200 && port < 5)
279 return -EOPNOTSUPP;
280
281 return mv88e6xxx_port_set_speed(chip, port, speed, true, false);
282}
283
284/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */
285int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
286{
287 if (speed == SPEED_MAX)
288 speed = port < 9 ? 1000 : 2500;
289
290 if (speed > 2500)
291 return -EOPNOTSUPP;
292
293 if (speed == 200 && port != 0)
294 return -EOPNOTSUPP;
295
296 if (speed == 2500 && port < 9)
297 return -EOPNOTSUPP;
298
299 return mv88e6xxx_port_set_speed(chip, port, speed, true, true);
300}
301
302/* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */
303int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
304{
305 if (speed == SPEED_MAX)
306 speed = port < 9 ? 1000 : 10000;
307
308 if (speed == 200 && port != 0)
309 return -EOPNOTSUPP;
310
311 if (speed >= 2500 && port < 9)
312 return -EOPNOTSUPP;
313
314 return mv88e6xxx_port_set_speed(chip, port, speed, true, true);
315}
316
Andrew Lunnf39908d2017-02-04 20:02:50 +0100317int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
318 phy_interface_t mode)
319{
320 u16 reg;
321 u16 cmode;
322 int err;
323
324 if (mode == PHY_INTERFACE_MODE_NA)
325 return 0;
326
327 if (port != 9 && port != 10)
328 return -EOPNOTSUPP;
329
330 switch (mode) {
331 case PHY_INTERFACE_MODE_1000BASEX:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400332 cmode = MV88E6XXX_PORT_STS_CMODE_1000BASE_X;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100333 break;
334 case PHY_INTERFACE_MODE_SGMII:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400335 cmode = MV88E6XXX_PORT_STS_CMODE_SGMII;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100336 break;
337 case PHY_INTERFACE_MODE_2500BASEX:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400338 cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100339 break;
340 case PHY_INTERFACE_MODE_XGMII:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400341 cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100342 break;
343 case PHY_INTERFACE_MODE_RXAUI:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400344 cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100345 break;
346 default:
347 cmode = 0;
348 }
349
350 if (cmode) {
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400351 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
Andrew Lunnf39908d2017-02-04 20:02:50 +0100352 if (err)
353 return err;
354
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400355 reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100356 reg |= cmode;
357
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400358 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
Andrew Lunnf39908d2017-02-04 20:02:50 +0100359 if (err)
360 return err;
361 }
362
363 return 0;
364}
365
366int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
367{
368 int err;
369 u16 reg;
370
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400371 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
Andrew Lunnf39908d2017-02-04 20:02:50 +0100372 if (err)
373 return err;
374
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400375 *cmode = reg & MV88E6XXX_PORT_STS_CMODE_MASK;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100376
377 return 0;
378}
379
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400380/* Offset 0x02: Jamming Control
Andrew Lunnb35d322a2016-12-03 04:45:19 +0100381 *
382 * Do not limit the period of time that this port can be paused for by
383 * the remote end or the period of time that this port can pause the
384 * remote end.
385 */
Vivien Didelot08984322017-06-08 18:34:12 -0400386int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
387 u8 out)
Andrew Lunnb35d322a2016-12-03 04:45:19 +0100388{
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400389 return mv88e6xxx_port_write(chip, port, MV88E6097_PORT_JAM_CTL,
390 out << 8 | in);
Andrew Lunnb35d322a2016-12-03 04:45:19 +0100391}
392
Vivien Didelot08984322017-06-08 18:34:12 -0400393int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
394 u8 out)
Andrew Lunn3ce0e652016-12-03 04:45:20 +0100395{
396 int err;
397
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400398 err = mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,
399 MV88E6390_PORT_FLOW_CTL_UPDATE |
400 MV88E6390_PORT_FLOW_CTL_LIMIT_IN | in);
Andrew Lunn3ce0e652016-12-03 04:45:20 +0100401 if (err)
402 return err;
403
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400404 return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,
405 MV88E6390_PORT_FLOW_CTL_UPDATE |
406 MV88E6390_PORT_FLOW_CTL_LIMIT_OUT | out);
Andrew Lunn3ce0e652016-12-03 04:45:20 +0100407}
408
Vivien Didelote28def332016-11-04 03:23:27 +0100409/* Offset 0x04: Port Control Register */
410
411static const char * const mv88e6xxx_port_state_names[] = {
Vivien Didelota89b433be2017-06-12 12:37:37 -0400412 [MV88E6XXX_PORT_CTL0_STATE_DISABLED] = "Disabled",
413 [MV88E6XXX_PORT_CTL0_STATE_BLOCKING] = "Blocking/Listening",
414 [MV88E6XXX_PORT_CTL0_STATE_LEARNING] = "Learning",
415 [MV88E6XXX_PORT_CTL0_STATE_FORWARDING] = "Forwarding",
Vivien Didelote28def332016-11-04 03:23:27 +0100416};
417
418int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state)
419{
420 u16 reg;
421 int err;
422
Vivien Didelota89b433be2017-06-12 12:37:37 -0400423 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Vivien Didelote28def332016-11-04 03:23:27 +0100424 if (err)
425 return err;
426
Vivien Didelota89b433be2017-06-12 12:37:37 -0400427 reg &= ~MV88E6XXX_PORT_CTL0_STATE_MASK;
Vivien Didelotf894c292017-06-08 18:34:10 -0400428
429 switch (state) {
430 case BR_STATE_DISABLED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400431 state = MV88E6XXX_PORT_CTL0_STATE_DISABLED;
Vivien Didelotf894c292017-06-08 18:34:10 -0400432 break;
433 case BR_STATE_BLOCKING:
434 case BR_STATE_LISTENING:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400435 state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING;
Vivien Didelotf894c292017-06-08 18:34:10 -0400436 break;
437 case BR_STATE_LEARNING:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400438 state = MV88E6XXX_PORT_CTL0_STATE_LEARNING;
Vivien Didelotf894c292017-06-08 18:34:10 -0400439 break;
440 case BR_STATE_FORWARDING:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400441 state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
Vivien Didelotf894c292017-06-08 18:34:10 -0400442 break;
443 default:
444 return -EINVAL;
445 }
446
Vivien Didelote28def332016-11-04 03:23:27 +0100447 reg |= state;
448
Vivien Didelota89b433be2017-06-12 12:37:37 -0400449 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Vivien Didelote28def332016-11-04 03:23:27 +0100450 if (err)
451 return err;
452
Vivien Didelot774439e52017-06-08 18:34:08 -0400453 dev_dbg(chip->dev, "p%d: PortState set to %s\n", port,
454 mv88e6xxx_port_state_names[state]);
Vivien Didelote28def332016-11-04 03:23:27 +0100455
456 return 0;
457}
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100458
Andrew Lunn56995cb2016-12-03 04:35:19 +0100459int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port,
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400460 enum mv88e6xxx_egress_mode mode)
Andrew Lunn56995cb2016-12-03 04:35:19 +0100461{
462 int err;
463 u16 reg;
464
Vivien Didelota89b433be2017-06-12 12:37:37 -0400465 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100466 if (err)
467 return err;
468
Vivien Didelota89b433be2017-06-12 12:37:37 -0400469 reg &= ~MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400470
471 switch (mode) {
472 case MV88E6XXX_EGRESS_MODE_UNMODIFIED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400473 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400474 break;
475 case MV88E6XXX_EGRESS_MODE_UNTAGGED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400476 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400477 break;
478 case MV88E6XXX_EGRESS_MODE_TAGGED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400479 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400480 break;
481 case MV88E6XXX_EGRESS_MODE_ETHERTYPE:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400482 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400483 break;
484 default:
485 return -EINVAL;
486 }
Andrew Lunn56995cb2016-12-03 04:35:19 +0100487
Vivien Didelota89b433be2017-06-12 12:37:37 -0400488 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100489}
490
491int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
492 enum mv88e6xxx_frame_mode mode)
493{
494 int err;
495 u16 reg;
496
Vivien Didelota89b433be2017-06-12 12:37:37 -0400497 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100498 if (err)
499 return err;
500
Vivien Didelota89b433be2017-06-12 12:37:37 -0400501 reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100502
503 switch (mode) {
504 case MV88E6XXX_FRAME_MODE_NORMAL:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400505 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100506 break;
507 case MV88E6XXX_FRAME_MODE_DSA:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400508 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100509 break;
510 default:
511 return -EINVAL;
512 }
513
Vivien Didelota89b433be2017-06-12 12:37:37 -0400514 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100515}
516
517int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
518 enum mv88e6xxx_frame_mode mode)
519{
520 int err;
521 u16 reg;
522
Vivien Didelota89b433be2017-06-12 12:37:37 -0400523 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100524 if (err)
525 return err;
526
Vivien Didelota89b433be2017-06-12 12:37:37 -0400527 reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100528
529 switch (mode) {
530 case MV88E6XXX_FRAME_MODE_NORMAL:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400531 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100532 break;
533 case MV88E6XXX_FRAME_MODE_DSA:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400534 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100535 break;
536 case MV88E6XXX_FRAME_MODE_PROVIDER:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400537 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_PROVIDER;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100538 break;
539 case MV88E6XXX_FRAME_MODE_ETHERTYPE:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400540 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_ETHER_TYPE_DSA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100541 break;
542 default:
543 return -EINVAL;
544 }
545
Vivien Didelota89b433be2017-06-12 12:37:37 -0400546 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100547}
548
Vivien Didelot601aeed2017-03-11 16:13:00 -0500549static int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip,
550 int port, bool unicast)
Andrew Lunn56995cb2016-12-03 04:35:19 +0100551{
552 int err;
553 u16 reg;
554
Vivien Didelota89b433be2017-06-12 12:37:37 -0400555 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100556 if (err)
557 return err;
558
Vivien Didelot601aeed2017-03-11 16:13:00 -0500559 if (unicast)
Vivien Didelota89b433be2017-06-12 12:37:37 -0400560 reg |= MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100561 else
Vivien Didelota89b433be2017-06-12 12:37:37 -0400562 reg &= ~MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100563
Vivien Didelota89b433be2017-06-12 12:37:37 -0400564 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100565}
566
Vivien Didelot601aeed2017-03-11 16:13:00 -0500567int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
568 bool unicast, bool multicast)
Andrew Lunn56995cb2016-12-03 04:35:19 +0100569{
570 int err;
571 u16 reg;
572
Vivien Didelota89b433be2017-06-12 12:37:37 -0400573 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100574 if (err)
575 return err;
576
Vivien Didelota89b433be2017-06-12 12:37:37 -0400577 reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MASK;
Vivien Didelot601aeed2017-03-11 16:13:00 -0500578
579 if (unicast && multicast)
Vivien Didelota89b433be2017-06-12 12:37:37 -0400580 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_ALL_UNKNOWN_DA;
Vivien Didelot601aeed2017-03-11 16:13:00 -0500581 else if (unicast)
Vivien Didelota89b433be2017-06-12 12:37:37 -0400582 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_MC_DA;
Vivien Didelot601aeed2017-03-11 16:13:00 -0500583 else if (multicast)
Vivien Didelota89b433be2017-06-12 12:37:37 -0400584 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_UC_DA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100585 else
Vivien Didelota89b433be2017-06-12 12:37:37 -0400586 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_DA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100587
Vivien Didelota89b433be2017-06-12 12:37:37 -0400588 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100589}
590
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100591/* Offset 0x05: Port Control 1 */
592
Vivien Didelotea698f42017-03-11 16:12:50 -0500593int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,
594 bool message_port)
595{
596 u16 val;
597 int err;
598
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400599 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val);
Vivien Didelotea698f42017-03-11 16:12:50 -0500600 if (err)
601 return err;
602
603 if (message_port)
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400604 val |= MV88E6XXX_PORT_CTL1_MESSAGE_PORT;
Vivien Didelotea698f42017-03-11 16:12:50 -0500605 else
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400606 val &= ~MV88E6XXX_PORT_CTL1_MESSAGE_PORT;
Vivien Didelotea698f42017-03-11 16:12:50 -0500607
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400608 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val);
Vivien Didelotea698f42017-03-11 16:12:50 -0500609}
610
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100611/* Offset 0x06: Port Based VLAN Map */
612
613int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map)
614{
Vivien Didelot4d294af2017-03-11 16:12:47 -0500615 const u16 mask = mv88e6xxx_port_mask(chip);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100616 u16 reg;
617 int err;
618
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400619 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100620 if (err)
621 return err;
622
623 reg &= ~mask;
624 reg |= map & mask;
625
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400626 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100627 if (err)
628 return err;
629
Vivien Didelot774439e52017-06-08 18:34:08 -0400630 dev_dbg(chip->dev, "p%d: VLANTable set to %.3x\n", port, map);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100631
632 return 0;
633}
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100634
635int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid)
636{
637 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
638 u16 reg;
639 int err;
640
641 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400642 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100643 if (err)
644 return err;
645
646 *fid = (reg & 0xf000) >> 12;
647
648 /* Port's default FID upper bits are located in reg 0x05, offset 0 */
649 if (upper_mask) {
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400650 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,
651 &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100652 if (err)
653 return err;
654
655 *fid |= (reg & upper_mask) << 4;
656 }
657
658 return 0;
659}
660
661int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid)
662{
663 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
664 u16 reg;
665 int err;
666
667 if (fid >= mv88e6xxx_num_databases(chip))
668 return -EINVAL;
669
670 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400671 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100672 if (err)
673 return err;
674
675 reg &= 0x0fff;
676 reg |= (fid & 0x000f) << 12;
677
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400678 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100679 if (err)
680 return err;
681
682 /* Port's default FID upper bits are located in reg 0x05, offset 0 */
683 if (upper_mask) {
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400684 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,
685 &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100686 if (err)
687 return err;
688
689 reg &= ~upper_mask;
690 reg |= (fid >> 4) & upper_mask;
691
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400692 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1,
693 reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100694 if (err)
695 return err;
696 }
697
Vivien Didelot774439e52017-06-08 18:34:08 -0400698 dev_dbg(chip->dev, "p%d: FID set to %u\n", port, fid);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100699
700 return 0;
701}
Vivien Didelot77064f32016-11-04 03:23:30 +0100702
703/* Offset 0x07: Default Port VLAN ID & Priority */
704
705int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid)
706{
707 u16 reg;
708 int err;
709
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400710 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
711 &reg);
Vivien Didelot77064f32016-11-04 03:23:30 +0100712 if (err)
713 return err;
714
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400715 *pvid = reg & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
Vivien Didelot77064f32016-11-04 03:23:30 +0100716
717 return 0;
718}
719
720int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid)
721{
722 u16 reg;
723 int err;
724
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400725 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
726 &reg);
Vivien Didelot77064f32016-11-04 03:23:30 +0100727 if (err)
728 return err;
729
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400730 reg &= ~MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
731 reg |= pvid & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
Vivien Didelot77064f32016-11-04 03:23:30 +0100732
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400733 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
734 reg);
Vivien Didelot77064f32016-11-04 03:23:30 +0100735 if (err)
736 return err;
737
Vivien Didelot774439e52017-06-08 18:34:08 -0400738 dev_dbg(chip->dev, "p%d: DefaultVID set to %u\n", port, pvid);
Vivien Didelot77064f32016-11-04 03:23:30 +0100739
740 return 0;
741}
Vivien Didelot385a0992016-11-04 03:23:31 +0100742
743/* Offset 0x08: Port Control 2 Register */
744
745static const char * const mv88e6xxx_port_8021q_mode_names[] = {
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400746 [MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED] = "Disabled",
747 [MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK] = "Fallback",
748 [MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK] = "Check",
749 [MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure",
Vivien Didelot385a0992016-11-04 03:23:31 +0100750};
751
Vivien Didelot601aeed2017-03-11 16:13:00 -0500752static int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip,
753 int port, bool multicast)
Andrew Lunna23b2962017-02-04 20:15:28 +0100754{
755 int err;
756 u16 reg;
757
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400758 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100759 if (err)
760 return err;
761
Vivien Didelot601aeed2017-03-11 16:13:00 -0500762 if (multicast)
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400763 reg |= MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;
Andrew Lunna23b2962017-02-04 20:15:28 +0100764 else
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400765 reg &= ~MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;
Andrew Lunna23b2962017-02-04 20:15:28 +0100766
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400767 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100768}
769
Vivien Didelot601aeed2017-03-11 16:13:00 -0500770int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
771 bool unicast, bool multicast)
772{
773 int err;
774
775 err = mv88e6185_port_set_forward_unknown(chip, port, unicast);
776 if (err)
777 return err;
778
779 return mv88e6185_port_set_default_forward(chip, port, multicast);
780}
781
Andrew Lunna23b2962017-02-04 20:15:28 +0100782int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
783 int upstream_port)
784{
785 int err;
786 u16 reg;
787
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400788 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100789 if (err)
790 return err;
791
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400792 reg &= ~MV88E6095_PORT_CTL2_CPU_PORT_MASK;
Andrew Lunna23b2962017-02-04 20:15:28 +0100793 reg |= upstream_port;
794
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400795 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100796}
797
Vivien Didelot385a0992016-11-04 03:23:31 +0100798int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
799 u16 mode)
800{
801 u16 reg;
802 int err;
803
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400804 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Vivien Didelot385a0992016-11-04 03:23:31 +0100805 if (err)
806 return err;
807
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400808 reg &= ~MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;
809 reg |= mode & MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;
Vivien Didelot385a0992016-11-04 03:23:31 +0100810
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400811 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Vivien Didelot385a0992016-11-04 03:23:31 +0100812 if (err)
813 return err;
814
Vivien Didelot774439e52017-06-08 18:34:08 -0400815 dev_dbg(chip->dev, "p%d: 802.1QMode set to %s\n", port,
816 mv88e6xxx_port_8021q_mode_names[mode]);
Vivien Didelot385a0992016-11-04 03:23:31 +0100817
818 return 0;
819}
Andrew Lunnef0a7312016-12-03 04:35:16 +0100820
Andrew Lunna23b2962017-02-04 20:15:28 +0100821int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port)
822{
823 u16 reg;
824 int err;
825
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400826 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100827 if (err)
828 return err;
829
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400830 reg |= MV88E6XXX_PORT_CTL2_MAP_DA;
Andrew Lunna23b2962017-02-04 20:15:28 +0100831
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400832 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100833}
834
Vivien Didelotcd782652017-06-08 18:34:13 -0400835int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,
836 size_t size)
Andrew Lunn5f436662016-12-03 04:45:17 +0100837{
838 u16 reg;
839 int err;
840
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400841 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunn5f436662016-12-03 04:45:17 +0100842 if (err)
843 return err;
844
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400845 reg &= ~MV88E6XXX_PORT_CTL2_JUMBO_MODE_MASK;
Vivien Didelotcd782652017-06-08 18:34:13 -0400846
847 if (size <= 1522)
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400848 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_1522;
Vivien Didelotcd782652017-06-08 18:34:13 -0400849 else if (size <= 2048)
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400850 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_2048;
Vivien Didelotcd782652017-06-08 18:34:13 -0400851 else if (size <= 10240)
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400852 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_10240;
Vivien Didelotcd782652017-06-08 18:34:13 -0400853 else
854 return -ERANGE;
Andrew Lunn5f436662016-12-03 04:45:17 +0100855
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400856 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunn5f436662016-12-03 04:45:17 +0100857}
858
Andrew Lunnef70b112016-12-03 04:45:18 +0100859/* Offset 0x09: Port Rate Control */
860
861int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
862{
Vivien Didelot2cb8cb12017-06-12 12:37:42 -0400863 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,
864 0x0000);
Andrew Lunnef70b112016-12-03 04:45:18 +0100865}
866
867int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
868{
Vivien Didelot2cb8cb12017-06-12 12:37:42 -0400869 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,
870 0x0001);
Andrew Lunnef70b112016-12-03 04:45:18 +0100871}
872
Vivien Didelotc8c94892017-03-11 16:13:01 -0500873/* Offset 0x0C: Port ATU Control */
874
875int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port)
876{
Vivien Didelotb8109592017-06-12 12:37:45 -0400877 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ATU_CTL, 0);
Vivien Didelotc8c94892017-03-11 16:13:01 -0500878}
879
Vivien Didelot9dbfb4e2017-03-11 16:13:02 -0500880/* Offset 0x0D: (Priority) Override Register */
881
882int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port)
883{
Vivien Didelotb8109592017-06-12 12:37:45 -0400884 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0);
Vivien Didelot9dbfb4e2017-03-11 16:13:02 -0500885}
886
Andrew Lunn56995cb2016-12-03 04:35:19 +0100887/* Offset 0x0f: Port Ether type */
888
889int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
890 u16 etype)
891{
Vivien Didelotb8109592017-06-12 12:37:45 -0400892 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100893}
894
Andrew Lunnef0a7312016-12-03 04:35:16 +0100895/* Offset 0x18: Port IEEE Priority Remapping Registers [0-3]
896 * Offset 0x19: Port IEEE Priority Remapping Registers [4-7]
897 */
898
899int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
900{
901 int err;
902
903 /* Use a direct priority mapping for all IEEE tagged frames */
Vivien Didelot8009df92017-06-12 12:37:44 -0400904 err = mv88e6xxx_port_write(chip, port,
905 MV88E6095_PORT_IEEE_PRIO_REMAP_0123,
906 0x3210);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100907 if (err)
908 return err;
909
Vivien Didelot8009df92017-06-12 12:37:44 -0400910 return mv88e6xxx_port_write(chip, port,
911 MV88E6095_PORT_IEEE_PRIO_REMAP_4567,
912 0x7654);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100913}
914
915static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip,
Vivien Didelotddcbabf2017-06-17 23:07:14 -0400916 int port, u16 table, u8 ptr, u16 data)
Andrew Lunnef0a7312016-12-03 04:35:16 +0100917{
918 u16 reg;
919
Vivien Didelotddcbabf2017-06-17 23:07:14 -0400920 reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE | table |
921 (ptr << __bf_shf(MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_PTR_MASK)) |
922 (data & MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_DATA_MASK);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100923
Vivien Didelot8009df92017-06-12 12:37:44 -0400924 return mv88e6xxx_port_write(chip, port,
925 MV88E6390_PORT_IEEE_PRIO_MAP_TABLE, reg);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100926}
927
928int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
929{
930 int err, i;
Vivien Didelot8009df92017-06-12 12:37:44 -0400931 u16 table;
Andrew Lunnef0a7312016-12-03 04:35:16 +0100932
933 for (i = 0; i <= 7; i++) {
Vivien Didelot8009df92017-06-12 12:37:44 -0400934 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP;
935 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i,
936 (i | i << 4));
Andrew Lunnef0a7312016-12-03 04:35:16 +0100937 if (err)
938 return err;
939
Vivien Didelot8009df92017-06-12 12:37:44 -0400940 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP;
941 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100942 if (err)
943 return err;
944
Vivien Didelot8009df92017-06-12 12:37:44 -0400945 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP;
946 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100947 if (err)
948 return err;
949
Vivien Didelot8009df92017-06-12 12:37:44 -0400950 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP;
951 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100952 if (err)
953 return err;
954 }
955
956 return 0;
957}