blob: ab72eaa92cc34d1ee645fd8f47620477ac99c05a [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 Dideloted441522017-06-19 10:55:43 -0400238 return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_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
Vivien Didelot3b19df72017-06-19 10:55:44 -0400755 mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, &reg);
Andrew Lunnfcd25162017-02-09 00:03:42 +0100756
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
Vivien Didelot3b19df72017-06-19 10:55:44 -0400766 mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, &reg);
Andrew Lunnfcd25162017-02-09 00:03:42 +0100767
Vivien Didelot3b19df72017-06-19 10:55:44 -0400768 reg &= ~(MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
769 MV88E6352_G2_WDOG_CTL_QC_ENABLE);
Andrew Lunnfcd25162017-02-09 00:03:42 +0100770
Vivien Didelot3b19df72017-06-19 10:55:44 -0400771 mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL, reg);
Andrew Lunnfcd25162017-02-09 00:03:42 +0100772}
773
774static int mv88e6097_watchdog_setup(struct mv88e6xxx_chip *chip)
775{
Vivien Didelot3b19df72017-06-19 10:55:44 -0400776 return mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL,
777 MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
778 MV88E6352_G2_WDOG_CTL_QC_ENABLE |
779 MV88E6352_G2_WDOG_CTL_SWRESET);
Andrew Lunnfcd25162017-02-09 00:03:42 +0100780}
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{
Vivien Didelot3b19df72017-06-19 10:55:44 -0400790 return mv88e6xxx_g2_update(chip, MV88E6390_G2_WDOG_CTL,
791 MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE |
792 MV88E6390_G2_WDOG_CTL_CUT_THROUGH |
793 MV88E6390_G2_WDOG_CTL_QUEUE_CONTROLLER |
794 MV88E6390_G2_WDOG_CTL_EGRESS |
795 MV88E6390_G2_WDOG_CTL_FORCE_IRQ);
Andrew Lunn61303732017-02-09 00:03:43 +0100796}
797
798static int mv88e6390_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
799{
800 int err;
801 u16 reg;
802
Vivien Didelot3b19df72017-06-19 10:55:44 -0400803 mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
804 MV88E6390_G2_WDOG_CTL_PTR_EVENT);
805 err = mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, &reg);
Andrew Lunn61303732017-02-09 00:03:43 +0100806
807 dev_info(chip->dev, "Watchdog event: 0x%04x",
Vivien Didelot3b19df72017-06-19 10:55:44 -0400808 reg & MV88E6390_G2_WDOG_CTL_DATA_MASK);
Andrew Lunn61303732017-02-09 00:03:43 +0100809
Vivien Didelot3b19df72017-06-19 10:55:44 -0400810 mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
811 MV88E6390_G2_WDOG_CTL_PTR_HISTORY);
812 err = mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, &reg);
Andrew Lunn61303732017-02-09 00:03:43 +0100813
814 dev_info(chip->dev, "Watchdog history: 0x%04x",
Vivien Didelot3b19df72017-06-19 10:55:44 -0400815 reg & MV88E6390_G2_WDOG_CTL_DATA_MASK);
Andrew Lunn61303732017-02-09 00:03:43 +0100816
817 /* Trigger a software reset to try to recover the switch */
818 if (chip->info->ops->reset)
819 chip->info->ops->reset(chip);
820
821 mv88e6390_watchdog_setup(chip);
822
823 return IRQ_HANDLED;
824}
825
826static void mv88e6390_watchdog_free(struct mv88e6xxx_chip *chip)
827{
Vivien Didelot3b19df72017-06-19 10:55:44 -0400828 mv88e6xxx_g2_update(chip, MV88E6390_G2_WDOG_CTL,
829 MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE);
Andrew Lunn61303732017-02-09 00:03:43 +0100830}
831
832const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {
833 .irq_action = mv88e6390_watchdog_action,
834 .irq_setup = mv88e6390_watchdog_setup,
835 .irq_free = mv88e6390_watchdog_free,
836};
837
Andrew Lunnfcd25162017-02-09 00:03:42 +0100838static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id)
839{
840 struct mv88e6xxx_chip *chip = dev_id;
841 irqreturn_t ret = IRQ_NONE;
842
843 mutex_lock(&chip->reg_lock);
844 if (chip->info->ops->watchdog_ops->irq_action)
845 ret = chip->info->ops->watchdog_ops->irq_action(chip, irq);
846 mutex_unlock(&chip->reg_lock);
847
848 return ret;
849}
850
851static void mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip *chip)
852{
853 mutex_lock(&chip->reg_lock);
854 if (chip->info->ops->watchdog_ops->irq_free)
855 chip->info->ops->watchdog_ops->irq_free(chip);
856 mutex_unlock(&chip->reg_lock);
857
858 free_irq(chip->watchdog_irq, chip);
859 irq_dispose_mapping(chip->watchdog_irq);
860}
861
862static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip)
863{
864 int err;
865
866 chip->watchdog_irq = irq_find_mapping(chip->g2_irq.domain,
867 GLOBAL2_INT_SOURCE_WATCHDOG);
868 if (chip->watchdog_irq < 0)
869 return chip->watchdog_irq;
870
871 err = request_threaded_irq(chip->watchdog_irq, NULL,
872 mv88e6xxx_g2_watchdog_thread_fn,
873 IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
874 "mv88e6xxx-watchdog", chip);
875 if (err)
876 return err;
877
878 mutex_lock(&chip->reg_lock);
879 if (chip->info->ops->watchdog_ops->irq_setup)
880 err = chip->info->ops->watchdog_ops->irq_setup(chip);
881 mutex_unlock(&chip->reg_lock);
882
883 return err;
884}
885
Vivien Didelot81228992017-03-30 17:37:08 -0400886/* Offset 0x1D: Misc Register */
887
888static int mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip *chip,
889 bool port_5_bit)
890{
891 u16 val;
892 int err;
893
894 err = mv88e6xxx_g2_read(chip, GLOBAL2_MISC, &val);
895 if (err)
896 return err;
897
898 if (port_5_bit)
899 val |= GLOBAL2_MISC_5_BIT_PORT;
900 else
901 val &= ~GLOBAL2_MISC_5_BIT_PORT;
902
903 return mv88e6xxx_g2_write(chip, GLOBAL2_MISC, val);
904}
905
906int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip)
907{
908 return mv88e6xxx_g2_misc_5_bit_port(chip, false);
909}
910
Andrew Lunndc30c352016-10-16 19:56:49 +0200911static void mv88e6xxx_g2_irq_mask(struct irq_data *d)
912{
913 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
914 unsigned int n = d->hwirq;
915
916 chip->g2_irq.masked |= (1 << n);
917}
918
919static void mv88e6xxx_g2_irq_unmask(struct irq_data *d)
920{
921 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
922 unsigned int n = d->hwirq;
923
924 chip->g2_irq.masked &= ~(1 << n);
925}
926
927static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id)
928{
929 struct mv88e6xxx_chip *chip = dev_id;
930 unsigned int nhandled = 0;
931 unsigned int sub_irq;
932 unsigned int n;
933 int err;
934 u16 reg;
935
936 mutex_lock(&chip->reg_lock);
937 err = mv88e6xxx_g2_read(chip, GLOBAL2_INT_SOURCE, &reg);
938 mutex_unlock(&chip->reg_lock);
939 if (err)
940 goto out;
941
942 for (n = 0; n < 16; ++n) {
943 if (reg & (1 << n)) {
944 sub_irq = irq_find_mapping(chip->g2_irq.domain, n);
945 handle_nested_irq(sub_irq);
946 ++nhandled;
947 }
948 }
949out:
950 return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
951}
952
953static void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d)
954{
955 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
956
957 mutex_lock(&chip->reg_lock);
958}
959
960static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
961{
962 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
963
964 mv88e6xxx_g2_write(chip, GLOBAL2_INT_MASK, ~chip->g2_irq.masked);
965
966 mutex_unlock(&chip->reg_lock);
967}
968
969static struct irq_chip mv88e6xxx_g2_irq_chip = {
970 .name = "mv88e6xxx-g2",
971 .irq_mask = mv88e6xxx_g2_irq_mask,
972 .irq_unmask = mv88e6xxx_g2_irq_unmask,
973 .irq_bus_lock = mv88e6xxx_g2_irq_bus_lock,
974 .irq_bus_sync_unlock = mv88e6xxx_g2_irq_bus_sync_unlock,
975};
976
977static int mv88e6xxx_g2_irq_domain_map(struct irq_domain *d,
978 unsigned int irq,
979 irq_hw_number_t hwirq)
980{
981 struct mv88e6xxx_chip *chip = d->host_data;
982
983 irq_set_chip_data(irq, d->host_data);
984 irq_set_chip_and_handler(irq, &chip->g2_irq.chip, handle_level_irq);
985 irq_set_noprobe(irq);
986
987 return 0;
988}
989
990static const struct irq_domain_ops mv88e6xxx_g2_irq_domain_ops = {
991 .map = mv88e6xxx_g2_irq_domain_map,
992 .xlate = irq_domain_xlate_twocell,
993};
994
995void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip)
996{
997 int irq, virq;
998
Andrew Lunnfcd25162017-02-09 00:03:42 +0100999 mv88e6xxx_g2_watchdog_free(chip);
1000
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001001 free_irq(chip->device_irq, chip);
1002 irq_dispose_mapping(chip->device_irq);
1003
Andrew Lunndc30c352016-10-16 19:56:49 +02001004 for (irq = 0; irq < 16; irq++) {
1005 virq = irq_find_mapping(chip->g2_irq.domain, irq);
1006 irq_dispose_mapping(virq);
1007 }
1008
1009 irq_domain_remove(chip->g2_irq.domain);
1010}
1011
1012int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip)
1013{
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001014 int err, irq, virq;
Andrew Lunndc30c352016-10-16 19:56:49 +02001015
1016 if (!chip->dev->of_node)
1017 return -EINVAL;
1018
1019 chip->g2_irq.domain = irq_domain_add_simple(
1020 chip->dev->of_node, 16, 0, &mv88e6xxx_g2_irq_domain_ops, chip);
1021 if (!chip->g2_irq.domain)
1022 return -ENOMEM;
1023
1024 for (irq = 0; irq < 16; irq++)
1025 irq_create_mapping(chip->g2_irq.domain, irq);
1026
1027 chip->g2_irq.chip = mv88e6xxx_g2_irq_chip;
1028 chip->g2_irq.masked = ~0;
1029
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001030 chip->device_irq = irq_find_mapping(chip->g1_irq.domain,
Vivien Didelot82466922017-06-15 12:13:59 -04001031 MV88E6XXX_G1_STS_IRQ_DEVICE);
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001032 if (chip->device_irq < 0) {
1033 err = chip->device_irq;
Andrew Lunndc30c352016-10-16 19:56:49 +02001034 goto out;
1035 }
1036
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001037 err = request_threaded_irq(chip->device_irq, NULL,
1038 mv88e6xxx_g2_irq_thread_fn,
1039 IRQF_ONESHOT, "mv88e6xxx-g1", chip);
Andrew Lunndc30c352016-10-16 19:56:49 +02001040 if (err)
1041 goto out;
1042
Andrew Lunnfcd25162017-02-09 00:03:42 +01001043 return mv88e6xxx_g2_watchdog_setup(chip);
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001044
Andrew Lunndc30c352016-10-16 19:56:49 +02001045out:
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001046 for (irq = 0; irq < 16; irq++) {
1047 virq = irq_find_mapping(chip->g2_irq.domain, irq);
1048 irq_dispose_mapping(virq);
1049 }
1050
1051 irq_domain_remove(chip->g2_irq.domain);
Andrew Lunndc30c352016-10-16 19:56:49 +02001052
1053 return err;
1054}
1055
Vivien Didelotec561272016-09-02 14:45:33 -04001056int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip)
1057{
1058 u16 reg;
1059 int err;
1060
Vivien Didelotec561272016-09-02 14:45:33 -04001061 /* Ignore removed tag data on doubly tagged packets, disable
1062 * flow control messages, force flow control priority to the
1063 * highest, and send all special multicast frames to the CPU
1064 * port at the highest priority.
1065 */
Vivien Didelot6bff47b2017-06-19 10:55:40 -04001066 reg = MV88E6XXX_G2_SWITCH_MGMT_FORCE_FLOW_CTL_PRI | (0x7 << 4);
Vivien Didelotec561272016-09-02 14:45:33 -04001067 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X) ||
1068 mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X))
Vivien Didelot6bff47b2017-06-19 10:55:40 -04001069 reg |= MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU | 0x7;
1070 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MGMT, reg);
Vivien Didelotec561272016-09-02 14:45:33 -04001071 if (err)
1072 return err;
1073
1074 /* Program the DSA routing table. */
1075 err = mv88e6xxx_g2_set_device_mapping(chip);
1076 if (err)
1077 return err;
1078
1079 /* Clear all trunk masks and mapping. */
1080 err = mv88e6xxx_g2_clear_trunk(chip);
1081 if (err)
1082 return err;
1083
Vivien Didelotec561272016-09-02 14:45:33 -04001084 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_POT)) {
1085 /* Clear the priority override table. */
1086 err = mv88e6xxx_g2_clear_pot(chip);
1087 if (err)
1088 return err;
1089 }
1090
1091 return 0;
1092}