blob: 158d0f499874031083d7d5646b3a3a22e603b8f6 [file] [log] [blame]
Vivien Didelotec561272016-09-02 14:45:33 -04001/*
Vivien Didelot1d900162017-06-19 10:55:45 -04002 * Marvell 88E6xxx Switch Global 2 Registers support
Vivien Didelotec561272016-09-02 14:45:33 -04003 *
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 Didelotec561272016-09-02 14:45:33 -04008 *
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 Didelote289ef02017-06-19 10:55:37 -040015#include <linux/bitfield.h>
Florian Westphal282ccf62017-03-29 17:17:31 +020016#include <linux/interrupt.h>
Andrew Lunndc30c352016-10-16 19:56:49 +020017#include <linux/irqdomain.h>
Vivien Didelot4d5f2ba72017-06-02 17:06:15 -040018
19#include "chip.h"
Vivien Didelot82466922017-06-15 12:13:59 -040020#include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */
Vivien Didelotec561272016-09-02 14:45:33 -040021#include "global2.h"
22
Vivien Didelot9fe850f2016-09-29 12:21:54 -040023static int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
24{
Vivien Didelot1d900162017-06-19 10:55:45 -040025 return mv88e6xxx_read(chip, MV88E6XXX_G2, reg, val);
Vivien Didelot9fe850f2016-09-29 12:21:54 -040026}
27
28static int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
29{
Vivien Didelot1d900162017-06-19 10:55:45 -040030 return mv88e6xxx_write(chip, MV88E6XXX_G2, reg, val);
Vivien Didelot9fe850f2016-09-29 12:21:54 -040031}
32
33static int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update)
34{
Vivien Didelot1d900162017-06-19 10:55:45 -040035 return mv88e6xxx_update(chip, MV88E6XXX_G2, reg, update);
Vivien Didelot9fe850f2016-09-29 12:21:54 -040036}
37
38static int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
39{
Vivien Didelot1d900162017-06-19 10:55:45 -040040 return mv88e6xxx_wait(chip, MV88E6XXX_G2, reg, mask);
Vivien Didelot9fe850f2016-09-29 12:21:54 -040041}
42
Andrew Lunn6e55f692016-12-03 04:45:16 +010043/* Offset 0x02: Management Enable 2x */
44/* Offset 0x03: Management Enable 0x */
45
46int mv88e6095_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
47{
48 int err;
49
50 /* Consider the frames with reserved multicast destination
51 * addresses matching 01:80:c2:00:00:2x as MGMT.
52 */
53 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X)) {
Vivien Didelot6bff47b2017-06-19 10:55:40 -040054 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_2X, 0xffff);
Andrew Lunn6e55f692016-12-03 04:45:16 +010055 if (err)
56 return err;
57 }
58
59 /* Consider the frames with reserved multicast destination
60 * addresses matching 01:80:c2:00:00:0x as MGMT.
61 */
62 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X))
Vivien Didelot6bff47b2017-06-19 10:55:40 -040063 return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_0X,
64 0xffff);
Andrew Lunn6e55f692016-12-03 04:45:16 +010065
66 return 0;
67}
68
Vivien Didelotec561272016-09-02 14:45:33 -040069/* Offset 0x06: Device Mapping Table register */
70
71static int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip,
72 int target, int port)
73{
74 u16 val = (target << 8) | (port & 0xf);
75
Vivien Didelot067e4742017-06-19 10:55:39 -040076 return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_DEVICE_MAPPING, val);
Vivien Didelotec561272016-09-02 14:45:33 -040077}
78
79static int mv88e6xxx_g2_set_device_mapping(struct mv88e6xxx_chip *chip)
80{
81 int target, port;
82 int err;
83
84 /* Initialize the routing port to the 32 possible target devices */
85 for (target = 0; target < 32; ++target) {
86 port = 0xf;
87
88 if (target < DSA_MAX_SWITCHES) {
89 port = chip->ds->rtable[target];
90 if (port == DSA_RTABLE_NONE)
91 port = 0xf;
92 }
93
94 err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
95 if (err)
96 break;
97 }
98
99 return err;
100}
101
102/* Offset 0x07: Trunk Mask Table register */
103
104static int mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip *chip, int num,
Vivien Didelot56dc7342017-06-19 10:55:38 -0400105 bool hash, u16 mask)
Vivien Didelotec561272016-09-02 14:45:33 -0400106{
Vivien Didelot56dc7342017-06-19 10:55:38 -0400107 u16 val = (num << 12) | (mask & mv88e6xxx_port_mask(chip));
Vivien Didelotec561272016-09-02 14:45:33 -0400108
Vivien Didelot56dc7342017-06-19 10:55:38 -0400109 if (hash)
110 val |= MV88E6XXX_G2_TRUNK_MASK_HASH;
Vivien Didelotec561272016-09-02 14:45:33 -0400111
Vivien Didelot56dc7342017-06-19 10:55:38 -0400112 return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_TRUNK_MASK, val);
Vivien Didelotec561272016-09-02 14:45:33 -0400113}
114
115/* Offset 0x08: Trunk Mapping Table register */
116
117static int mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip *chip, int id,
118 u16 map)
119{
Vivien Didelot370b4ff2016-09-29 12:21:57 -0400120 const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
Vivien Didelotec561272016-09-02 14:45:33 -0400121 u16 val = (id << 11) | (map & port_mask);
122
Vivien Didelot56dc7342017-06-19 10:55:38 -0400123 return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_TRUNK_MAPPING, val);
Vivien Didelotec561272016-09-02 14:45:33 -0400124}
125
126static int mv88e6xxx_g2_clear_trunk(struct mv88e6xxx_chip *chip)
127{
Vivien Didelot370b4ff2016-09-29 12:21:57 -0400128 const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
Vivien Didelotec561272016-09-02 14:45:33 -0400129 int i, err;
130
131 /* Clear all eight possible Trunk Mask vectors */
132 for (i = 0; i < 8; ++i) {
133 err = mv88e6xxx_g2_trunk_mask_write(chip, i, false, port_mask);
134 if (err)
135 return err;
136 }
137
138 /* Clear all sixteen possible Trunk ID routing vectors */
139 for (i = 0; i < 16; ++i) {
140 err = mv88e6xxx_g2_trunk_mapping_write(chip, i, 0);
141 if (err)
142 return err;
143 }
144
145 return 0;
146}
147
148/* Offset 0x09: Ingress Rate Command register
149 * Offset 0x0A: Ingress Rate Data register
150 */
151
Vivien Didelotcd8da8b2017-06-19 10:55:36 -0400152static int mv88e6xxx_g2_irl_wait(struct mv88e6xxx_chip *chip)
Vivien Didelotec561272016-09-02 14:45:33 -0400153{
Vivien Didelotcd8da8b2017-06-19 10:55:36 -0400154 return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_IRL_CMD,
155 MV88E6XXX_G2_IRL_CMD_BUSY);
156}
Vivien Didelotec561272016-09-02 14:45:33 -0400157
Vivien Didelotcd8da8b2017-06-19 10:55:36 -0400158static int mv88e6xxx_g2_irl_op(struct mv88e6xxx_chip *chip, u16 op, int port,
159 int res, int reg)
160{
161 int err;
Vivien Didelotec561272016-09-02 14:45:33 -0400162
Vivien Didelotcd8da8b2017-06-19 10:55:36 -0400163 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_IRL_CMD,
164 MV88E6XXX_G2_IRL_CMD_BUSY | op | (port << 8) |
165 (res << 5) | reg);
166 if (err)
167 return err;
Vivien Didelotec561272016-09-02 14:45:33 -0400168
Vivien Didelotcd8da8b2017-06-19 10:55:36 -0400169 return mv88e6xxx_g2_irl_wait(chip);
170}
171
172int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
173{
174 return mv88e6xxx_g2_irl_op(chip, MV88E6352_G2_IRL_CMD_OP_INIT_ALL, port,
175 0, 0);
176}
177
178int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
179{
180 return mv88e6xxx_g2_irl_op(chip, MV88E6390_G2_IRL_CMD_OP_INIT_ALL, port,
181 0, 0);
Vivien Didelotec561272016-09-02 14:45:33 -0400182}
183
Vivien Didelot17a15942017-03-30 17:37:09 -0400184/* Offset 0x0B: Cross-chip Port VLAN (Addr) Register
185 * Offset 0x0C: Cross-chip Port VLAN Data Register
186 */
187
188static int mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip *chip)
189{
Vivien Didelot67d1ea82017-06-19 10:55:41 -0400190 return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_PVT_ADDR,
191 MV88E6XXX_G2_PVT_ADDR_BUSY);
Vivien Didelot17a15942017-03-30 17:37:09 -0400192}
193
194static int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev,
195 int src_port, u16 op)
196{
197 int err;
198
Vivien Didelot67d1ea82017-06-19 10:55:41 -0400199 /* 9-bit Cross-chip PVT pointer: with MV88E6XXX_G2_MISC_5_BIT_PORT
200 * cleared, source device is 5-bit, source port is 4-bit.
Vivien Didelot17a15942017-03-30 17:37:09 -0400201 */
Vivien Didelot67d1ea82017-06-19 10:55:41 -0400202 op |= MV88E6XXX_G2_PVT_ADDR_BUSY;
Vivien Didelot17a15942017-03-30 17:37:09 -0400203 op |= (src_dev & 0x1f) << 4;
204 op |= (src_port & 0xf);
205
Vivien Didelot67d1ea82017-06-19 10:55:41 -0400206 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_ADDR, op);
Vivien Didelot17a15942017-03-30 17:37:09 -0400207 if (err)
208 return err;
209
210 return mv88e6xxx_g2_pvt_op_wait(chip);
211}
212
213int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev,
214 int src_port, u16 data)
215{
216 int err;
217
218 err = mv88e6xxx_g2_pvt_op_wait(chip);
219 if (err)
220 return err;
221
Vivien Didelot67d1ea82017-06-19 10:55:41 -0400222 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_DATA, data);
Vivien Didelot17a15942017-03-30 17:37:09 -0400223 if (err)
224 return err;
225
226 return mv88e6xxx_g2_pvt_op(chip, src_dev, src_port,
Vivien Didelot67d1ea82017-06-19 10:55:41 -0400227 MV88E6XXX_G2_PVT_ADDR_OP_WRITE_PVLAN);
Vivien Didelot17a15942017-03-30 17:37:09 -0400228}
229
Vivien Didelotec561272016-09-02 14:45:33 -0400230/* Offset 0x0D: Switch MAC/WoL/WoF register */
231
232static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip,
233 unsigned int pointer, u8 data)
234{
235 u16 val = (pointer << 8) | data;
236
Vivien Dideloted441522017-06-19 10:55:43 -0400237 return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_SWITCH_MAC, val);
Vivien Didelotec561272016-09-02 14:45:33 -0400238}
239
240int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr)
241{
242 int i, err;
243
244 for (i = 0; i < 6; i++) {
245 err = mv88e6xxx_g2_switch_mac_write(chip, i, addr[i]);
246 if (err)
247 break;
248 }
249
250 return err;
251}
252
253/* Offset 0x0F: Priority Override Table */
254
255static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer,
256 u8 data)
257{
258 u16 val = (pointer << 8) | (data & 0x7);
259
Vivien Didelot1d900162017-06-19 10:55:45 -0400260 return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_PRIO_OVERRIDE, val);
Vivien Didelotec561272016-09-02 14:45:33 -0400261}
262
263static int mv88e6xxx_g2_clear_pot(struct mv88e6xxx_chip *chip)
264{
265 int i, err;
266
267 /* Clear all sixteen possible Priority Override entries */
268 for (i = 0; i < 16; i++) {
269 err = mv88e6xxx_g2_pot_write(chip, i, 0);
270 if (err)
271 break;
272 }
273
274 return err;
275}
276
277/* Offset 0x14: EEPROM Command
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500278 * Offset 0x15: EEPROM Data (for 16-bit data access)
279 * Offset 0x15: EEPROM Addr (for 8-bit data access)
Vivien Didelotec561272016-09-02 14:45:33 -0400280 */
281
282static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
283{
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400284 return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_EEPROM_CMD,
285 MV88E6XXX_G2_EEPROM_CMD_BUSY |
286 MV88E6XXX_G2_EEPROM_CMD_RUNNING);
Vivien Didelotec561272016-09-02 14:45:33 -0400287}
288
289static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
290{
291 int err;
292
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400293 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_EEPROM_CMD,
294 MV88E6XXX_G2_EEPROM_CMD_BUSY | cmd);
Vivien Didelotec561272016-09-02 14:45:33 -0400295 if (err)
296 return err;
297
298 return mv88e6xxx_g2_eeprom_wait(chip);
299}
300
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500301static int mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip *chip,
302 u16 addr, u8 *data)
303{
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400304 u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ;
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500305 int err;
306
307 err = mv88e6xxx_g2_eeprom_wait(chip);
308 if (err)
309 return err;
310
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400311 err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500312 if (err)
313 return err;
314
315 err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
316 if (err)
317 return err;
318
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400319 err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &cmd);
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500320 if (err)
321 return err;
322
323 *data = cmd & 0xff;
324
325 return 0;
326}
327
328static int mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip *chip,
329 u16 addr, u8 data)
330{
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400331 u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE |
332 MV88E6XXX_G2_EEPROM_CMD_WRITE_EN;
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500333 int err;
334
335 err = mv88e6xxx_g2_eeprom_wait(chip);
336 if (err)
337 return err;
338
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400339 err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500340 if (err)
341 return err;
342
343 return mv88e6xxx_g2_eeprom_cmd(chip, cmd | data);
344}
345
Vivien Didelotec561272016-09-02 14:45:33 -0400346static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip,
347 u8 addr, u16 *data)
348{
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400349 u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ | addr;
Vivien Didelotec561272016-09-02 14:45:33 -0400350 int err;
351
352 err = mv88e6xxx_g2_eeprom_wait(chip);
353 if (err)
354 return err;
355
356 err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
357 if (err)
358 return err;
359
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400360 return mv88e6xxx_g2_read(chip, MV88E6352_G2_EEPROM_DATA, data);
Vivien Didelotec561272016-09-02 14:45:33 -0400361}
362
363static int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip,
364 u8 addr, u16 data)
365{
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400366 u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE | addr;
Vivien Didelotec561272016-09-02 14:45:33 -0400367 int err;
368
369 err = mv88e6xxx_g2_eeprom_wait(chip);
370 if (err)
371 return err;
372
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400373 err = mv88e6xxx_g2_write(chip, MV88E6352_G2_EEPROM_DATA, data);
Vivien Didelotec561272016-09-02 14:45:33 -0400374 if (err)
375 return err;
376
377 return mv88e6xxx_g2_eeprom_cmd(chip, cmd);
378}
379
Vivien Didelot98fc3c62017-01-12 18:07:16 -0500380int mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip *chip,
381 struct ethtool_eeprom *eeprom, u8 *data)
382{
383 unsigned int offset = eeprom->offset;
384 unsigned int len = eeprom->len;
385 int err;
386
387 eeprom->len = 0;
388
389 while (len) {
390 err = mv88e6xxx_g2_eeprom_read8(chip, offset, data);
391 if (err)
392 return err;
393
394 eeprom->len++;
395 offset++;
396 data++;
397 len--;
398 }
399
400 return 0;
401}
402
403int mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip *chip,
404 struct ethtool_eeprom *eeprom, u8 *data)
405{
406 unsigned int offset = eeprom->offset;
407 unsigned int len = eeprom->len;
408 int err;
409
410 eeprom->len = 0;
411
412 while (len) {
413 err = mv88e6xxx_g2_eeprom_write8(chip, offset, *data);
414 if (err)
415 return err;
416
417 eeprom->len++;
418 offset++;
419 data++;
420 len--;
421 }
422
423 return 0;
424}
425
Vivien Didelotec561272016-09-02 14:45:33 -0400426int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
427 struct ethtool_eeprom *eeprom, u8 *data)
428{
429 unsigned int offset = eeprom->offset;
430 unsigned int len = eeprom->len;
431 u16 val;
432 int err;
433
434 eeprom->len = 0;
435
436 if (offset & 1) {
437 err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
438 if (err)
439 return err;
440
441 *data++ = (val >> 8) & 0xff;
442
443 offset++;
444 len--;
445 eeprom->len++;
446 }
447
448 while (len >= 2) {
449 err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
450 if (err)
451 return err;
452
453 *data++ = val & 0xff;
454 *data++ = (val >> 8) & 0xff;
455
456 offset += 2;
457 len -= 2;
458 eeprom->len += 2;
459 }
460
461 if (len) {
462 err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
463 if (err)
464 return err;
465
466 *data++ = val & 0xff;
467
468 offset++;
469 len--;
470 eeprom->len++;
471 }
472
473 return 0;
474}
475
476int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
477 struct ethtool_eeprom *eeprom, u8 *data)
478{
479 unsigned int offset = eeprom->offset;
480 unsigned int len = eeprom->len;
481 u16 val;
482 int err;
483
484 /* Ensure the RO WriteEn bit is set */
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400485 err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &val);
Vivien Didelotec561272016-09-02 14:45:33 -0400486 if (err)
487 return err;
488
Vivien Didelot7fc8c9d2017-06-19 10:55:42 -0400489 if (!(val & MV88E6XXX_G2_EEPROM_CMD_WRITE_EN))
Vivien Didelotec561272016-09-02 14:45:33 -0400490 return -EROFS;
491
492 eeprom->len = 0;
493
494 if (offset & 1) {
495 err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
496 if (err)
497 return err;
498
499 val = (*data++ << 8) | (val & 0xff);
500
501 err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
502 if (err)
503 return err;
504
505 offset++;
506 len--;
507 eeprom->len++;
508 }
509
510 while (len >= 2) {
511 val = *data++;
512 val |= *data++ << 8;
513
514 err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
515 if (err)
516 return err;
517
518 offset += 2;
519 len -= 2;
520 eeprom->len += 2;
521 }
522
523 if (len) {
524 err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
525 if (err)
526 return err;
527
528 val = (val & 0xff00) | *data++;
529
530 err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
531 if (err)
532 return err;
533
534 offset++;
535 len--;
536 eeprom->len++;
537 }
538
539 return 0;
540}
541
542/* Offset 0x18: SMI PHY Command Register
543 * Offset 0x19: SMI PHY Data Register
544 */
545
546static int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip)
547{
Vivien Didelote289ef02017-06-19 10:55:37 -0400548 return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_SMI_PHY_CMD,
549 MV88E6XXX_G2_SMI_PHY_CMD_BUSY);
Vivien Didelotec561272016-09-02 14:45:33 -0400550}
551
552static int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
553{
554 int err;
555
Vivien Didelote289ef02017-06-19 10:55:37 -0400556 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_CMD,
557 MV88E6XXX_G2_SMI_PHY_CMD_BUSY | cmd);
Vivien Didelotec561272016-09-02 14:45:33 -0400558 if (err)
559 return err;
560
561 return mv88e6xxx_g2_smi_phy_wait(chip);
562}
563
Vivien Didelote289ef02017-06-19 10:55:37 -0400564static int mv88e6xxx_g2_smi_phy_access(struct mv88e6xxx_chip *chip,
565 bool external, bool c45, u16 op, int dev,
566 int reg)
Vivien Didelotec561272016-09-02 14:45:33 -0400567{
Vivien Didelote289ef02017-06-19 10:55:37 -0400568 u16 cmd = op;
Vivien Didelotec561272016-09-02 14:45:33 -0400569
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100570 if (external)
Vivien Didelote289ef02017-06-19 10:55:37 -0400571 cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_EXTERNAL;
572 else
573 cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_INTERNAL; /* empty mask */
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100574
Vivien Didelote289ef02017-06-19 10:55:37 -0400575 if (c45)
576 cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_45; /* empty mask */
577 else
578 cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_22;
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100579
Vivien Didelote289ef02017-06-19 10:55:37 -0400580 dev <<= __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK);
581 cmd |= dev & MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK;
582 cmd |= reg & MV88E6XXX_G2_SMI_PHY_CMD_REG_ADDR_MASK;
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100583
584 return mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
585}
586
Vivien Didelote289ef02017-06-19 10:55:37 -0400587static int mv88e6xxx_g2_smi_phy_access_c22(struct mv88e6xxx_chip *chip,
588 bool external, u16 op, int dev,
589 int reg)
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100590{
Vivien Didelote289ef02017-06-19 10:55:37 -0400591 return mv88e6xxx_g2_smi_phy_access(chip, external, false, op, dev, reg);
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100592}
593
Vivien Didelote289ef02017-06-19 10:55:37 -0400594/* IEEE 802.3 Clause 22 Read Data Register */
595static int mv88e6xxx_g2_smi_phy_read_data_c22(struct mv88e6xxx_chip *chip,
596 bool external, int dev, int reg,
597 u16 *data)
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100598{
Vivien Didelote289ef02017-06-19 10:55:37 -0400599 u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_READ_DATA;
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100600 int err;
601
Vivien Didelotec561272016-09-02 14:45:33 -0400602 err = mv88e6xxx_g2_smi_phy_wait(chip);
603 if (err)
604 return err;
605
Vivien Didelote289ef02017-06-19 10:55:37 -0400606 err = mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
Vivien Didelotec561272016-09-02 14:45:33 -0400607 if (err)
608 return err;
609
Vivien Didelote289ef02017-06-19 10:55:37 -0400610 return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
Vivien Didelotec561272016-09-02 14:45:33 -0400611}
612
Vivien Didelote289ef02017-06-19 10:55:37 -0400613/* IEEE 802.3 Clause 22 Write Data Register */
614static int mv88e6xxx_g2_smi_phy_write_data_c22(struct mv88e6xxx_chip *chip,
615 bool external, int dev, int reg,
616 u16 data)
617{
618 u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_WRITE_DATA;
619 int err;
620
621 err = mv88e6xxx_g2_smi_phy_wait(chip);
622 if (err)
623 return err;
624
625 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
626 if (err)
627 return err;
628
629 return mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
630}
631
632static int mv88e6xxx_g2_smi_phy_access_c45(struct mv88e6xxx_chip *chip,
633 bool external, u16 op, int port,
634 int dev)
635{
636 return mv88e6xxx_g2_smi_phy_access(chip, external, true, op, port, dev);
637}
638
639/* IEEE 802.3 Clause 45 Write Address Register */
640static int mv88e6xxx_g2_smi_phy_write_addr_c45(struct mv88e6xxx_chip *chip,
641 bool external, int port, int dev,
642 int addr)
643{
644 u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_ADDR;
645 int err;
646
647 err = mv88e6xxx_g2_smi_phy_wait(chip);
648 if (err)
649 return err;
650
651 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, addr);
652 if (err)
653 return err;
654
655 return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
656}
657
658/* IEEE 802.3 Clause 45 Read Data Register */
659static int mv88e6xxx_g2_smi_phy_read_data_c45(struct mv88e6xxx_chip *chip,
660 bool external, int port, int dev,
661 u16 *data)
662{
663 u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA;
664 int err;
665
666 err = mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
667 if (err)
668 return err;
669
670 return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
671}
672
673static int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip,
674 bool external, int port, int reg,
675 u16 *data)
676{
677 int dev = (reg >> 16) & 0x1f;
678 int addr = reg & 0xffff;
679 int err;
680
681 err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev,
682 addr);
683 if (err)
684 return err;
685
686 return mv88e6xxx_g2_smi_phy_read_data_c45(chip, external, port, dev,
687 data);
688}
689
690/* IEEE 802.3 Clause 45 Write Data Register */
691static int mv88e6xxx_g2_smi_phy_write_data_c45(struct mv88e6xxx_chip *chip,
692 bool external, int port, int dev,
693 u16 data)
694{
695 u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_DATA;
696 int err;
697
698 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
699 if (err)
700 return err;
701
702 return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
703}
704
705static int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip,
706 bool external, int port, int reg,
707 u16 data)
708{
709 int dev = (reg >> 16) & 0x1f;
710 int addr = reg & 0xffff;
711 int err;
712
713 err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev,
714 addr);
715 if (err)
716 return err;
717
718 return mv88e6xxx_g2_smi_phy_write_data_c45(chip, external, port, dev,
719 data);
720}
721
722int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100723 int addr, int reg, u16 *val)
724{
725 struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
726 bool external = mdio_bus->external;
727
728 if (reg & MII_ADDR_C45)
Vivien Didelote289ef02017-06-19 10:55:37 -0400729 return mv88e6xxx_g2_smi_phy_read_c45(chip, external, addr, reg,
730 val);
731
732 return mv88e6xxx_g2_smi_phy_read_data_c22(chip, external, addr, reg,
733 val);
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100734}
735
Vivien Didelote289ef02017-06-19 10:55:37 -0400736int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100737 int addr, int reg, u16 val)
738{
739 struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
740 bool external = mdio_bus->external;
741
742 if (reg & MII_ADDR_C45)
Vivien Didelote289ef02017-06-19 10:55:37 -0400743 return mv88e6xxx_g2_smi_phy_write_c45(chip, external, addr, reg,
744 val);
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100745
Vivien Didelote289ef02017-06-19 10:55:37 -0400746 return mv88e6xxx_g2_smi_phy_write_data_c22(chip, external, addr, reg,
747 val);
Andrew Lunncf3e80d2017-02-04 20:12:24 +0100748}
749
Andrew Lunnfcd25162017-02-09 00:03:42 +0100750static int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
751{
752 u16 reg;
753
Vivien Didelot3b19df72017-06-19 10:55:44 -0400754 mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, &reg);
Andrew Lunnfcd25162017-02-09 00:03:42 +0100755
756 dev_info(chip->dev, "Watchdog event: 0x%04x", reg);
757
758 return IRQ_HANDLED;
759}
760
761static void mv88e6097_watchdog_free(struct mv88e6xxx_chip *chip)
762{
763 u16 reg;
764
Vivien Didelot3b19df72017-06-19 10:55:44 -0400765 mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, &reg);
Andrew Lunnfcd25162017-02-09 00:03:42 +0100766
Vivien Didelot3b19df72017-06-19 10:55:44 -0400767 reg &= ~(MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
768 MV88E6352_G2_WDOG_CTL_QC_ENABLE);
Andrew Lunnfcd25162017-02-09 00:03:42 +0100769
Vivien Didelot3b19df72017-06-19 10:55:44 -0400770 mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL, reg);
Andrew Lunnfcd25162017-02-09 00:03:42 +0100771}
772
773static int mv88e6097_watchdog_setup(struct mv88e6xxx_chip *chip)
774{
Vivien Didelot3b19df72017-06-19 10:55:44 -0400775 return mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL,
776 MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
777 MV88E6352_G2_WDOG_CTL_QC_ENABLE |
778 MV88E6352_G2_WDOG_CTL_SWRESET);
Andrew Lunnfcd25162017-02-09 00:03:42 +0100779}
780
781const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {
782 .irq_action = mv88e6097_watchdog_action,
783 .irq_setup = mv88e6097_watchdog_setup,
784 .irq_free = mv88e6097_watchdog_free,
785};
786
Andrew Lunn61303732017-02-09 00:03:43 +0100787static int mv88e6390_watchdog_setup(struct mv88e6xxx_chip *chip)
788{
Vivien Didelot3b19df72017-06-19 10:55:44 -0400789 return mv88e6xxx_g2_update(chip, MV88E6390_G2_WDOG_CTL,
790 MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE |
791 MV88E6390_G2_WDOG_CTL_CUT_THROUGH |
792 MV88E6390_G2_WDOG_CTL_QUEUE_CONTROLLER |
793 MV88E6390_G2_WDOG_CTL_EGRESS |
794 MV88E6390_G2_WDOG_CTL_FORCE_IRQ);
Andrew Lunn61303732017-02-09 00:03:43 +0100795}
796
797static int mv88e6390_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
798{
799 int err;
800 u16 reg;
801
Vivien Didelot3b19df72017-06-19 10:55:44 -0400802 mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
803 MV88E6390_G2_WDOG_CTL_PTR_EVENT);
804 err = mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, &reg);
Andrew Lunn61303732017-02-09 00:03:43 +0100805
806 dev_info(chip->dev, "Watchdog event: 0x%04x",
Vivien Didelot3b19df72017-06-19 10:55:44 -0400807 reg & MV88E6390_G2_WDOG_CTL_DATA_MASK);
Andrew Lunn61303732017-02-09 00:03:43 +0100808
Vivien Didelot3b19df72017-06-19 10:55:44 -0400809 mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
810 MV88E6390_G2_WDOG_CTL_PTR_HISTORY);
811 err = mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, &reg);
Andrew Lunn61303732017-02-09 00:03:43 +0100812
813 dev_info(chip->dev, "Watchdog history: 0x%04x",
Vivien Didelot3b19df72017-06-19 10:55:44 -0400814 reg & MV88E6390_G2_WDOG_CTL_DATA_MASK);
Andrew Lunn61303732017-02-09 00:03:43 +0100815
816 /* Trigger a software reset to try to recover the switch */
817 if (chip->info->ops->reset)
818 chip->info->ops->reset(chip);
819
820 mv88e6390_watchdog_setup(chip);
821
822 return IRQ_HANDLED;
823}
824
825static void mv88e6390_watchdog_free(struct mv88e6xxx_chip *chip)
826{
Vivien Didelot3b19df72017-06-19 10:55:44 -0400827 mv88e6xxx_g2_update(chip, MV88E6390_G2_WDOG_CTL,
828 MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE);
Andrew Lunn61303732017-02-09 00:03:43 +0100829}
830
831const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {
832 .irq_action = mv88e6390_watchdog_action,
833 .irq_setup = mv88e6390_watchdog_setup,
834 .irq_free = mv88e6390_watchdog_free,
835};
836
Andrew Lunnfcd25162017-02-09 00:03:42 +0100837static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id)
838{
839 struct mv88e6xxx_chip *chip = dev_id;
840 irqreturn_t ret = IRQ_NONE;
841
842 mutex_lock(&chip->reg_lock);
843 if (chip->info->ops->watchdog_ops->irq_action)
844 ret = chip->info->ops->watchdog_ops->irq_action(chip, irq);
845 mutex_unlock(&chip->reg_lock);
846
847 return ret;
848}
849
850static void mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip *chip)
851{
852 mutex_lock(&chip->reg_lock);
853 if (chip->info->ops->watchdog_ops->irq_free)
854 chip->info->ops->watchdog_ops->irq_free(chip);
855 mutex_unlock(&chip->reg_lock);
856
857 free_irq(chip->watchdog_irq, chip);
858 irq_dispose_mapping(chip->watchdog_irq);
859}
860
861static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip)
862{
863 int err;
864
865 chip->watchdog_irq = irq_find_mapping(chip->g2_irq.domain,
Vivien Didelot1d900162017-06-19 10:55:45 -0400866 MV88E6XXX_G2_INT_SOURCE_WATCHDOG);
Andrew Lunnfcd25162017-02-09 00:03:42 +0100867 if (chip->watchdog_irq < 0)
868 return chip->watchdog_irq;
869
870 err = request_threaded_irq(chip->watchdog_irq, NULL,
871 mv88e6xxx_g2_watchdog_thread_fn,
872 IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
873 "mv88e6xxx-watchdog", chip);
874 if (err)
875 return err;
876
877 mutex_lock(&chip->reg_lock);
878 if (chip->info->ops->watchdog_ops->irq_setup)
879 err = chip->info->ops->watchdog_ops->irq_setup(chip);
880 mutex_unlock(&chip->reg_lock);
881
882 return err;
883}
884
Vivien Didelot81228992017-03-30 17:37:08 -0400885/* Offset 0x1D: Misc Register */
886
887static int mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip *chip,
888 bool port_5_bit)
889{
890 u16 val;
891 int err;
892
Vivien Didelot1d900162017-06-19 10:55:45 -0400893 err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_MISC, &val);
Vivien Didelot81228992017-03-30 17:37:08 -0400894 if (err)
895 return err;
896
897 if (port_5_bit)
Vivien Didelot1d900162017-06-19 10:55:45 -0400898 val |= MV88E6XXX_G2_MISC_5_BIT_PORT;
Vivien Didelot81228992017-03-30 17:37:08 -0400899 else
Vivien Didelot1d900162017-06-19 10:55:45 -0400900 val &= ~MV88E6XXX_G2_MISC_5_BIT_PORT;
Vivien Didelot81228992017-03-30 17:37:08 -0400901
Vivien Didelot1d900162017-06-19 10:55:45 -0400902 return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MISC, val);
Vivien Didelot81228992017-03-30 17:37:08 -0400903}
904
905int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip)
906{
907 return mv88e6xxx_g2_misc_5_bit_port(chip, false);
908}
909
Andrew Lunndc30c352016-10-16 19:56:49 +0200910static void mv88e6xxx_g2_irq_mask(struct irq_data *d)
911{
912 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
913 unsigned int n = d->hwirq;
914
915 chip->g2_irq.masked |= (1 << n);
916}
917
918static void mv88e6xxx_g2_irq_unmask(struct irq_data *d)
919{
920 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
921 unsigned int n = d->hwirq;
922
923 chip->g2_irq.masked &= ~(1 << n);
924}
925
926static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id)
927{
928 struct mv88e6xxx_chip *chip = dev_id;
929 unsigned int nhandled = 0;
930 unsigned int sub_irq;
931 unsigned int n;
932 int err;
933 u16 reg;
934
935 mutex_lock(&chip->reg_lock);
Vivien Didelot1d900162017-06-19 10:55:45 -0400936 err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_INT_SOURCE, &reg);
Andrew Lunndc30c352016-10-16 19:56:49 +0200937 mutex_unlock(&chip->reg_lock);
938 if (err)
939 goto out;
940
941 for (n = 0; n < 16; ++n) {
942 if (reg & (1 << n)) {
943 sub_irq = irq_find_mapping(chip->g2_irq.domain, n);
944 handle_nested_irq(sub_irq);
945 ++nhandled;
946 }
947 }
948out:
949 return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
950}
951
952static void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d)
953{
954 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
955
956 mutex_lock(&chip->reg_lock);
957}
958
959static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
960{
961 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
962
Vivien Didelot1d900162017-06-19 10:55:45 -0400963 mv88e6xxx_g2_write(chip, MV88E6XXX_G2_INT_MASK, ~chip->g2_irq.masked);
Andrew Lunndc30c352016-10-16 19:56:49 +0200964
965 mutex_unlock(&chip->reg_lock);
966}
967
968static struct irq_chip mv88e6xxx_g2_irq_chip = {
969 .name = "mv88e6xxx-g2",
970 .irq_mask = mv88e6xxx_g2_irq_mask,
971 .irq_unmask = mv88e6xxx_g2_irq_unmask,
972 .irq_bus_lock = mv88e6xxx_g2_irq_bus_lock,
973 .irq_bus_sync_unlock = mv88e6xxx_g2_irq_bus_sync_unlock,
974};
975
976static int mv88e6xxx_g2_irq_domain_map(struct irq_domain *d,
977 unsigned int irq,
978 irq_hw_number_t hwirq)
979{
980 struct mv88e6xxx_chip *chip = d->host_data;
981
982 irq_set_chip_data(irq, d->host_data);
983 irq_set_chip_and_handler(irq, &chip->g2_irq.chip, handle_level_irq);
984 irq_set_noprobe(irq);
985
986 return 0;
987}
988
989static const struct irq_domain_ops mv88e6xxx_g2_irq_domain_ops = {
990 .map = mv88e6xxx_g2_irq_domain_map,
991 .xlate = irq_domain_xlate_twocell,
992};
993
994void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip)
995{
996 int irq, virq;
997
Andrew Lunnfcd25162017-02-09 00:03:42 +0100998 mv88e6xxx_g2_watchdog_free(chip);
999
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001000 free_irq(chip->device_irq, chip);
1001 irq_dispose_mapping(chip->device_irq);
1002
Andrew Lunndc30c352016-10-16 19:56:49 +02001003 for (irq = 0; irq < 16; irq++) {
1004 virq = irq_find_mapping(chip->g2_irq.domain, irq);
1005 irq_dispose_mapping(virq);
1006 }
1007
1008 irq_domain_remove(chip->g2_irq.domain);
1009}
1010
1011int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip)
1012{
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001013 int err, irq, virq;
Andrew Lunndc30c352016-10-16 19:56:49 +02001014
1015 if (!chip->dev->of_node)
1016 return -EINVAL;
1017
1018 chip->g2_irq.domain = irq_domain_add_simple(
1019 chip->dev->of_node, 16, 0, &mv88e6xxx_g2_irq_domain_ops, chip);
1020 if (!chip->g2_irq.domain)
1021 return -ENOMEM;
1022
1023 for (irq = 0; irq < 16; irq++)
1024 irq_create_mapping(chip->g2_irq.domain, irq);
1025
1026 chip->g2_irq.chip = mv88e6xxx_g2_irq_chip;
1027 chip->g2_irq.masked = ~0;
1028
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001029 chip->device_irq = irq_find_mapping(chip->g1_irq.domain,
Vivien Didelot82466922017-06-15 12:13:59 -04001030 MV88E6XXX_G1_STS_IRQ_DEVICE);
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001031 if (chip->device_irq < 0) {
1032 err = chip->device_irq;
Andrew Lunndc30c352016-10-16 19:56:49 +02001033 goto out;
1034 }
1035
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001036 err = request_threaded_irq(chip->device_irq, NULL,
1037 mv88e6xxx_g2_irq_thread_fn,
1038 IRQF_ONESHOT, "mv88e6xxx-g1", chip);
Andrew Lunndc30c352016-10-16 19:56:49 +02001039 if (err)
1040 goto out;
1041
Andrew Lunnfcd25162017-02-09 00:03:42 +01001042 return mv88e6xxx_g2_watchdog_setup(chip);
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001043
Andrew Lunndc30c352016-10-16 19:56:49 +02001044out:
Andrew Lunn8e757eb2016-11-20 20:14:18 +01001045 for (irq = 0; irq < 16; irq++) {
1046 virq = irq_find_mapping(chip->g2_irq.domain, irq);
1047 irq_dispose_mapping(virq);
1048 }
1049
1050 irq_domain_remove(chip->g2_irq.domain);
Andrew Lunndc30c352016-10-16 19:56:49 +02001051
1052 return err;
1053}
1054
Vivien Didelotec561272016-09-02 14:45:33 -04001055int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip)
1056{
1057 u16 reg;
1058 int err;
1059
Vivien Didelotec561272016-09-02 14:45:33 -04001060 /* Ignore removed tag data on doubly tagged packets, disable
1061 * flow control messages, force flow control priority to the
1062 * highest, and send all special multicast frames to the CPU
1063 * port at the highest priority.
1064 */
Vivien Didelot6bff47b2017-06-19 10:55:40 -04001065 reg = MV88E6XXX_G2_SWITCH_MGMT_FORCE_FLOW_CTL_PRI | (0x7 << 4);
Vivien Didelotec561272016-09-02 14:45:33 -04001066 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X) ||
1067 mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X))
Vivien Didelot6bff47b2017-06-19 10:55:40 -04001068 reg |= MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU | 0x7;
1069 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MGMT, reg);
Vivien Didelotec561272016-09-02 14:45:33 -04001070 if (err)
1071 return err;
1072
1073 /* Program the DSA routing table. */
1074 err = mv88e6xxx_g2_set_device_mapping(chip);
1075 if (err)
1076 return err;
1077
1078 /* Clear all trunk masks and mapping. */
1079 err = mv88e6xxx_g2_clear_trunk(chip);
1080 if (err)
1081 return err;
1082
Vivien Didelotec561272016-09-02 14:45:33 -04001083 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_POT)) {
1084 /* Clear the priority override table. */
1085 err = mv88e6xxx_g2_clear_pot(chip);
1086 if (err)
1087 return err;
1088 }
1089
1090 return 0;
1091}