blob: c0701deaca6a6f2a9bb35cedfd48f0d0f2ecd1f1 [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>
Russell Kingc9a23562018-05-10 13:17:35 -070018#include <linux/phylink.h>
Vivien Didelot4d5f2ba72017-06-02 17:06:15 -040019
20#include "chip.h"
Vivien Didelot18abed22016-11-04 03:23:26 +010021#include "port.h"
22
23int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
24 u16 *val)
25{
26 int addr = chip->info->port_base_addr + port;
27
28 return mv88e6xxx_read(chip, addr, reg, val);
29}
30
31int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
32 u16 val)
33{
34 int addr = chip->info->port_base_addr + port;
35
36 return mv88e6xxx_write(chip, addr, reg, val);
37}
Vivien Didelote28def332016-11-04 03:23:27 +010038
Andrew Lunn54186b92018-08-09 15:38:37 +020039/* Offset 0x00: MAC (or PCS or Physical) Status Register
40 *
41 * For most devices, this is read only. However the 6185 has the MyPause
42 * bit read/write.
43 */
44int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
45 int pause)
46{
47 u16 reg;
48 int err;
49
50 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
51 if (err)
52 return err;
53
54 if (pause)
55 reg |= MV88E6XXX_PORT_STS_MY_PAUSE;
56 else
57 reg &= ~MV88E6XXX_PORT_STS_MY_PAUSE;
58
59 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
60}
61
Vivien Didelot08ef7f12016-11-04 03:23:32 +010062/* Offset 0x01: MAC (or PCS or Physical) Control Register
63 *
64 * Link, Duplex and Flow Control have one force bit, one value bit.
Vivien Didelot96a2b402016-11-04 03:23:35 +010065 *
66 * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value.
67 * Alternative values require the 200BASE (or AltSpeed) bit 12 set.
68 * Newer chips need a ForcedSpd bit 13 set to consider the value.
Vivien Didelot08ef7f12016-11-04 03:23:32 +010069 */
70
Vivien Didelota0a0f622016-11-04 03:23:34 +010071static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
72 phy_interface_t mode)
73{
74 u16 reg;
75 int err;
76
Vivien Didelot5ee55572017-06-12 12:37:34 -040077 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelota0a0f622016-11-04 03:23:34 +010078 if (err)
79 return err;
80
Vivien Didelot5ee55572017-06-12 12:37:34 -040081 reg &= ~(MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
82 MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK);
Vivien Didelota0a0f622016-11-04 03:23:34 +010083
84 switch (mode) {
85 case PHY_INTERFACE_MODE_RGMII_RXID:
Vivien Didelot5ee55572017-06-12 12:37:34 -040086 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK;
Vivien Didelota0a0f622016-11-04 03:23:34 +010087 break;
88 case PHY_INTERFACE_MODE_RGMII_TXID:
Vivien Didelot5ee55572017-06-12 12:37:34 -040089 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
Vivien Didelota0a0f622016-11-04 03:23:34 +010090 break;
91 case PHY_INTERFACE_MODE_RGMII_ID:
Vivien Didelot5ee55572017-06-12 12:37:34 -040092 reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
93 MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
Vivien Didelota0a0f622016-11-04 03:23:34 +010094 break;
Andrew Lunnfedf1862016-11-10 15:44:00 +010095 case PHY_INTERFACE_MODE_RGMII:
Vivien Didelota0a0f622016-11-04 03:23:34 +010096 break;
Andrew Lunnfedf1862016-11-10 15:44:00 +010097 default:
98 return 0;
Vivien Didelota0a0f622016-11-04 03:23:34 +010099 }
100
Vivien Didelot5ee55572017-06-12 12:37:34 -0400101 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelota0a0f622016-11-04 03:23:34 +0100102 if (err)
103 return err;
104
Vivien Didelot774439e52017-06-08 18:34:08 -0400105 dev_dbg(chip->dev, "p%d: delay RXCLK %s, TXCLK %s\n", port,
Vivien Didelot5ee55572017-06-12 12:37:34 -0400106 reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK ? "yes" : "no",
107 reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK ? "yes" : "no");
Vivien Didelota0a0f622016-11-04 03:23:34 +0100108
109 return 0;
110}
111
112int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
113 phy_interface_t mode)
114{
115 if (port < 5)
116 return -EOPNOTSUPP;
117
118 return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
119}
120
121int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
122 phy_interface_t mode)
123{
124 if (port != 0)
125 return -EOPNOTSUPP;
126
127 return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
128}
129
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100130int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link)
131{
132 u16 reg;
133 int err;
134
Vivien Didelot5ee55572017-06-12 12:37:34 -0400135 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100136 if (err)
137 return err;
138
Vivien Didelot5ee55572017-06-12 12:37:34 -0400139 reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
140 MV88E6XXX_PORT_MAC_CTL_LINK_UP);
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100141
142 switch (link) {
143 case LINK_FORCED_DOWN:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400144 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK;
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100145 break;
146 case LINK_FORCED_UP:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400147 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
148 MV88E6XXX_PORT_MAC_CTL_LINK_UP;
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100149 break;
150 case LINK_UNFORCED:
151 /* normal link detection */
152 break;
153 default:
154 return -EINVAL;
155 }
156
Vivien Didelot5ee55572017-06-12 12:37:34 -0400157 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100158 if (err)
159 return err;
160
Vivien Didelot774439e52017-06-08 18:34:08 -0400161 dev_dbg(chip->dev, "p%d: %s link %s\n", port,
Vivien Didelot5ee55572017-06-12 12:37:34 -0400162 reg & MV88E6XXX_PORT_MAC_CTL_FORCE_LINK ? "Force" : "Unforce",
163 reg & MV88E6XXX_PORT_MAC_CTL_LINK_UP ? "up" : "down");
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100164
165 return 0;
166}
167
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100168int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup)
169{
170 u16 reg;
171 int err;
172
Vivien Didelot5ee55572017-06-12 12:37:34 -0400173 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100174 if (err)
175 return err;
176
Vivien Didelot5ee55572017-06-12 12:37:34 -0400177 reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
178 MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100179
180 switch (dup) {
181 case DUPLEX_HALF:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400182 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100183 break;
184 case DUPLEX_FULL:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400185 reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
186 MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100187 break;
188 case DUPLEX_UNFORCED:
189 /* normal duplex detection */
190 break;
191 default:
192 return -EINVAL;
193 }
194
Vivien Didelot5ee55572017-06-12 12:37:34 -0400195 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100196 if (err)
197 return err;
198
Vivien Didelot774439e52017-06-08 18:34:08 -0400199 dev_dbg(chip->dev, "p%d: %s %s duplex\n", port,
Vivien Didelot5ee55572017-06-12 12:37:34 -0400200 reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce",
201 reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half");
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100202
203 return 0;
204}
205
Vivien Didelot96a2b402016-11-04 03:23:35 +0100206static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port,
207 int speed, bool alt_bit, bool force_bit)
208{
209 u16 reg, ctrl;
210 int err;
211
212 switch (speed) {
213 case 10:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400214 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100215 break;
216 case 100:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400217 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100218 break;
219 case 200:
220 if (alt_bit)
Vivien Didelot5ee55572017-06-12 12:37:34 -0400221 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |
222 MV88E6390_PORT_MAC_CTL_ALTSPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100223 else
Vivien Didelot5ee55572017-06-12 12:37:34 -0400224 ctrl = MV88E6065_PORT_MAC_CTL_SPEED_200;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100225 break;
226 case 1000:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400227 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100228 break;
229 case 2500:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400230 ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
231 MV88E6390_PORT_MAC_CTL_ALTSPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100232 break;
233 case 10000:
234 /* all bits set, fall through... */
235 case SPEED_UNFORCED:
Vivien Didelot5ee55572017-06-12 12:37:34 -0400236 ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100237 break;
238 default:
239 return -EOPNOTSUPP;
240 }
241
Vivien Didelot5ee55572017-06-12 12:37:34 -0400242 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100243 if (err)
244 return err;
245
Vivien Didelot5ee55572017-06-12 12:37:34 -0400246 reg &= ~MV88E6XXX_PORT_MAC_CTL_SPEED_MASK;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100247 if (alt_bit)
Vivien Didelot5ee55572017-06-12 12:37:34 -0400248 reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100249 if (force_bit) {
Vivien Didelot5ee55572017-06-12 12:37:34 -0400250 reg &= ~MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
Andrew Lunn0b6e3d02016-11-16 04:26:48 +0100251 if (speed != SPEED_UNFORCED)
Vivien Didelot5ee55572017-06-12 12:37:34 -0400252 ctrl |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
Vivien Didelot96a2b402016-11-04 03:23:35 +0100253 }
254 reg |= ctrl;
255
Vivien Didelot5ee55572017-06-12 12:37:34 -0400256 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100257 if (err)
258 return err;
259
260 if (speed)
Vivien Didelot774439e52017-06-08 18:34:08 -0400261 dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100262 else
Vivien Didelot774439e52017-06-08 18:34:08 -0400263 dev_dbg(chip->dev, "p%d: Speed unforced\n", port);
Vivien Didelot96a2b402016-11-04 03:23:35 +0100264
265 return 0;
266}
267
268/* Support 10, 100, 200 Mbps (e.g. 88E6065 family) */
269int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
270{
271 if (speed == SPEED_MAX)
272 speed = 200;
273
274 if (speed > 200)
275 return -EOPNOTSUPP;
276
277 /* Setting 200 Mbps on port 0 to 3 selects 100 Mbps */
278 return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
279}
280
281/* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */
282int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
283{
284 if (speed == SPEED_MAX)
285 speed = 1000;
286
287 if (speed == 200 || speed > 1000)
288 return -EOPNOTSUPP;
289
290 return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
291}
292
293/* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */
294int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
295{
296 if (speed == SPEED_MAX)
297 speed = 1000;
298
299 if (speed > 1000)
300 return -EOPNOTSUPP;
301
302 if (speed == 200 && port < 5)
303 return -EOPNOTSUPP;
304
305 return mv88e6xxx_port_set_speed(chip, port, speed, true, false);
306}
307
308/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */
309int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
310{
311 if (speed == SPEED_MAX)
312 speed = port < 9 ? 1000 : 2500;
313
314 if (speed > 2500)
315 return -EOPNOTSUPP;
316
317 if (speed == 200 && port != 0)
318 return -EOPNOTSUPP;
319
320 if (speed == 2500 && port < 9)
321 return -EOPNOTSUPP;
322
323 return mv88e6xxx_port_set_speed(chip, port, speed, true, true);
324}
325
326/* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */
327int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
328{
329 if (speed == SPEED_MAX)
330 speed = port < 9 ? 1000 : 10000;
331
332 if (speed == 200 && port != 0)
333 return -EOPNOTSUPP;
334
335 if (speed >= 2500 && port < 9)
336 return -EOPNOTSUPP;
337
338 return mv88e6xxx_port_set_speed(chip, port, speed, true, true);
339}
340
Andrew Lunnf39908d2017-02-04 20:02:50 +0100341int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
342 phy_interface_t mode)
343{
344 u16 reg;
345 u16 cmode;
346 int err;
347
348 if (mode == PHY_INTERFACE_MODE_NA)
349 return 0;
350
351 if (port != 9 && port != 10)
352 return -EOPNOTSUPP;
353
354 switch (mode) {
355 case PHY_INTERFACE_MODE_1000BASEX:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400356 cmode = MV88E6XXX_PORT_STS_CMODE_1000BASE_X;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100357 break;
358 case PHY_INTERFACE_MODE_SGMII:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400359 cmode = MV88E6XXX_PORT_STS_CMODE_SGMII;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100360 break;
361 case PHY_INTERFACE_MODE_2500BASEX:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400362 cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100363 break;
364 case PHY_INTERFACE_MODE_XGMII:
Russell King2e51a8d2017-12-12 09:29:46 +0000365 case PHY_INTERFACE_MODE_XAUI:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400366 cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100367 break;
368 case PHY_INTERFACE_MODE_RXAUI:
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400369 cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100370 break;
371 default:
372 cmode = 0;
373 }
374
375 if (cmode) {
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400376 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
Andrew Lunnf39908d2017-02-04 20:02:50 +0100377 if (err)
378 return err;
379
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400380 reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100381 reg |= cmode;
382
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400383 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
Andrew Lunnf39908d2017-02-04 20:02:50 +0100384 if (err)
385 return err;
386 }
387
388 return 0;
389}
390
391int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
392{
393 int err;
394 u16 reg;
395
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400396 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
Andrew Lunnf39908d2017-02-04 20:02:50 +0100397 if (err)
398 return err;
399
Vivien Didelot5f83dc92017-06-12 12:37:33 -0400400 *cmode = reg & MV88E6XXX_PORT_STS_CMODE_MASK;
Andrew Lunnf39908d2017-02-04 20:02:50 +0100401
402 return 0;
403}
404
Russell Kingc9a23562018-05-10 13:17:35 -0700405int mv88e6xxx_port_link_state(struct mv88e6xxx_chip *chip, int port,
406 struct phylink_link_state *state)
407{
408 int err;
409 u16 reg;
410
411 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
412 if (err)
413 return err;
414
415 switch (reg & MV88E6XXX_PORT_STS_SPEED_MASK) {
416 case MV88E6XXX_PORT_STS_SPEED_10:
417 state->speed = SPEED_10;
418 break;
419 case MV88E6XXX_PORT_STS_SPEED_100:
420 state->speed = SPEED_100;
421 break;
422 case MV88E6XXX_PORT_STS_SPEED_1000:
423 state->speed = SPEED_1000;
424 break;
425 case MV88E6XXX_PORT_STS_SPEED_10000:
426 if ((reg &MV88E6XXX_PORT_STS_CMODE_MASK) ==
427 MV88E6XXX_PORT_STS_CMODE_2500BASEX)
428 state->speed = SPEED_2500;
429 else
430 state->speed = SPEED_10000;
431 break;
432 }
433
434 state->duplex = reg & MV88E6XXX_PORT_STS_DUPLEX ?
435 DUPLEX_FULL : DUPLEX_HALF;
436 state->link = !!(reg & MV88E6XXX_PORT_STS_LINK);
437 state->an_enabled = 1;
438 state->an_complete = state->link;
439
440 return 0;
441}
442
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400443/* Offset 0x02: Jamming Control
Andrew Lunnb35d322a2016-12-03 04:45:19 +0100444 *
445 * Do not limit the period of time that this port can be paused for by
446 * the remote end or the period of time that this port can pause the
447 * remote end.
448 */
Vivien Didelot08984322017-06-08 18:34:12 -0400449int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
450 u8 out)
Andrew Lunnb35d322a2016-12-03 04:45:19 +0100451{
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400452 return mv88e6xxx_port_write(chip, port, MV88E6097_PORT_JAM_CTL,
453 out << 8 | in);
Andrew Lunnb35d322a2016-12-03 04:45:19 +0100454}
455
Vivien Didelot08984322017-06-08 18:34:12 -0400456int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
457 u8 out)
Andrew Lunn3ce0e652016-12-03 04:45:20 +0100458{
459 int err;
460
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400461 err = mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,
462 MV88E6390_PORT_FLOW_CTL_UPDATE |
463 MV88E6390_PORT_FLOW_CTL_LIMIT_IN | in);
Andrew Lunn3ce0e652016-12-03 04:45:20 +0100464 if (err)
465 return err;
466
Vivien Didelot6c96bbf2017-06-12 12:37:35 -0400467 return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,
468 MV88E6390_PORT_FLOW_CTL_UPDATE |
469 MV88E6390_PORT_FLOW_CTL_LIMIT_OUT | out);
Andrew Lunn3ce0e652016-12-03 04:45:20 +0100470}
471
Vivien Didelote28def332016-11-04 03:23:27 +0100472/* Offset 0x04: Port Control Register */
473
474static const char * const mv88e6xxx_port_state_names[] = {
Vivien Didelota89b433be2017-06-12 12:37:37 -0400475 [MV88E6XXX_PORT_CTL0_STATE_DISABLED] = "Disabled",
476 [MV88E6XXX_PORT_CTL0_STATE_BLOCKING] = "Blocking/Listening",
477 [MV88E6XXX_PORT_CTL0_STATE_LEARNING] = "Learning",
478 [MV88E6XXX_PORT_CTL0_STATE_FORWARDING] = "Forwarding",
Vivien Didelote28def332016-11-04 03:23:27 +0100479};
480
481int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state)
482{
483 u16 reg;
484 int err;
485
Vivien Didelota89b433be2017-06-12 12:37:37 -0400486 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Vivien Didelote28def332016-11-04 03:23:27 +0100487 if (err)
488 return err;
489
Vivien Didelota89b433be2017-06-12 12:37:37 -0400490 reg &= ~MV88E6XXX_PORT_CTL0_STATE_MASK;
Vivien Didelotf894c292017-06-08 18:34:10 -0400491
492 switch (state) {
493 case BR_STATE_DISABLED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400494 state = MV88E6XXX_PORT_CTL0_STATE_DISABLED;
Vivien Didelotf894c292017-06-08 18:34:10 -0400495 break;
496 case BR_STATE_BLOCKING:
497 case BR_STATE_LISTENING:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400498 state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING;
Vivien Didelotf894c292017-06-08 18:34:10 -0400499 break;
500 case BR_STATE_LEARNING:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400501 state = MV88E6XXX_PORT_CTL0_STATE_LEARNING;
Vivien Didelotf894c292017-06-08 18:34:10 -0400502 break;
503 case BR_STATE_FORWARDING:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400504 state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
Vivien Didelotf894c292017-06-08 18:34:10 -0400505 break;
506 default:
507 return -EINVAL;
508 }
509
Vivien Didelote28def332016-11-04 03:23:27 +0100510 reg |= state;
511
Vivien Didelota89b433be2017-06-12 12:37:37 -0400512 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Vivien Didelote28def332016-11-04 03:23:27 +0100513 if (err)
514 return err;
515
Vivien Didelot774439e52017-06-08 18:34:08 -0400516 dev_dbg(chip->dev, "p%d: PortState set to %s\n", port,
517 mv88e6xxx_port_state_names[state]);
Vivien Didelote28def332016-11-04 03:23:27 +0100518
519 return 0;
520}
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100521
Andrew Lunn56995cb2016-12-03 04:35:19 +0100522int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port,
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400523 enum mv88e6xxx_egress_mode mode)
Andrew Lunn56995cb2016-12-03 04:35:19 +0100524{
525 int err;
526 u16 reg;
527
Vivien Didelota89b433be2017-06-12 12:37:37 -0400528 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100529 if (err)
530 return err;
531
Vivien Didelota89b433be2017-06-12 12:37:37 -0400532 reg &= ~MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400533
534 switch (mode) {
535 case MV88E6XXX_EGRESS_MODE_UNMODIFIED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400536 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400537 break;
538 case MV88E6XXX_EGRESS_MODE_UNTAGGED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400539 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400540 break;
541 case MV88E6XXX_EGRESS_MODE_TAGGED:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400542 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400543 break;
544 case MV88E6XXX_EGRESS_MODE_ETHERTYPE:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400545 reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA;
Vivien Didelot31bef4e2017-06-08 18:34:09 -0400546 break;
547 default:
548 return -EINVAL;
549 }
Andrew Lunn56995cb2016-12-03 04:35:19 +0100550
Vivien Didelota89b433be2017-06-12 12:37:37 -0400551 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100552}
553
554int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
555 enum mv88e6xxx_frame_mode mode)
556{
557 int err;
558 u16 reg;
559
Vivien Didelota89b433be2017-06-12 12:37:37 -0400560 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100561 if (err)
562 return err;
563
Vivien Didelota89b433be2017-06-12 12:37:37 -0400564 reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100565
566 switch (mode) {
567 case MV88E6XXX_FRAME_MODE_NORMAL:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400568 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100569 break;
570 case MV88E6XXX_FRAME_MODE_DSA:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400571 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100572 break;
573 default:
574 return -EINVAL;
575 }
576
Vivien Didelota89b433be2017-06-12 12:37:37 -0400577 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100578}
579
580int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
581 enum mv88e6xxx_frame_mode mode)
582{
583 int err;
584 u16 reg;
585
Vivien Didelota89b433be2017-06-12 12:37:37 -0400586 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100587 if (err)
588 return err;
589
Vivien Didelota89b433be2017-06-12 12:37:37 -0400590 reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100591
592 switch (mode) {
593 case MV88E6XXX_FRAME_MODE_NORMAL:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400594 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100595 break;
596 case MV88E6XXX_FRAME_MODE_DSA:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400597 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100598 break;
599 case MV88E6XXX_FRAME_MODE_PROVIDER:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400600 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_PROVIDER;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100601 break;
602 case MV88E6XXX_FRAME_MODE_ETHERTYPE:
Vivien Didelota89b433be2017-06-12 12:37:37 -0400603 reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_ETHER_TYPE_DSA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100604 break;
605 default:
606 return -EINVAL;
607 }
608
Vivien Didelota89b433be2017-06-12 12:37:37 -0400609 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100610}
611
Vivien Didelot601aeed2017-03-11 16:13:00 -0500612static int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip,
613 int port, bool unicast)
Andrew Lunn56995cb2016-12-03 04:35:19 +0100614{
615 int err;
616 u16 reg;
617
Vivien Didelota89b433be2017-06-12 12:37:37 -0400618 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100619 if (err)
620 return err;
621
Vivien Didelot601aeed2017-03-11 16:13:00 -0500622 if (unicast)
Vivien Didelota89b433be2017-06-12 12:37:37 -0400623 reg |= MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100624 else
Vivien Didelota89b433be2017-06-12 12:37:37 -0400625 reg &= ~MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100626
Vivien Didelota89b433be2017-06-12 12:37:37 -0400627 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100628}
629
Vivien Didelot601aeed2017-03-11 16:13:00 -0500630int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
631 bool unicast, bool multicast)
Andrew Lunn56995cb2016-12-03 04:35:19 +0100632{
633 int err;
634 u16 reg;
635
Vivien Didelota89b433be2017-06-12 12:37:37 -0400636 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100637 if (err)
638 return err;
639
Vivien Didelota89b433be2017-06-12 12:37:37 -0400640 reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MASK;
Vivien Didelot601aeed2017-03-11 16:13:00 -0500641
642 if (unicast && multicast)
Vivien Didelota89b433be2017-06-12 12:37:37 -0400643 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_ALL_UNKNOWN_DA;
Vivien Didelot601aeed2017-03-11 16:13:00 -0500644 else if (unicast)
Vivien Didelota89b433be2017-06-12 12:37:37 -0400645 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_MC_DA;
Vivien Didelot601aeed2017-03-11 16:13:00 -0500646 else if (multicast)
Vivien Didelota89b433be2017-06-12 12:37:37 -0400647 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_UC_DA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100648 else
Vivien Didelota89b433be2017-06-12 12:37:37 -0400649 reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_DA;
Andrew Lunn56995cb2016-12-03 04:35:19 +0100650
Vivien Didelota89b433be2017-06-12 12:37:37 -0400651 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100652}
653
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100654/* Offset 0x05: Port Control 1 */
655
Vivien Didelotea698f42017-03-11 16:12:50 -0500656int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,
657 bool message_port)
658{
659 u16 val;
660 int err;
661
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400662 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val);
Vivien Didelotea698f42017-03-11 16:12:50 -0500663 if (err)
664 return err;
665
666 if (message_port)
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400667 val |= MV88E6XXX_PORT_CTL1_MESSAGE_PORT;
Vivien Didelotea698f42017-03-11 16:12:50 -0500668 else
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400669 val &= ~MV88E6XXX_PORT_CTL1_MESSAGE_PORT;
Vivien Didelotea698f42017-03-11 16:12:50 -0500670
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400671 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val);
Vivien Didelotea698f42017-03-11 16:12:50 -0500672}
673
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100674/* Offset 0x06: Port Based VLAN Map */
675
676int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map)
677{
Vivien Didelot4d294af2017-03-11 16:12:47 -0500678 const u16 mask = mv88e6xxx_port_mask(chip);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100679 u16 reg;
680 int err;
681
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400682 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100683 if (err)
684 return err;
685
686 reg &= ~mask;
687 reg |= map & mask;
688
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400689 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100690 if (err)
691 return err;
692
Vivien Didelot774439e52017-06-08 18:34:08 -0400693 dev_dbg(chip->dev, "p%d: VLANTable set to %.3x\n", port, map);
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100694
695 return 0;
696}
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100697
698int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid)
699{
700 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
701 u16 reg;
702 int err;
703
704 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400705 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100706 if (err)
707 return err;
708
709 *fid = (reg & 0xf000) >> 12;
710
711 /* Port's default FID upper bits are located in reg 0x05, offset 0 */
712 if (upper_mask) {
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400713 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,
714 &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100715 if (err)
716 return err;
717
718 *fid |= (reg & upper_mask) << 4;
719 }
720
721 return 0;
722}
723
724int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid)
725{
726 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
727 u16 reg;
728 int err;
729
730 if (fid >= mv88e6xxx_num_databases(chip))
731 return -EINVAL;
732
733 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400734 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100735 if (err)
736 return err;
737
738 reg &= 0x0fff;
739 reg |= (fid & 0x000f) << 12;
740
Vivien Didelot7e5cc5f2017-06-12 12:37:39 -0400741 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100742 if (err)
743 return err;
744
745 /* Port's default FID upper bits are located in reg 0x05, offset 0 */
746 if (upper_mask) {
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400747 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,
748 &reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100749 if (err)
750 return err;
751
752 reg &= ~upper_mask;
753 reg |= (fid >> 4) & upper_mask;
754
Vivien Didelotcd985bb2017-06-12 12:37:38 -0400755 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1,
756 reg);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100757 if (err)
758 return err;
759 }
760
Vivien Didelot774439e52017-06-08 18:34:08 -0400761 dev_dbg(chip->dev, "p%d: FID set to %u\n", port, fid);
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100762
763 return 0;
764}
Vivien Didelot77064f32016-11-04 03:23:30 +0100765
766/* Offset 0x07: Default Port VLAN ID & Priority */
767
768int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid)
769{
770 u16 reg;
771 int err;
772
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400773 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
774 &reg);
Vivien Didelot77064f32016-11-04 03:23:30 +0100775 if (err)
776 return err;
777
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400778 *pvid = reg & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
Vivien Didelot77064f32016-11-04 03:23:30 +0100779
780 return 0;
781}
782
783int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid)
784{
785 u16 reg;
786 int err;
787
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400788 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
789 &reg);
Vivien Didelot77064f32016-11-04 03:23:30 +0100790 if (err)
791 return err;
792
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400793 reg &= ~MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
794 reg |= pvid & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;
Vivien Didelot77064f32016-11-04 03:23:30 +0100795
Vivien Didelotb7929fb2017-06-12 12:37:40 -0400796 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,
797 reg);
Vivien Didelot77064f32016-11-04 03:23:30 +0100798 if (err)
799 return err;
800
Vivien Didelot774439e52017-06-08 18:34:08 -0400801 dev_dbg(chip->dev, "p%d: DefaultVID set to %u\n", port, pvid);
Vivien Didelot77064f32016-11-04 03:23:30 +0100802
803 return 0;
804}
Vivien Didelot385a0992016-11-04 03:23:31 +0100805
806/* Offset 0x08: Port Control 2 Register */
807
808static const char * const mv88e6xxx_port_8021q_mode_names[] = {
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400809 [MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED] = "Disabled",
810 [MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK] = "Fallback",
811 [MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK] = "Check",
812 [MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure",
Vivien Didelot385a0992016-11-04 03:23:31 +0100813};
814
Vivien Didelot601aeed2017-03-11 16:13:00 -0500815static int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip,
816 int port, bool multicast)
Andrew Lunna23b2962017-02-04 20:15:28 +0100817{
818 int err;
819 u16 reg;
820
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400821 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100822 if (err)
823 return err;
824
Vivien Didelot601aeed2017-03-11 16:13:00 -0500825 if (multicast)
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400826 reg |= MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;
Andrew Lunna23b2962017-02-04 20:15:28 +0100827 else
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400828 reg &= ~MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;
Andrew Lunna23b2962017-02-04 20:15:28 +0100829
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400830 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100831}
832
Vivien Didelot601aeed2017-03-11 16:13:00 -0500833int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
834 bool unicast, bool multicast)
835{
836 int err;
837
838 err = mv88e6185_port_set_forward_unknown(chip, port, unicast);
839 if (err)
840 return err;
841
842 return mv88e6185_port_set_default_forward(chip, port, multicast);
843}
844
Andrew Lunna23b2962017-02-04 20:15:28 +0100845int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
846 int upstream_port)
847{
848 int err;
849 u16 reg;
850
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400851 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100852 if (err)
853 return err;
854
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400855 reg &= ~MV88E6095_PORT_CTL2_CPU_PORT_MASK;
Andrew Lunna23b2962017-02-04 20:15:28 +0100856 reg |= upstream_port;
857
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400858 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100859}
860
Vivien Didelot385a0992016-11-04 03:23:31 +0100861int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
862 u16 mode)
863{
864 u16 reg;
865 int err;
866
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400867 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Vivien Didelot385a0992016-11-04 03:23:31 +0100868 if (err)
869 return err;
870
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400871 reg &= ~MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;
872 reg |= mode & MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;
Vivien Didelot385a0992016-11-04 03:23:31 +0100873
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400874 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Vivien Didelot385a0992016-11-04 03:23:31 +0100875 if (err)
876 return err;
877
Vivien Didelot774439e52017-06-08 18:34:08 -0400878 dev_dbg(chip->dev, "p%d: 802.1QMode set to %s\n", port,
879 mv88e6xxx_port_8021q_mode_names[mode]);
Vivien Didelot385a0992016-11-04 03:23:31 +0100880
881 return 0;
882}
Andrew Lunnef0a7312016-12-03 04:35:16 +0100883
Andrew Lunna23b2962017-02-04 20:15:28 +0100884int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port)
885{
886 u16 reg;
887 int err;
888
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400889 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100890 if (err)
891 return err;
892
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400893 reg |= MV88E6XXX_PORT_CTL2_MAP_DA;
Andrew Lunna23b2962017-02-04 20:15:28 +0100894
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400895 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunna23b2962017-02-04 20:15:28 +0100896}
897
Vivien Didelotcd782652017-06-08 18:34:13 -0400898int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,
899 size_t size)
Andrew Lunn5f436662016-12-03 04:45:17 +0100900{
901 u16 reg;
902 int err;
903
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400904 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
Andrew Lunn5f436662016-12-03 04:45:17 +0100905 if (err)
906 return err;
907
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400908 reg &= ~MV88E6XXX_PORT_CTL2_JUMBO_MODE_MASK;
Vivien Didelotcd782652017-06-08 18:34:13 -0400909
910 if (size <= 1522)
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400911 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_1522;
Vivien Didelotcd782652017-06-08 18:34:13 -0400912 else if (size <= 2048)
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400913 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_2048;
Vivien Didelotcd782652017-06-08 18:34:13 -0400914 else if (size <= 10240)
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400915 reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_10240;
Vivien Didelotcd782652017-06-08 18:34:13 -0400916 else
917 return -ERANGE;
Andrew Lunn5f436662016-12-03 04:45:17 +0100918
Vivien Didelot81c6edb2017-06-12 12:37:41 -0400919 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
Andrew Lunn5f436662016-12-03 04:45:17 +0100920}
921
Andrew Lunnef70b112016-12-03 04:45:18 +0100922/* Offset 0x09: Port Rate Control */
923
924int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
925{
Vivien Didelot2cb8cb12017-06-12 12:37:42 -0400926 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,
927 0x0000);
Andrew Lunnef70b112016-12-03 04:45:18 +0100928}
929
930int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
931{
Vivien Didelot2cb8cb12017-06-12 12:37:42 -0400932 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,
933 0x0001);
Andrew Lunnef70b112016-12-03 04:45:18 +0100934}
935
Vivien Didelotc8c94892017-03-11 16:13:01 -0500936/* Offset 0x0C: Port ATU Control */
937
938int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port)
939{
Vivien Didelotb8109592017-06-12 12:37:45 -0400940 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ATU_CTL, 0);
Vivien Didelotc8c94892017-03-11 16:13:01 -0500941}
942
Vivien Didelot9dbfb4e2017-03-11 16:13:02 -0500943/* Offset 0x0D: (Priority) Override Register */
944
945int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port)
946{
Vivien Didelotb8109592017-06-12 12:37:45 -0400947 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0);
Vivien Didelot9dbfb4e2017-03-11 16:13:02 -0500948}
949
Andrew Lunn56995cb2016-12-03 04:35:19 +0100950/* Offset 0x0f: Port Ether type */
951
952int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
953 u16 etype)
954{
Vivien Didelotb8109592017-06-12 12:37:45 -0400955 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype);
Andrew Lunn56995cb2016-12-03 04:35:19 +0100956}
957
Andrew Lunnef0a7312016-12-03 04:35:16 +0100958/* Offset 0x18: Port IEEE Priority Remapping Registers [0-3]
959 * Offset 0x19: Port IEEE Priority Remapping Registers [4-7]
960 */
961
962int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
963{
964 int err;
965
966 /* Use a direct priority mapping for all IEEE tagged frames */
Vivien Didelot8009df92017-06-12 12:37:44 -0400967 err = mv88e6xxx_port_write(chip, port,
968 MV88E6095_PORT_IEEE_PRIO_REMAP_0123,
969 0x3210);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100970 if (err)
971 return err;
972
Vivien Didelot8009df92017-06-12 12:37:44 -0400973 return mv88e6xxx_port_write(chip, port,
974 MV88E6095_PORT_IEEE_PRIO_REMAP_4567,
975 0x7654);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100976}
977
978static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip,
Vivien Didelotddcbabf2017-06-17 23:07:14 -0400979 int port, u16 table, u8 ptr, u16 data)
Andrew Lunnef0a7312016-12-03 04:35:16 +0100980{
981 u16 reg;
982
Vivien Didelotddcbabf2017-06-17 23:07:14 -0400983 reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE | table |
984 (ptr << __bf_shf(MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_PTR_MASK)) |
985 (data & MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_DATA_MASK);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100986
Vivien Didelot8009df92017-06-12 12:37:44 -0400987 return mv88e6xxx_port_write(chip, port,
988 MV88E6390_PORT_IEEE_PRIO_MAP_TABLE, reg);
Andrew Lunnef0a7312016-12-03 04:35:16 +0100989}
990
991int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
992{
993 int err, i;
Vivien Didelot8009df92017-06-12 12:37:44 -0400994 u16 table;
Andrew Lunnef0a7312016-12-03 04:35:16 +0100995
996 for (i = 0; i <= 7; i++) {
Vivien Didelot8009df92017-06-12 12:37:44 -0400997 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP;
998 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i,
999 (i | i << 4));
Andrew Lunnef0a7312016-12-03 04:35:16 +01001000 if (err)
1001 return err;
1002
Vivien Didelot8009df92017-06-12 12:37:44 -04001003 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP;
1004 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
Andrew Lunnef0a7312016-12-03 04:35:16 +01001005 if (err)
1006 return err;
1007
Vivien Didelot8009df92017-06-12 12:37:44 -04001008 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP;
1009 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
Andrew Lunnef0a7312016-12-03 04:35:16 +01001010 if (err)
1011 return err;
1012
Vivien Didelot8009df92017-06-12 12:37:44 -04001013 table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP;
1014 err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);
Andrew Lunnef0a7312016-12-03 04:35:16 +01001015 if (err)
1016 return err;
1017 }
1018
1019 return 0;
1020}