blob: 8621f589340688c3e10a426169f5711c5d0a0bd6 [file] [log] [blame]
Vivien Didelotec561272016-09-02 14:45:33 -04001/*
Andrew Lunndc30c352016-10-16 19:56:49 +02002 * Marvell 88E6xxx Switch Global 2 Registers support (device address
3 * 0x1C)
Vivien Didelotec561272016-09-02 14:45:33 -04004 *
5 * Copyright (c) 2008 Marvell Semiconductor
6 *
Vivien Didelot4333d612017-03-28 15:10:36 -04007 * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
8 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Vivien Didelotec561272016-09-02 14:45:33 -04009 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 */
15
Vivien Didelote289ef02017-06-19 10:55:37 -040016#include <linux/bitfield.h>
Florian Westphal282ccf62017-03-29 17:17:31 +020017#include <linux/interrupt.h>
Andrew Lunndc30c352016-10-16 19:56:49 +020018#include <linux/irqdomain.h>
Vivien Didelot4d5f2ba72017-06-02 17:06:15 -040019
20#include "chip.h"
Vivien Didelot82466922017-06-15 12:13:59 -040021#include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */
Vivien Didelotec561272016-09-02 14:45:33 -040022#include "global2.h"
23
Vivien Didelot9fe850f2016-09-29 12:21:54 -040024static int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
25{
26 return mv88e6xxx_read(chip, ADDR_GLOBAL2, reg, val);
27}
28
29static int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
30{
31 return mv88e6xxx_write(chip, ADDR_GLOBAL2, reg, val);
32}
33
34static int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update)
35{
36 return mv88e6xxx_update(chip, ADDR_GLOBAL2, reg, update);
37}
38
39static int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
40{
41 return mv88e6xxx_wait(chip, ADDR_GLOBAL2, reg, mask);
42}
43
Andrew Lunn6e55f692016-12-03 04:45:16 +010044/* Offset 0x02: Management Enable 2x */
45/* Offset 0x03: Management Enable 0x */
46
47int mv88e6095_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
48{
49 int err;
50
51 /* Consider the frames with reserved multicast destination
52 * addresses matching 01:80:c2:00:00:2x as MGMT.
53 */
54 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X)) {
Vivien Didelot6bff47b2017-06-19 10:55:40 -040055 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_2X, 0xffff);
Andrew Lunn6e55f692016-12-03 04:45:16 +010056 if (err)
57 return err;
58 }
59
60 /* Consider the frames with reserved multicast destination
61 * addresses matching 01:80:c2:00:00:0x as MGMT.
62 */
63 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X))
Vivien Didelot6bff47b2017-06-19 10:55:40 -040064 return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_0X,
65 0xffff);
Andrew Lunn6e55f692016-12-03 04:45:16 +010066
67 return 0;
68}
69
Vivien Didelotec561272016-09-02 14:45:33 -040070/* Offset 0x06: Device Mapping Table register */
71
72static int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip,
73 int target, int port)
74{
75 u16 val = (target << 8) | (port & 0xf);
76
Vivien Didelot067e4742017-06-19 10:55:39 -040077 return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_DEVICE_MAPPING, val);
Vivien Didelotec561272016-09-02 14:45:33 -040078}
79
80static int mv88e6xxx_g2_set_device_mapping(struct mv88e6xxx_chip *chip)
81{
82 int target, port;
83 int err;
84
85 /* Initialize the routing port to the 32 possible target devices */
86 for (target = 0; target < 32; ++target) {
87 port = 0xf;
88
89 if (target < DSA_MAX_SWITCHES) {
90 port = chip->ds->rtable[target];
91 if (port == DSA_RTABLE_NONE)
92 port = 0xf;
93 }
94
95 err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
96 if (err)
97 break;
98 }
99
100 return err;
101}
102
103/* Offset 0x07: Trunk Mask Table register */
104
105static int mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip *chip, int num,
Vivien Didelot56dc7342017-06-19 10:55:38 -0400106 bool hash, u16 mask)
Vivien Didelotec561272016-09-02 14:45:33 -0400107{
Vivien Didelot56dc7342017-06-19 10:55:38 -0400108 u16 val = (num << 12) | (mask & mv88e6xxx_port_mask(chip));
Vivien Didelotec561272016-09-02 14:45:33 -0400109
Vivien Didelot56dc7342017-06-19 10:55:38 -0400110 if (hash)
111 val |= MV88E6XXX_G2_TRUNK_MASK_HASH;
Vivien Didelotec561272016-09-02 14:45:33 -0400112
Vivien Didelot56dc7342017-06-19 10:55:38 -0400113 return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_TRUNK_MASK, val);
Vivien Didelotec561272016-09-02 14:45:33 -0400114}
115
116/* Offset 0x08: Trunk Mapping Table register */
117
118static int mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip *chip, int id,
119 u16 map)
120{
Vivien Didelot370b4ff2016-09-29 12:21:57 -0400121 const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
Vivien Didelotec561272016-09-02 14:45:33 -0400122 u16 val = (id << 11) | (map & port_mask);
123
Vivien Didelot56dc7342017-06-19 10:55:38 -0400124 return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_TRUNK_MAPPING, val);
Vivien Didelotec561272016-09-02 14:45:33 -0400125}
126
127static int mv88e6xxx_g2_clear_trunk(struct mv88e6xxx_chip *chip)
128{
Vivien Didelot370b4ff2016-09-29 12:21:57 -0400129 const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
Vivien Didelotec561272016-09-02 14:45:33 -0400130 int i, err;
131
132 /* Clear all eight possible Trunk Mask vectors */
133 for (i = 0; i < 8; ++i) {
134 err = mv88e6xxx_g2_trunk_mask_write(chip, i, false, port_mask);
135 if (err)
136 return err;
137 }
138
139 /* Clear all sixteen possible Trunk ID routing vectors */
140 for (i = 0; i < 16; ++i) {
141 err = mv88e6xxx_g2_trunk_mapping_write(chip, i, 0);
142 if (err)
143 return err;
144 }
145
146 return 0;
147}
148
149/* Offset 0x09: Ingress Rate Command register
150 * Offset 0x0A: Ingress Rate Data register
151 */
152
Vivien Didelotcd8da8b2017-06-19 10:55:36 -0400153static int mv88e6xxx_g2_irl_wait(struct mv88e6xxx_chip *chip)
Vivien Didelotec561272016-09-02 14:45:33 -0400154{
Vivien Didelotcd8da8b2017-06-19 10:55:36 -0400155 return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_IRL_CMD,
156 MV88E6XXX_G2_IRL_CMD_BUSY);
157}
Vivien Didelotec561272016-09-02 14:45:33 -0400158
Vivien Didelotcd8da8b2017-06-19 10:55:36 -0400159static int mv88e6xxx_g2_irl_op(struct mv88e6xxx_chip *chip, u16 op, int port,
160 int res, int reg)
161{
162 int err;
Vivien Didelotec561272016-09-02 14:45:33 -0400163
Vivien Didelotcd8da8b2017-06-19 10:55:36 -0400164 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_IRL_CMD,
165 MV88E6XXX_G2_IRL_CMD_BUSY | op | (port << 8) |
166 (res << 5) | reg);
167 if (err)
168 return err;
Vivien Didelotec561272016-09-02 14:45:33 -0400169
Vivien Didelotcd8da8b2017-06-19 10:55:36 -0400170 return mv88e6xxx_g2_irl_wait(chip);
171}
172
173int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
174{
175 return mv88e6xxx_g2_irl_op(chip, MV88E6352_G2_IRL_CMD_OP_INIT_ALL, port,
176 0, 0);
177}
178
179int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
180{
181 return mv88e6xxx_g2_irl_op(chip, MV88E6390_G2_IRL_CMD_OP_INIT_ALL, port,
182 0, 0);
Vivien Didelotec561272016-09-02 14:45:33 -0400183}
184
Vivien Didelot17a15942017-03-30 17:37:09 -0400185/* Offset 0x0B: Cross-chip Port VLAN (Addr) Register
186 * Offset 0x0C: Cross-chip Port VLAN Data Register
187 */
188
189static int mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip *chip)
190{
Vivien Didelot67d1ea82017-06-19 10:55:41 -0400191 return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_PVT_ADDR,
192 MV88E6XXX_G2_PVT_ADDR_BUSY);
Vivien Didelot17a15942017-03-30 17:37:09 -0400193}
194
195static int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev,
196 int src_port, u16 op)
197{
198 int err;
199
Vivien Didelot67d1ea82017-06-19 10:55:41 -0400200 /* 9-bit Cross-chip PVT pointer: with MV88E6XXX_G2_MISC_5_BIT_PORT
201 * cleared, source device is 5-bit, source port is 4-bit.
Vivien Didelot17a15942017-03-30 17:37:09 -0400202 */
Vivien Didelot67d1ea82017-06-19 10:55:41 -0400203 op |= MV88E6XXX_G2_PVT_ADDR_BUSY;
Vivien Didelot17a15942017-03-30 17:37:09 -0400204 op |= (src_dev & 0x1f) << 4;
205 op |= (src_port & 0xf);
206
Vivien Didelot67d1ea82017-06-19 10:55:41 -0400207 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_ADDR, op);
Vivien Didelot17a15942017-03-30 17:37:09 -0400208 if (err)
209 return err;
210
211 return mv88e6xxx_g2_pvt_op_wait(chip);
212}
213
214int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev,
215 int src_port, u16 data)
216{
217 int err;
218
219 err = mv88e6xxx_g2_pvt_op_wait(chip);
220 if (err)
221 return err;
222
Vivien Didelot67d1ea82017-06-19 10:55:41 -0400223 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_DATA, data);
Vivien Didelot17a15942017-03-30 17:37:09 -0400224 if (err)
225 return err;
226
227 return mv88e6xxx_g2_pvt_op(chip, src_dev, src_port,
Vivien Didelot67d1ea82017-06-19 10:55:41 -0400228 MV88E6XXX_G2_PVT_ADDR_OP_WRITE_PVLAN);
Vivien Didelot17a15942017-03-30 17:37:09 -0400229}
230
Vivien Didelotec561272016-09-02 14:45:33 -0400231/* Offset 0x0D: Switch MAC/WoL/WoF register */
232
233static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip,
234 unsigned int pointer, u8 data)
235{
236 u16 val = (pointer << 8) | data;
237
Vivien Didelot9fe850f2016-09-29 12:21:54 -0400238 return mv88e6xxx_g2_update(chip, GLOBAL2_SWITCH_MAC, val);
Vivien Didelotec561272016-09-02 14:45:33 -0400239}
240
241int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr)
242{
243 int i, err;
244
245 for (i = 0; i < 6; i++) {
246 err = mv88e6xxx_g2_switch_mac_write(chip, i, addr[i]);
247 if (err)
248 break;
249 }
250
251 return err;
252}
253
254/* Offset 0x0F: Priority Override Table */
255
256static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer,
257 u8 data)
258{
259 u16 val = (pointer << 8) | (data & 0x7);
260
Vivien Didelot9fe850f2016-09-29 12:21:54 -0400261 return mv88e6xxx_g2_update(chip, GLOBAL2_PRIO_OVERRIDE, val);
Vivien Didelotec561272016-09-02 14:45:33 -0400262}
263
264static int mv88e6xxx_g2_clear_pot(struct mv88e6xxx_chip *chip)
265{
266 int i, err;
267
268 /* Clear all sixteen possible Priority Override entries */
269 for (i = 0; i < 16; i++) {
270 err = mv88e6xxx_g2_pot_write(chip, i, 0);
271 if (err)
272 break;
273 }
274
275 return err;
276}
277
278/* Offset 0x14: EEPROM Command
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500279 * Offset 0x15: EEPROM Data (for 16-bit data access)
280 * Offset 0x15: EEPROM Addr (for 8-bit data access)
Vivien Didelotec561272016-09-02 14:45:33 -0400281 */
282
283static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
284{
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400285 return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_EEPROM_CMD,
286 MV88E6XXX_G2_EEPROM_CMD_BUSY |
287 MV88E6XXX_G2_EEPROM_CMD_RUNNING);
Vivien Didelotec561272016-09-02 14:45:33 -0400288}
289
290static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
291{
292 int err;
293
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400294 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_EEPROM_CMD,
295 MV88E6XXX_G2_EEPROM_CMD_BUSY | cmd);
Vivien Didelotec561272016-09-02 14:45:33 -0400296 if (err)
297 return err;
298
299 return mv88e6xxx_g2_eeprom_wait(chip);
300}
301
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500302static int mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip *chip,
303 u16 addr, u8 *data)
304{
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400305 u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ;
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500306 int err;
307
308 err = mv88e6xxx_g2_eeprom_wait(chip);
309 if (err)
310 return err;
311
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400312 err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500313 if (err)
314 return err;
315
316 err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
317 if (err)
318 return err;
319
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400320 err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &cmd);
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500321 if (err)
322 return err;
323
324 *data = cmd & 0xff;
325
326 return 0;
327}
328
329static int mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip *chip,
330 u16 addr, u8 data)
331{
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400332 u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE |
333 MV88E6XXX_G2_EEPROM_CMD_WRITE_EN;
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500334 int err;
335
336 err = mv88e6xxx_g2_eeprom_wait(chip);
337 if (err)
338 return err;
339
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400340 err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500341 if (err)
342 return err;
343
344 return mv88e6xxx_g2_eeprom_cmd(chip, cmd | data);
345}
346
Vivien Didelotec561272016-09-02 14:45:33 -0400347static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip,
348 u8 addr, u16 *data)
349{
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400350 u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ | addr;
Vivien Didelotec561272016-09-02 14:45:33 -0400351 int err;
352
353 err = mv88e6xxx_g2_eeprom_wait(chip);
354 if (err)
355 return err;
356
357 err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
358 if (err)
359 return err;
360
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400361 return mv88e6xxx_g2_read(chip, MV88E6352_G2_EEPROM_DATA, data);
Vivien Didelotec561272016-09-02 14:45:33 -0400362}
363
364static int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip,
365 u8 addr, u16 data)
366{
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400367 u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE | addr;
Vivien Didelotec561272016-09-02 14:45:33 -0400368 int err;
369
370 err = mv88e6xxx_g2_eeprom_wait(chip);
371 if (err)
372 return err;
373
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400374 err = mv88e6xxx_g2_write(chip, MV88E6352_G2_EEPROM_DATA, data);
Vivien Didelotec561272016-09-02 14:45:33 -0400375 if (err)
376 return err;
377
378 return mv88e6xxx_g2_eeprom_cmd(chip, cmd);
379}
380
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500381int mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip *chip,
382 struct ethtool_eeprom *eeprom, u8 *data)
383{
384 unsigned int offset = eeprom->offset;
385 unsigned int len = eeprom->len;
386 int err;
387
388 eeprom->len = 0;
389
390 while (len) {
391 err = mv88e6xxx_g2_eeprom_read8(chip, offset, data);
392 if (err)
393 return err;
394
395 eeprom->len++;
396 offset++;
397 data++;
398 len--;
399 }
400
401 return 0;
402}
403
404int mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip *chip,
405 struct ethtool_eeprom *eeprom, u8 *data)
406{
407 unsigned int offset = eeprom->offset;
408 unsigned int len = eeprom->len;
409 int err;
410
411 eeprom->len = 0;
412
413 while (len) {
414 err = mv88e6xxx_g2_eeprom_write8(chip, offset, *data);
415 if (err)
416 return err;
417
418 eeprom->len++;
419 offset++;
420 data++;
421 len--;
422 }
423
424 return 0;
425}
426
Vivien Didelotec561272016-09-02 14:45:33 -0400427int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
428 struct ethtool_eeprom *eeprom, u8 *data)
429{
430 unsigned int offset = eeprom->offset;
431 unsigned int len = eeprom->len;
432 u16 val;
433 int err;
434
435 eeprom->len = 0;
436
437 if (offset & 1) {
438 err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
439 if (err)
440 return err;
441
442 *data++ = (val >> 8) & 0xff;
443
444 offset++;
445 len--;
446 eeprom->len++;
447 }
448
449 while (len >= 2) {
450 err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
451 if (err)
452 return err;
453
454 *data++ = val & 0xff;
455 *data++ = (val >> 8) & 0xff;
456
457 offset += 2;
458 len -= 2;
459 eeprom->len += 2;
460 }
461
462 if (len) {
463 err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
464 if (err)
465 return err;
466
467 *data++ = val & 0xff;
468
469 offset++;
470 len--;
471 eeprom->len++;
472 }
473
474 return 0;
475}
476
477int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
478 struct ethtool_eeprom *eeprom, u8 *data)
479{
480 unsigned int offset = eeprom->offset;
481 unsigned int len = eeprom->len;
482 u16 val;
483 int err;
484
485 /* Ensure the RO WriteEn bit is set */
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400486 err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &val);
Vivien Didelotec561272016-09-02 14:45:33 -0400487 if (err)
488 return err;
489
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400490 if (!(val & MV88E6XXX_G2_EEPROM_CMD_WRITE_EN))
Vivien Didelotec561272016-09-02 14:45:33 -0400491 return -EROFS;
492
493 eeprom->len = 0;
494
495 if (offset & 1) {
496 err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
497 if (err)
498 return err;
499
500 val = (*data++ << 8) | (val & 0xff);
501
502 err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
503 if (err)
504 return err;
505
506 offset++;
507 len--;
508 eeprom->len++;
509 }
510
511 while (len >= 2) {
512 val = *data++;
513 val |= *data++ << 8;
514
515 err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
516 if (err)
517 return err;
518
519 offset += 2;
520 len -= 2;
521 eeprom->len += 2;
522 }
523
524 if (len) {
525 err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
526 if (err)
527 return err;
528
529 val = (val & 0xff00) | *data++;
530
531 err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
532 if (err)
533 return err;
534
535 offset++;
536 len--;
537 eeprom->len++;
538 }
539
540 return 0;
541}
542
543/* Offset 0x18: SMI PHY Command Register
544 * Offset 0x19: SMI PHY Data Register
545 */
546
547static int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip)
548{
Vivien Didelote289ef02017-06-19 10:55:37 -0400549 return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_SMI_PHY_CMD,
550 MV88E6XXX_G2_SMI_PHY_CMD_BUSY);
Vivien Didelotec561272016-09-02 14:45:33 -0400551}
552
553static int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
554{
555 int err;
556
Vivien Didelote289ef02017-06-19 10:55:37 -0400557 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_CMD,
558 MV88E6XXX_G2_SMI_PHY_CMD_BUSY | cmd);
Vivien Didelotec561272016-09-02 14:45:33 -0400559 if (err)
560 return err;
561
562 return mv88e6xxx_g2_smi_phy_wait(chip);
563}
564
Vivien Didelote289ef02017-06-19 10:55:37 -0400565static int mv88e6xxx_g2_smi_phy_access(struct mv88e6xxx_chip *chip,
566 bool external, bool c45, u16 op, int dev,
567 int reg)
Vivien Didelotec561272016-09-02 14:45:33 -0400568{
Vivien Didelote289ef02017-06-19 10:55:37 -0400569 u16 cmd = op;
Vivien Didelotec561272016-09-02 14:45:33 -0400570
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100571 if (external)
Vivien Didelote289ef02017-06-19 10:55:37 -0400572 cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_EXTERNAL;
573 else
574 cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_INTERNAL; /* empty mask */
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100575
Vivien Didelote289ef02017-06-19 10:55:37 -0400576 if (c45)
577 cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_45; /* empty mask */
578 else
579 cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_22;
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100580
Vivien Didelote289ef02017-06-19 10:55:37 -0400581 dev <<= __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK);
582 cmd |= dev & MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK;
583 cmd |= reg & MV88E6XXX_G2_SMI_PHY_CMD_REG_ADDR_MASK;
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100584
585 return mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
586}
587
Vivien Didelote289ef02017-06-19 10:55:37 -0400588static int mv88e6xxx_g2_smi_phy_access_c22(struct mv88e6xxx_chip *chip,
589 bool external, u16 op, int dev,
590 int reg)
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100591{
Vivien Didelote289ef02017-06-19 10:55:37 -0400592 return mv88e6xxx_g2_smi_phy_access(chip, external, false, op, dev, reg);
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100593}
594
Vivien Didelote289ef02017-06-19 10:55:37 -0400595/* IEEE 802.3 Clause 22 Read Data Register */
596static int mv88e6xxx_g2_smi_phy_read_data_c22(struct mv88e6xxx_chip *chip,
597 bool external, int dev, int reg,
598 u16 *data)
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100599{
Vivien Didelote289ef02017-06-19 10:55:37 -0400600 u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_READ_DATA;
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100601 int err;
602
Vivien Didelotec561272016-09-02 14:45:33 -0400603 err = mv88e6xxx_g2_smi_phy_wait(chip);
604 if (err)
605 return err;
606
Vivien Didelote289ef02017-06-19 10:55:37 -0400607 err = mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
Vivien Didelotec561272016-09-02 14:45:33 -0400608 if (err)
609 return err;
610
Vivien Didelote289ef02017-06-19 10:55:37 -0400611 return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
Vivien Didelotec561272016-09-02 14:45:33 -0400612}
613
Vivien Didelote289ef02017-06-19 10:55:37 -0400614/* IEEE 802.3 Clause 22 Write Data Register */
615static int mv88e6xxx_g2_smi_phy_write_data_c22(struct mv88e6xxx_chip *chip,
616 bool external, int dev, int reg,
617 u16 data)
618{
619 u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_WRITE_DATA;
620 int err;
621
622 err = mv88e6xxx_g2_smi_phy_wait(chip);
623 if (err)
624 return err;
625
626 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
627 if (err)
628 return err;
629
630 return mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
631}
632
633static int mv88e6xxx_g2_smi_phy_access_c45(struct mv88e6xxx_chip *chip,
634 bool external, u16 op, int port,
635 int dev)
636{
637 return mv88e6xxx_g2_smi_phy_access(chip, external, true, op, port, dev);
638}
639
640/* IEEE 802.3 Clause 45 Write Address Register */
641static int mv88e6xxx_g2_smi_phy_write_addr_c45(struct mv88e6xxx_chip *chip,
642 bool external, int port, int dev,
643 int addr)
644{
645 u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_ADDR;
646 int err;
647
648 err = mv88e6xxx_g2_smi_phy_wait(chip);
649 if (err)
650 return err;
651
652 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, addr);
653 if (err)
654 return err;
655
656 return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
657}
658
659/* IEEE 802.3 Clause 45 Read Data Register */
660static int mv88e6xxx_g2_smi_phy_read_data_c45(struct mv88e6xxx_chip *chip,
661 bool external, int port, int dev,
662 u16 *data)
663{
664 u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA;
665 int err;
666
667 err = mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
668 if (err)
669 return err;
670
671 return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
672}
673
674static int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip,
675 bool external, int port, int reg,
676 u16 *data)
677{
678 int dev = (reg >> 16) & 0x1f;
679 int addr = reg & 0xffff;
680 int err;
681
682 err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev,
683 addr);
684 if (err)
685 return err;
686
687 return mv88e6xxx_g2_smi_phy_read_data_c45(chip, external, port, dev,
688 data);
689}
690
691/* IEEE 802.3 Clause 45 Write Data Register */
692static int mv88e6xxx_g2_smi_phy_write_data_c45(struct mv88e6xxx_chip *chip,
693 bool external, int port, int dev,
694 u16 data)
695{
696 u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_DATA;
697 int err;
698
699 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
700 if (err)
701 return err;
702
703 return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
704}
705
706static int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip,
707 bool external, int port, int reg,
708 u16 data)
709{
710 int dev = (reg >> 16) & 0x1f;
711 int addr = reg & 0xffff;
712 int err;
713
714 err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev,
715 addr);
716 if (err)
717 return err;
718
719 return mv88e6xxx_g2_smi_phy_write_data_c45(chip, external, port, dev,
720 data);
721}
722
723int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100724 int addr, int reg, u16 *val)
725{
726 struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
727 bool external = mdio_bus->external;
728
729 if (reg & MII_ADDR_C45)
Vivien Didelote289ef02017-06-19 10:55:37 -0400730 return mv88e6xxx_g2_smi_phy_read_c45(chip, external, addr, reg,
731 val);
732
733 return mv88e6xxx_g2_smi_phy_read_data_c22(chip, external, addr, reg,
734 val);
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100735}
736
Vivien Didelote289ef02017-06-19 10:55:37 -0400737int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100738 int addr, int reg, u16 val)
739{
740 struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
741 bool external = mdio_bus->external;
742
743 if (reg & MII_ADDR_C45)
Vivien Didelote289ef02017-06-19 10:55:37 -0400744 return mv88e6xxx_g2_smi_phy_write_c45(chip, external, addr, reg,
745 val);
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100746
Vivien Didelote289ef02017-06-19 10:55:37 -0400747 return mv88e6xxx_g2_smi_phy_write_data_c22(chip, external, addr, reg,
748 val);
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100749}
750
Andrew Lunnfcd25162017-02-09 00:03:42 +0100751static int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
752{
753 u16 reg;
754
755 mv88e6xxx_g2_read(chip, GLOBAL2_WDOG_CONTROL, &reg);
756
757 dev_info(chip->dev, "Watchdog event: 0x%04x", reg);
758
759 return IRQ_HANDLED;
760}
761
762static void mv88e6097_watchdog_free(struct mv88e6xxx_chip *chip)
763{
764 u16 reg;
765
766 mv88e6xxx_g2_read(chip, GLOBAL2_WDOG_CONTROL, &reg);
767
768 reg &= ~(GLOBAL2_WDOG_CONTROL_EGRESS_ENABLE |
769 GLOBAL2_WDOG_CONTROL_QC_ENABLE);
770
771 mv88e6xxx_g2_write(chip, GLOBAL2_WDOG_CONTROL, reg);
772}
773
774static int mv88e6097_watchdog_setup(struct mv88e6xxx_chip *chip)
775{
776 return mv88e6xxx_g2_write(chip, GLOBAL2_WDOG_CONTROL,
777 GLOBAL2_WDOG_CONTROL_EGRESS_ENABLE |
778 GLOBAL2_WDOG_CONTROL_QC_ENABLE |
779 GLOBAL2_WDOG_CONTROL_SWRESET);
780}
781
782const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {
783 .irq_action = mv88e6097_watchdog_action,
784 .irq_setup = mv88e6097_watchdog_setup,
785 .irq_free = mv88e6097_watchdog_free,
786};
787
Andrew Lunn61303732017-02-09 00:03:43 +0100788static int mv88e6390_watchdog_setup(struct mv88e6xxx_chip *chip)
789{
790 return mv88e6xxx_g2_update(chip, GLOBAL2_WDOG_CONTROL,
791 GLOBAL2_WDOG_INT_ENABLE |
792 GLOBAL2_WDOG_CUT_THROUGH |
793 GLOBAL2_WDOG_QUEUE_CONTROLLER |
794 GLOBAL2_WDOG_EGRESS |
795 GLOBAL2_WDOG_FORCE_IRQ);
796}
797
798static int mv88e6390_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
799{
800 int err;
801 u16 reg;
802
803 mv88e6xxx_g2_write(chip, GLOBAL2_WDOG_CONTROL, GLOBAL2_WDOG_EVENT);
804 err = mv88e6xxx_g2_read(chip, GLOBAL2_WDOG_CONTROL, &reg);
805
806 dev_info(chip->dev, "Watchdog event: 0x%04x",
807 reg & GLOBAL2_WDOG_DATA_MASK);
808
809 mv88e6xxx_g2_write(chip, GLOBAL2_WDOG_CONTROL, GLOBAL2_WDOG_HISTORY);
810 err = mv88e6xxx_g2_read(chip, GLOBAL2_WDOG_CONTROL, &reg);
811
812 dev_info(chip->dev, "Watchdog history: 0x%04x",
813 reg & GLOBAL2_WDOG_DATA_MASK);
814
815 /* Trigger a software reset to try to recover the switch */
816 if (chip->info->ops->reset)
817 chip->info->ops->reset(chip);
818
819 mv88e6390_watchdog_setup(chip);
820
821 return IRQ_HANDLED;
822}
823
824static void mv88e6390_watchdog_free(struct mv88e6xxx_chip *chip)
825{
826 mv88e6xxx_g2_update(chip, GLOBAL2_WDOG_CONTROL,
827 GLOBAL2_WDOG_INT_ENABLE);
828}
829
830const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {
831 .irq_action = mv88e6390_watchdog_action,
832 .irq_setup = mv88e6390_watchdog_setup,
833 .irq_free = mv88e6390_watchdog_free,
834};
835
Andrew Lunnfcd25162017-02-09 00:03:42 +0100836static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id)
837{
838 struct mv88e6xxx_chip *chip = dev_id;
839 irqreturn_t ret = IRQ_NONE;
840
841 mutex_lock(&chip->reg_lock);
842 if (chip->info->ops->watchdog_ops->irq_action)
843 ret = chip->info->ops->watchdog_ops->irq_action(chip, irq);
844 mutex_unlock(&chip->reg_lock);
845
846 return ret;
847}
848
849static void mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip *chip)
850{
851 mutex_lock(&chip->reg_lock);
852 if (chip->info->ops->watchdog_ops->irq_free)
853 chip->info->ops->watchdog_ops->irq_free(chip);
854 mutex_unlock(&chip->reg_lock);
855
856 free_irq(chip->watchdog_irq, chip);
857 irq_dispose_mapping(chip->watchdog_irq);
858}
859
860static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip)
861{
862 int err;
863
864 chip->watchdog_irq = irq_find_mapping(chip->g2_irq.domain,
865 GLOBAL2_INT_SOURCE_WATCHDOG);
866 if (chip->watchdog_irq < 0)
867 return chip->watchdog_irq;
868
869 err = request_threaded_irq(chip->watchdog_irq, NULL,
870 mv88e6xxx_g2_watchdog_thread_fn,
871 IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
872 "mv88e6xxx-watchdog", chip);
873 if (err)
874 return err;
875
876 mutex_lock(&chip->reg_lock);
877 if (chip->info->ops->watchdog_ops->irq_setup)
878 err = chip->info->ops->watchdog_ops->irq_setup(chip);
879 mutex_unlock(&chip->reg_lock);
880
881 return err;
882}
883
Vivien Didelot81228992017-03-30 17:37:08 -0400884/* Offset 0x1D: Misc Register */
885
886static int mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip *chip,
887 bool port_5_bit)
888{
889 u16 val;
890 int err;
891
892 err = mv88e6xxx_g2_read(chip, GLOBAL2_MISC, &val);
893 if (err)
894 return err;
895
896 if (port_5_bit)
897 val |= GLOBAL2_MISC_5_BIT_PORT;
898 else
899 val &= ~GLOBAL2_MISC_5_BIT_PORT;
900
901 return mv88e6xxx_g2_write(chip, GLOBAL2_MISC, val);
902}
903
904int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip)
905{
906 return mv88e6xxx_g2_misc_5_bit_port(chip, false);
907}
908
Andrew Lunndc30c352016-10-16 19:56:49 +0200909static void mv88e6xxx_g2_irq_mask(struct irq_data *d)
910{
911 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
912 unsigned int n = d->hwirq;
913
914 chip->g2_irq.masked |= (1 << n);
915}
916
917static void mv88e6xxx_g2_irq_unmask(struct irq_data *d)
918{
919 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
920 unsigned int n = d->hwirq;
921
922 chip->g2_irq.masked &= ~(1 << n);
923}
924
925static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id)
926{
927 struct mv88e6xxx_chip *chip = dev_id;
928 unsigned int nhandled = 0;
929 unsigned int sub_irq;
930 unsigned int n;
931 int err;
932 u16 reg;
933
934 mutex_lock(&chip->reg_lock);
935 err = mv88e6xxx_g2_read(chip, GLOBAL2_INT_SOURCE, &reg);
936 mutex_unlock(&chip->reg_lock);
937 if (err)
938 goto out;
939
940 for (n = 0; n < 16; ++n) {
941 if (reg & (1 << n)) {
942 sub_irq = irq_find_mapping(chip->g2_irq.domain, n);
943 handle_nested_irq(sub_irq);
944 ++nhandled;
945 }
946 }
947out:
948 return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
949}
950
951static void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d)
952{
953 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
954
955 mutex_lock(&chip->reg_lock);
956}
957
958static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
959{
960 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
961
962 mv88e6xxx_g2_write(chip, GLOBAL2_INT_MASK, ~chip->g2_irq.masked);
963
964 mutex_unlock(&chip->reg_lock);
965}
966
967static struct irq_chip mv88e6xxx_g2_irq_chip = {
968 .name = "mv88e6xxx-g2",
969 .irq_mask = mv88e6xxx_g2_irq_mask,
970 .irq_unmask = mv88e6xxx_g2_irq_unmask,
971 .irq_bus_lock = mv88e6xxx_g2_irq_bus_lock,
972 .irq_bus_sync_unlock = mv88e6xxx_g2_irq_bus_sync_unlock,
973};
974
975static int mv88e6xxx_g2_irq_domain_map(struct irq_domain *d,
976 unsigned int irq,
977 irq_hw_number_t hwirq)
978{
979 struct mv88e6xxx_chip *chip = d->host_data;
980
981 irq_set_chip_data(irq, d->host_data);
982 irq_set_chip_and_handler(irq, &chip->g2_irq.chip, handle_level_irq);
983 irq_set_noprobe(irq);
984
985 return 0;
986}
987
988static const struct irq_domain_ops mv88e6xxx_g2_irq_domain_ops = {
989 .map = mv88e6xxx_g2_irq_domain_map,
990 .xlate = irq_domain_xlate_twocell,
991};
992
993void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip)
994{
995 int irq, virq;
996
Andrew Lunnfcd25162017-02-09 00:03:42 +0100997 mv88e6xxx_g2_watchdog_free(chip);
998
Andrew Lunn8e757eb2016-11-20 20:14:18 +0100999 free_irq(chip->device_irq, chip);
1000 irq_dispose_mapping(chip->device_irq);
1001
Andrew Lunndc30c352016-10-16 19:56:49 +02001002 for (irq = 0; irq < 16; irq++) {
1003 virq = irq_find_mapping(chip->g2_irq.domain, irq);
1004 irq_dispose_mapping(virq);
1005 }
1006
1007 irq_domain_remove(chip->g2_irq.domain);
1008}
1009
1010int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip)
1011{
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001012 int err, irq, virq;
Andrew Lunndc30c352016-10-16 19:56:49 +02001013
1014 if (!chip->dev->of_node)
1015 return -EINVAL;
1016
1017 chip->g2_irq.domain = irq_domain_add_simple(
1018 chip->dev->of_node, 16, 0, &mv88e6xxx_g2_irq_domain_ops, chip);
1019 if (!chip->g2_irq.domain)
1020 return -ENOMEM;
1021
1022 for (irq = 0; irq < 16; irq++)
1023 irq_create_mapping(chip->g2_irq.domain, irq);
1024
1025 chip->g2_irq.chip = mv88e6xxx_g2_irq_chip;
1026 chip->g2_irq.masked = ~0;
1027
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001028 chip->device_irq = irq_find_mapping(chip->g1_irq.domain,
Vivien Didelot82466922017-06-15 12:13:59 -04001029 MV88E6XXX_G1_STS_IRQ_DEVICE);
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001030 if (chip->device_irq < 0) {
1031 err = chip->device_irq;
Andrew Lunndc30c352016-10-16 19:56:49 +02001032 goto out;
1033 }
1034
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001035 err = request_threaded_irq(chip->device_irq, NULL,
1036 mv88e6xxx_g2_irq_thread_fn,
1037 IRQF_ONESHOT, "mv88e6xxx-g1", chip);
Andrew Lunndc30c352016-10-16 19:56:49 +02001038 if (err)
1039 goto out;
1040
Andrew Lunnfcd25162017-02-09 00:03:42 +01001041 return mv88e6xxx_g2_watchdog_setup(chip);
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001042
Andrew Lunndc30c352016-10-16 19:56:49 +02001043out:
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001044 for (irq = 0; irq < 16; irq++) {
1045 virq = irq_find_mapping(chip->g2_irq.domain, irq);
1046 irq_dispose_mapping(virq);
1047 }
1048
1049 irq_domain_remove(chip->g2_irq.domain);
Andrew Lunndc30c352016-10-16 19:56:49 +02001050
1051 return err;
1052}
1053
Vivien Didelotec561272016-09-02 14:45:33 -04001054int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip)
1055{
1056 u16 reg;
1057 int err;
1058
Vivien Didelotec561272016-09-02 14:45:33 -04001059 /* Ignore removed tag data on doubly tagged packets, disable
1060 * flow control messages, force flow control priority to the
1061 * highest, and send all special multicast frames to the CPU
1062 * port at the highest priority.
1063 */
Vivien Didelot6bff47b2017-06-19 10:55:40 -04001064 reg = MV88E6XXX_G2_SWITCH_MGMT_FORCE_FLOW_CTL_PRI | (0x7 << 4);
Vivien Didelotec561272016-09-02 14:45:33 -04001065 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X) ||
1066 mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X))
Vivien Didelot6bff47b2017-06-19 10:55:40 -04001067 reg |= MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU | 0x7;
1068 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MGMT, reg);
Vivien Didelotec561272016-09-02 14:45:33 -04001069 if (err)
1070 return err;
1071
1072 /* Program the DSA routing table. */
1073 err = mv88e6xxx_g2_set_device_mapping(chip);
1074 if (err)
1075 return err;
1076
1077 /* Clear all trunk masks and mapping. */
1078 err = mv88e6xxx_g2_clear_trunk(chip);
1079 if (err)
1080 return err;
1081
Vivien Didelotec561272016-09-02 14:45:33 -04001082 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_POT)) {
1083 /* Clear the priority override table. */
1084 err = mv88e6xxx_g2_clear_pot(chip);
1085 if (err)
1086 return err;
1087 }
1088
1089 return 0;
1090}