blob: 39825837a1c9c062accd80af5a8dc3d6ccd4b771 [file] [log] [blame]
Vivien Didelota935c052016-09-29 12:21:53 -04001/*
2 * Marvell 88E6xxx Switch Global (1) Registers support
3 *
4 * Copyright (c) 2008 Marvell Semiconductor
5 *
Vivien Didelot4333d612017-03-28 15:10:36 -04006 * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
7 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Vivien Didelota935c052016-09-29 12:21:53 -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
15#include "mv88e6xxx.h"
16#include "global1.h"
17
18int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
19{
20 int addr = chip->info->global1_addr;
21
22 return mv88e6xxx_read(chip, addr, reg, val);
23}
24
25int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
26{
27 int addr = chip->info->global1_addr;
28
29 return mv88e6xxx_write(chip, addr, reg, val);
30}
31
32int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
33{
34 return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask);
35}
Andrew Lunna605a0f2016-11-21 23:26:58 +010036
Vivien Didelot17e708b2016-12-05 17:30:27 -050037/* Offset 0x00: Switch Global Status Register */
38
Vivien Didelota199d8b2016-12-05 17:30:28 -050039static int mv88e6185_g1_wait_ppu_disabled(struct mv88e6xxx_chip *chip)
40{
41 u16 state;
42 int i, err;
43
44 for (i = 0; i < 16; i++) {
45 err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state);
46 if (err)
47 return err;
48
49 /* Check the value of the PPUState bits 15:14 */
50 state &= GLOBAL_STATUS_PPU_STATE_MASK;
51 if (state != GLOBAL_STATUS_PPU_STATE_POLLING)
52 return 0;
53
54 usleep_range(1000, 2000);
55 }
56
57 return -ETIMEDOUT;
58}
59
Vivien Didelot17e708b2016-12-05 17:30:27 -050060static int mv88e6185_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip)
61{
62 u16 state;
63 int i, err;
64
65 for (i = 0; i < 16; ++i) {
66 err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state);
67 if (err)
68 return err;
69
70 /* Check the value of the PPUState bits 15:14 */
71 state &= GLOBAL_STATUS_PPU_STATE_MASK;
72 if (state == GLOBAL_STATUS_PPU_STATE_POLLING)
73 return 0;
74
75 usleep_range(1000, 2000);
76 }
77
78 return -ETIMEDOUT;
79}
80
81static int mv88e6352_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip)
82{
83 u16 state;
84 int i, err;
85
86 for (i = 0; i < 16; ++i) {
87 err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state);
88 if (err)
89 return err;
90
91 /* Check the value of the PPUState (or InitState) bit 15 */
92 if (state & GLOBAL_STATUS_PPU_STATE)
93 return 0;
94
95 usleep_range(1000, 2000);
96 }
97
98 return -ETIMEDOUT;
99}
100
101static int mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip *chip)
102{
103 const unsigned long timeout = jiffies + 1 * HZ;
104 u16 val;
105 int err;
106
107 /* Wait up to 1 second for the switch to be ready. The InitReady bit 11
108 * is set to a one when all units inside the device (ATU, VTU, etc.)
109 * have finished their initialization and are ready to accept frames.
110 */
111 while (time_before(jiffies, timeout)) {
112 err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &val);
113 if (err)
114 return err;
115
116 if (val & GLOBAL_STATUS_INIT_READY)
117 break;
118
119 usleep_range(1000, 2000);
120 }
121
122 if (time_after(jiffies, timeout))
123 return -ETIMEDOUT;
124
125 return 0;
126}
127
128/* Offset 0x04: Switch Global Control Register */
129
130int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip)
131{
132 u16 val;
133 int err;
134
135 /* Set the SWReset bit 15 along with the PPUEn bit 14, to also restart
136 * the PPU, including re-doing PHY detection and initialization
137 */
138 err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
139 if (err)
140 return err;
141
142 val |= GLOBAL_CONTROL_SW_RESET;
143 val |= GLOBAL_CONTROL_PPU_ENABLE;
144
145 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
146 if (err)
147 return err;
148
149 err = mv88e6xxx_g1_wait_init_ready(chip);
150 if (err)
151 return err;
152
153 return mv88e6185_g1_wait_ppu_polling(chip);
154}
155
156int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip)
157{
158 u16 val;
159 int err;
160
161 /* Set the SWReset bit 15 */
162 err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
163 if (err)
164 return err;
165
166 val |= GLOBAL_CONTROL_SW_RESET;
167
168 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
169 if (err)
170 return err;
171
172 err = mv88e6xxx_g1_wait_init_ready(chip);
173 if (err)
174 return err;
175
176 return mv88e6352_g1_wait_ppu_polling(chip);
177}
178
Vivien Didelota199d8b2016-12-05 17:30:28 -0500179int mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip)
180{
181 u16 val;
182 int err;
183
184 err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
185 if (err)
186 return err;
187
188 val |= GLOBAL_CONTROL_PPU_ENABLE;
189
190 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
191 if (err)
192 return err;
193
194 return mv88e6185_g1_wait_ppu_polling(chip);
195}
196
197int mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip *chip)
198{
199 u16 val;
200 int err;
201
202 err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
203 if (err)
204 return err;
205
206 val &= ~GLOBAL_CONTROL_PPU_ENABLE;
207
208 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
209 if (err)
210 return err;
211
212 return mv88e6185_g1_wait_ppu_disabled(chip);
213}
214
Andrew Lunn33641992016-12-03 04:35:17 +0100215/* Offset 0x1a: Monitor Control */
216/* Offset 0x1a: Monitor & MGMT Control on some devices */
217
218int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
219{
220 u16 reg;
221 int err;
222
223 err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, &reg);
224 if (err)
225 return err;
226
227 reg &= ~(GLOBAL_MONITOR_CONTROL_INGRESS_MASK |
228 GLOBAL_MONITOR_CONTROL_EGRESS_MASK);
229
230 reg |= port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
231 port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT;
232
233 return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
234}
235
236/* Older generations also call this the ARP destination. It has been
237 * generalized in more modern devices such that more than ARP can
238 * egress it
239 */
240int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
241{
242 u16 reg;
243 int err;
244
245 err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, &reg);
246 if (err)
247 return err;
248
249 reg &= ~GLOBAL_MONITOR_CONTROL_ARP_MASK;
250 reg |= port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
251
252 return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
253}
254
255static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip,
256 u16 pointer, u8 data)
257{
258 u16 reg;
259
260 reg = GLOBAL_MONITOR_CONTROL_UPDATE | pointer | data;
261
262 return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
263}
264
265int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
266{
267 int err;
268
269 err = mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_INGRESS,
270 port);
271 if (err)
272 return err;
273
274 return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_EGRESS,
275 port);
276}
277
278int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
279{
280 return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_CPU_DEST,
281 port);
282}
283
Andrew Lunn6e55f692016-12-03 04:45:16 +0100284int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
285{
286 int err;
287
288 /* 01:c2:80:00:00:00:00-01:c2:80:00:00:00:07 are Management */
289 err = mv88e6390_g1_monitor_write(
290 chip, GLOBAL_MONITOR_CONTROL_0180C280000000XLO, 0xff);
291 if (err)
292 return err;
293
294 /* 01:c2:80:00:00:00:08-01:c2:80:00:00:00:0f are Management */
295 err = mv88e6390_g1_monitor_write(
296 chip, GLOBAL_MONITOR_CONTROL_0180C280000000XHI, 0xff);
297 if (err)
298 return err;
299
300 /* 01:c2:80:00:00:00:20-01:c2:80:00:00:00:27 are Management */
301 err = mv88e6390_g1_monitor_write(
302 chip, GLOBAL_MONITOR_CONTROL_0180C280000002XLO, 0xff);
303 if (err)
304 return err;
305
306 /* 01:c2:80:00:00:00:28-01:c2:80:00:00:00:2f are Management */
307 return mv88e6390_g1_monitor_write(
308 chip, GLOBAL_MONITOR_CONTROL_0180C280000002XHI, 0xff);
309}
310
Andrew Lunnde2273872016-11-21 23:27:01 +0100311/* Offset 0x1c: Global Control 2 */
312
313int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
314{
315 u16 val;
316 int err;
317
318 err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL_2, &val);
319 if (err)
320 return err;
321
322 val |= GLOBAL_CONTROL_2_HIST_RX_TX;
323
324 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, val);
325
326 return err;
327}
328
329/* Offset 0x1d: Statistics Operation 2 */
330
Andrew Lunn7f9ef3a2016-11-21 23:27:05 +0100331int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip)
Andrew Lunna605a0f2016-11-21 23:26:58 +0100332{
333 return mv88e6xxx_g1_wait(chip, GLOBAL_STATS_OP, GLOBAL_STATS_OP_BUSY);
334}
335
336int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
337{
338 int err;
339
340 /* Snapshot the hardware statistics counters for this port. */
341 err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
342 GLOBAL_STATS_OP_CAPTURE_PORT |
343 GLOBAL_STATS_OP_HIST_RX_TX | port);
344 if (err)
345 return err;
346
347 /* Wait for the snapshotting to complete. */
348 return mv88e6xxx_g1_stats_wait(chip);
349}
350
351int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
352{
353 port = (port + 1) << 5;
354
355 return mv88e6xxx_g1_stats_snapshot(chip, port);
356}
Andrew Lunn79523472016-11-21 23:27:00 +0100357
358int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
359{
360 int err;
361
362 port = (port + 1) << 5;
363
364 /* Snapshot the hardware statistics counters for this port. */
365 err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
366 GLOBAL_STATS_OP_CAPTURE_PORT | port);
367 if (err)
368 return err;
369
370 /* Wait for the snapshotting to complete. */
371 return mv88e6xxx_g1_stats_wait(chip);
372}
Andrew Lunn7f9ef3a2016-11-21 23:27:05 +0100373
374void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val)
375{
376 u32 value;
377 u16 reg;
378 int err;
379
380 *val = 0;
381
382 err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
383 GLOBAL_STATS_OP_READ_CAPTURED | stat);
384 if (err)
385 return;
386
387 err = mv88e6xxx_g1_stats_wait(chip);
388 if (err)
389 return;
390
391 err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_32, &reg);
392 if (err)
393 return;
394
395 value = reg << 16;
396
397 err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_01, &reg);
398 if (err)
399 return;
400
401 *val = value | reg;
402}