blob: 18eeed083cbda37aaeeaa539254ee192a61c7c94 [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 *
6 * Copyright (c) 2016 Vivien Didelot <vivien.didelot@savoirfairelinux.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include "mv88e6xxx.h"
15#include "port.h"
16
17int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
18 u16 *val)
19{
20 int addr = chip->info->port_base_addr + port;
21
22 return mv88e6xxx_read(chip, addr, reg, val);
23}
24
25int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
26 u16 val)
27{
28 int addr = chip->info->port_base_addr + port;
29
30 return mv88e6xxx_write(chip, addr, reg, val);
31}
Vivien Didelote28def332016-11-04 03:23:27 +010032
Vivien Didelot08ef7f12016-11-04 03:23:32 +010033/* Offset 0x01: MAC (or PCS or Physical) Control Register
34 *
35 * Link, Duplex and Flow Control have one force bit, one value bit.
Vivien Didelot96a2b402016-11-04 03:23:35 +010036 *
37 * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value.
38 * Alternative values require the 200BASE (or AltSpeed) bit 12 set.
39 * Newer chips need a ForcedSpd bit 13 set to consider the value.
Vivien Didelot08ef7f12016-11-04 03:23:32 +010040 */
41
Vivien Didelota0a0f622016-11-04 03:23:34 +010042static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
43 phy_interface_t mode)
44{
45 u16 reg;
46 int err;
47
48 err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, &reg);
49 if (err)
50 return err;
51
52 reg &= ~(PORT_PCS_CTRL_RGMII_DELAY_RXCLK |
53 PORT_PCS_CTRL_RGMII_DELAY_TXCLK);
54
55 switch (mode) {
56 case PHY_INTERFACE_MODE_RGMII_RXID:
57 reg |= PORT_PCS_CTRL_RGMII_DELAY_RXCLK;
58 break;
59 case PHY_INTERFACE_MODE_RGMII_TXID:
60 reg |= PORT_PCS_CTRL_RGMII_DELAY_TXCLK;
61 break;
62 case PHY_INTERFACE_MODE_RGMII_ID:
63 reg |= PORT_PCS_CTRL_RGMII_DELAY_RXCLK |
64 PORT_PCS_CTRL_RGMII_DELAY_TXCLK;
65 break;
66 default:
67 /* no delay */
68 break;
69 }
70
71 err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg);
72 if (err)
73 return err;
74
75 netdev_dbg(chip->ds->ports[port].netdev, "delay RXCLK %s, TXCLK %s\n",
76 reg & PORT_PCS_CTRL_RGMII_DELAY_RXCLK ? "yes" : "no",
77 reg & PORT_PCS_CTRL_RGMII_DELAY_TXCLK ? "yes" : "no");
78
79 return 0;
80}
81
82int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
83 phy_interface_t mode)
84{
85 if (port < 5)
86 return -EOPNOTSUPP;
87
88 return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
89}
90
91int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
92 phy_interface_t mode)
93{
94 if (port != 0)
95 return -EOPNOTSUPP;
96
97 return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
98}
99
Vivien Didelot08ef7f12016-11-04 03:23:32 +0100100int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link)
101{
102 u16 reg;
103 int err;
104
105 err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, &reg);
106 if (err)
107 return err;
108
109 reg &= ~(PORT_PCS_CTRL_FORCE_LINK | PORT_PCS_CTRL_LINK_UP);
110
111 switch (link) {
112 case LINK_FORCED_DOWN:
113 reg |= PORT_PCS_CTRL_FORCE_LINK;
114 break;
115 case LINK_FORCED_UP:
116 reg |= PORT_PCS_CTRL_FORCE_LINK | PORT_PCS_CTRL_LINK_UP;
117 break;
118 case LINK_UNFORCED:
119 /* normal link detection */
120 break;
121 default:
122 return -EINVAL;
123 }
124
125 err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg);
126 if (err)
127 return err;
128
129 netdev_dbg(chip->ds->ports[port].netdev, "%s link %s\n",
130 reg & PORT_PCS_CTRL_FORCE_LINK ? "Force" : "Unforce",
131 reg & PORT_PCS_CTRL_LINK_UP ? "up" : "down");
132
133 return 0;
134}
135
Vivien Didelot7f1ae072016-11-04 03:23:33 +0100136int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup)
137{
138 u16 reg;
139 int err;
140
141 err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, &reg);
142 if (err)
143 return err;
144
145 reg &= ~(PORT_PCS_CTRL_FORCE_DUPLEX | PORT_PCS_CTRL_DUPLEX_FULL);
146
147 switch (dup) {
148 case DUPLEX_HALF:
149 reg |= PORT_PCS_CTRL_FORCE_DUPLEX;
150 break;
151 case DUPLEX_FULL:
152 reg |= PORT_PCS_CTRL_FORCE_DUPLEX | PORT_PCS_CTRL_DUPLEX_FULL;
153 break;
154 case DUPLEX_UNFORCED:
155 /* normal duplex detection */
156 break;
157 default:
158 return -EINVAL;
159 }
160
161 err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg);
162 if (err)
163 return err;
164
165 netdev_dbg(chip->ds->ports[port].netdev, "%s %s duplex\n",
166 reg & PORT_PCS_CTRL_FORCE_DUPLEX ? "Force" : "Unforce",
167 reg & PORT_PCS_CTRL_DUPLEX_FULL ? "full" : "half");
168
169 return 0;
170}
171
Vivien Didelot96a2b402016-11-04 03:23:35 +0100172static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port,
173 int speed, bool alt_bit, bool force_bit)
174{
175 u16 reg, ctrl;
176 int err;
177
178 switch (speed) {
179 case 10:
180 ctrl = PORT_PCS_CTRL_SPEED_10;
181 break;
182 case 100:
183 ctrl = PORT_PCS_CTRL_SPEED_100;
184 break;
185 case 200:
186 if (alt_bit)
187 ctrl = PORT_PCS_CTRL_SPEED_100 | PORT_PCS_CTRL_ALTSPEED;
188 else
189 ctrl = PORT_PCS_CTRL_SPEED_200;
190 break;
191 case 1000:
192 ctrl = PORT_PCS_CTRL_SPEED_1000;
193 break;
194 case 2500:
195 ctrl = PORT_PCS_CTRL_SPEED_1000 | PORT_PCS_CTRL_ALTSPEED;
196 break;
197 case 10000:
198 /* all bits set, fall through... */
199 case SPEED_UNFORCED:
200 ctrl = PORT_PCS_CTRL_SPEED_UNFORCED;
201 break;
202 default:
203 return -EOPNOTSUPP;
204 }
205
206 err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, &reg);
207 if (err)
208 return err;
209
210 reg &= ~PORT_PCS_CTRL_SPEED_MASK;
211 if (alt_bit)
212 reg &= ~PORT_PCS_CTRL_ALTSPEED;
213 if (force_bit) {
214 reg &= ~PORT_PCS_CTRL_FORCE_SPEED;
215 if (speed)
216 ctrl |= PORT_PCS_CTRL_FORCE_SPEED;
217 }
218 reg |= ctrl;
219
220 err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg);
221 if (err)
222 return err;
223
224 if (speed)
225 netdev_dbg(chip->ds->ports[port].netdev,
226 "Speed set to %d Mbps\n", speed);
227 else
228 netdev_dbg(chip->ds->ports[port].netdev, "Speed unforced\n");
229
230 return 0;
231}
232
233/* Support 10, 100, 200 Mbps (e.g. 88E6065 family) */
234int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
235{
236 if (speed == SPEED_MAX)
237 speed = 200;
238
239 if (speed > 200)
240 return -EOPNOTSUPP;
241
242 /* Setting 200 Mbps on port 0 to 3 selects 100 Mbps */
243 return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
244}
245
246/* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */
247int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
248{
249 if (speed == SPEED_MAX)
250 speed = 1000;
251
252 if (speed == 200 || speed > 1000)
253 return -EOPNOTSUPP;
254
255 return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
256}
257
258/* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */
259int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
260{
261 if (speed == SPEED_MAX)
262 speed = 1000;
263
264 if (speed > 1000)
265 return -EOPNOTSUPP;
266
267 if (speed == 200 && port < 5)
268 return -EOPNOTSUPP;
269
270 return mv88e6xxx_port_set_speed(chip, port, speed, true, false);
271}
272
273/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */
274int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
275{
276 if (speed == SPEED_MAX)
277 speed = port < 9 ? 1000 : 2500;
278
279 if (speed > 2500)
280 return -EOPNOTSUPP;
281
282 if (speed == 200 && port != 0)
283 return -EOPNOTSUPP;
284
285 if (speed == 2500 && port < 9)
286 return -EOPNOTSUPP;
287
288 return mv88e6xxx_port_set_speed(chip, port, speed, true, true);
289}
290
291/* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */
292int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
293{
294 if (speed == SPEED_MAX)
295 speed = port < 9 ? 1000 : 10000;
296
297 if (speed == 200 && port != 0)
298 return -EOPNOTSUPP;
299
300 if (speed >= 2500 && port < 9)
301 return -EOPNOTSUPP;
302
303 return mv88e6xxx_port_set_speed(chip, port, speed, true, true);
304}
305
Vivien Didelote28def332016-11-04 03:23:27 +0100306/* Offset 0x04: Port Control Register */
307
308static const char * const mv88e6xxx_port_state_names[] = {
309 [PORT_CONTROL_STATE_DISABLED] = "Disabled",
310 [PORT_CONTROL_STATE_BLOCKING] = "Blocking/Listening",
311 [PORT_CONTROL_STATE_LEARNING] = "Learning",
312 [PORT_CONTROL_STATE_FORWARDING] = "Forwarding",
313};
314
315int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state)
316{
317 u16 reg;
318 int err;
319
320 err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, &reg);
321 if (err)
322 return err;
323
324 reg &= ~PORT_CONTROL_STATE_MASK;
325 reg |= state;
326
327 err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
328 if (err)
329 return err;
330
331 netdev_dbg(chip->ds->ports[port].netdev, "PortState set to %s\n",
332 mv88e6xxx_port_state_names[state]);
333
334 return 0;
335}
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100336
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100337/* Offset 0x05: Port Control 1 */
338
Vivien Didelot5a7921f2016-11-04 03:23:28 +0100339/* Offset 0x06: Port Based VLAN Map */
340
341int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map)
342{
343 const u16 mask = GENMASK(mv88e6xxx_num_ports(chip) - 1, 0);
344 u16 reg;
345 int err;
346
347 err = mv88e6xxx_port_read(chip, port, PORT_BASE_VLAN, &reg);
348 if (err)
349 return err;
350
351 reg &= ~mask;
352 reg |= map & mask;
353
354 err = mv88e6xxx_port_write(chip, port, PORT_BASE_VLAN, reg);
355 if (err)
356 return err;
357
358 netdev_dbg(chip->ds->ports[port].netdev, "VLANTable set to %.3x\n",
359 map);
360
361 return 0;
362}
Vivien Didelotb4e48c52016-11-04 03:23:29 +0100363
364int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid)
365{
366 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
367 u16 reg;
368 int err;
369
370 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
371 err = mv88e6xxx_port_read(chip, port, PORT_BASE_VLAN, &reg);
372 if (err)
373 return err;
374
375 *fid = (reg & 0xf000) >> 12;
376
377 /* Port's default FID upper bits are located in reg 0x05, offset 0 */
378 if (upper_mask) {
379 err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_1, &reg);
380 if (err)
381 return err;
382
383 *fid |= (reg & upper_mask) << 4;
384 }
385
386 return 0;
387}
388
389int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid)
390{
391 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
392 u16 reg;
393 int err;
394
395 if (fid >= mv88e6xxx_num_databases(chip))
396 return -EINVAL;
397
398 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
399 err = mv88e6xxx_port_read(chip, port, PORT_BASE_VLAN, &reg);
400 if (err)
401 return err;
402
403 reg &= 0x0fff;
404 reg |= (fid & 0x000f) << 12;
405
406 err = mv88e6xxx_port_write(chip, port, PORT_BASE_VLAN, reg);
407 if (err)
408 return err;
409
410 /* Port's default FID upper bits are located in reg 0x05, offset 0 */
411 if (upper_mask) {
412 err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_1, &reg);
413 if (err)
414 return err;
415
416 reg &= ~upper_mask;
417 reg |= (fid >> 4) & upper_mask;
418
419 err = mv88e6xxx_port_write(chip, port, PORT_CONTROL_1, reg);
420 if (err)
421 return err;
422 }
423
424 netdev_dbg(chip->ds->ports[port].netdev, "FID set to %u\n", fid);
425
426 return 0;
427}
Vivien Didelot77064f32016-11-04 03:23:30 +0100428
429/* Offset 0x07: Default Port VLAN ID & Priority */
430
431int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid)
432{
433 u16 reg;
434 int err;
435
436 err = mv88e6xxx_port_read(chip, port, PORT_DEFAULT_VLAN, &reg);
437 if (err)
438 return err;
439
440 *pvid = reg & PORT_DEFAULT_VLAN_MASK;
441
442 return 0;
443}
444
445int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid)
446{
447 u16 reg;
448 int err;
449
450 err = mv88e6xxx_port_read(chip, port, PORT_DEFAULT_VLAN, &reg);
451 if (err)
452 return err;
453
454 reg &= ~PORT_DEFAULT_VLAN_MASK;
455 reg |= pvid & PORT_DEFAULT_VLAN_MASK;
456
457 err = mv88e6xxx_port_write(chip, port, PORT_DEFAULT_VLAN, reg);
458 if (err)
459 return err;
460
461 netdev_dbg(chip->ds->ports[port].netdev, "DefaultVID set to %u\n",
462 pvid);
463
464 return 0;
465}
Vivien Didelot385a0992016-11-04 03:23:31 +0100466
467/* Offset 0x08: Port Control 2 Register */
468
469static const char * const mv88e6xxx_port_8021q_mode_names[] = {
470 [PORT_CONTROL_2_8021Q_DISABLED] = "Disabled",
471 [PORT_CONTROL_2_8021Q_FALLBACK] = "Fallback",
472 [PORT_CONTROL_2_8021Q_CHECK] = "Check",
473 [PORT_CONTROL_2_8021Q_SECURE] = "Secure",
474};
475
476int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
477 u16 mode)
478{
479 u16 reg;
480 int err;
481
482 err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_2, &reg);
483 if (err)
484 return err;
485
486 reg &= ~PORT_CONTROL_2_8021Q_MASK;
487 reg |= mode & PORT_CONTROL_2_8021Q_MASK;
488
489 err = mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg);
490 if (err)
491 return err;
492
493 netdev_dbg(chip->ds->ports[port].netdev, "802.1QMode set to %s\n",
494 mv88e6xxx_port_8021q_mode_names[mode]);
495
496 return 0;
497}