blob: c868eb06497f97a8a6ce686ae68840454a0c9720 [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 *
6 * Copyright (c) 2016 Vivien Didelot <vivien.didelot@savoirfairelinux.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include "mv88e6xxx.h"
15#include "global1.h"
16
17int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
18{
19 int addr = chip->info->global1_addr;
20
21 return mv88e6xxx_read(chip, addr, reg, val);
22}
23
24int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
25{
26 int addr = chip->info->global1_addr;
27
28 return mv88e6xxx_write(chip, addr, reg, val);
29}
30
31int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
32{
33 return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask);
34}
Andrew Lunna605a0f2016-11-21 23:26:58 +010035
Vivien Didelot17e708b2016-12-05 17:30:27 -050036/* Offset 0x00: Switch Global Status Register */
37
38static int mv88e6185_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip)
39{
40 u16 state;
41 int i, err;
42
43 for (i = 0; i < 16; ++i) {
44 err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state);
45 if (err)
46 return err;
47
48 /* Check the value of the PPUState bits 15:14 */
49 state &= GLOBAL_STATUS_PPU_STATE_MASK;
50 if (state == GLOBAL_STATUS_PPU_STATE_POLLING)
51 return 0;
52
53 usleep_range(1000, 2000);
54 }
55
56 return -ETIMEDOUT;
57}
58
59static int mv88e6352_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip)
60{
61 u16 state;
62 int i, err;
63
64 for (i = 0; i < 16; ++i) {
65 err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state);
66 if (err)
67 return err;
68
69 /* Check the value of the PPUState (or InitState) bit 15 */
70 if (state & GLOBAL_STATUS_PPU_STATE)
71 return 0;
72
73 usleep_range(1000, 2000);
74 }
75
76 return -ETIMEDOUT;
77}
78
79static int mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip *chip)
80{
81 const unsigned long timeout = jiffies + 1 * HZ;
82 u16 val;
83 int err;
84
85 /* Wait up to 1 second for the switch to be ready. The InitReady bit 11
86 * is set to a one when all units inside the device (ATU, VTU, etc.)
87 * have finished their initialization and are ready to accept frames.
88 */
89 while (time_before(jiffies, timeout)) {
90 err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &val);
91 if (err)
92 return err;
93
94 if (val & GLOBAL_STATUS_INIT_READY)
95 break;
96
97 usleep_range(1000, 2000);
98 }
99
100 if (time_after(jiffies, timeout))
101 return -ETIMEDOUT;
102
103 return 0;
104}
105
106/* Offset 0x04: Switch Global Control Register */
107
108int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip)
109{
110 u16 val;
111 int err;
112
113 /* Set the SWReset bit 15 along with the PPUEn bit 14, to also restart
114 * the PPU, including re-doing PHY detection and initialization
115 */
116 err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
117 if (err)
118 return err;
119
120 val |= GLOBAL_CONTROL_SW_RESET;
121 val |= GLOBAL_CONTROL_PPU_ENABLE;
122
123 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
124 if (err)
125 return err;
126
127 err = mv88e6xxx_g1_wait_init_ready(chip);
128 if (err)
129 return err;
130
131 return mv88e6185_g1_wait_ppu_polling(chip);
132}
133
134int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip)
135{
136 u16 val;
137 int err;
138
139 /* Set the SWReset bit 15 */
140 err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
141 if (err)
142 return err;
143
144 val |= GLOBAL_CONTROL_SW_RESET;
145
146 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
147 if (err)
148 return err;
149
150 err = mv88e6xxx_g1_wait_init_ready(chip);
151 if (err)
152 return err;
153
154 return mv88e6352_g1_wait_ppu_polling(chip);
155}
156
Andrew Lunn33641992016-12-03 04:35:17 +0100157/* Offset 0x1a: Monitor Control */
158/* Offset 0x1a: Monitor & MGMT Control on some devices */
159
160int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
161{
162 u16 reg;
163 int err;
164
165 err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, &reg);
166 if (err)
167 return err;
168
169 reg &= ~(GLOBAL_MONITOR_CONTROL_INGRESS_MASK |
170 GLOBAL_MONITOR_CONTROL_EGRESS_MASK);
171
172 reg |= port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
173 port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT;
174
175 return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
176}
177
178/* Older generations also call this the ARP destination. It has been
179 * generalized in more modern devices such that more than ARP can
180 * egress it
181 */
182int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
183{
184 u16 reg;
185 int err;
186
187 err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, &reg);
188 if (err)
189 return err;
190
191 reg &= ~GLOBAL_MONITOR_CONTROL_ARP_MASK;
192 reg |= port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
193
194 return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
195}
196
197static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip,
198 u16 pointer, u8 data)
199{
200 u16 reg;
201
202 reg = GLOBAL_MONITOR_CONTROL_UPDATE | pointer | data;
203
204 return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
205}
206
207int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
208{
209 int err;
210
211 err = mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_INGRESS,
212 port);
213 if (err)
214 return err;
215
216 return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_EGRESS,
217 port);
218}
219
220int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
221{
222 return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_CPU_DEST,
223 port);
224}
225
Andrew Lunn6e55f692016-12-03 04:45:16 +0100226int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
227{
228 int err;
229
230 /* 01:c2:80:00:00:00:00-01:c2:80:00:00:00:07 are Management */
231 err = mv88e6390_g1_monitor_write(
232 chip, GLOBAL_MONITOR_CONTROL_0180C280000000XLO, 0xff);
233 if (err)
234 return err;
235
236 /* 01:c2:80:00:00:00:08-01:c2:80:00:00:00:0f are Management */
237 err = mv88e6390_g1_monitor_write(
238 chip, GLOBAL_MONITOR_CONTROL_0180C280000000XHI, 0xff);
239 if (err)
240 return err;
241
242 /* 01:c2:80:00:00:00:20-01:c2:80:00:00:00:27 are Management */
243 err = mv88e6390_g1_monitor_write(
244 chip, GLOBAL_MONITOR_CONTROL_0180C280000002XLO, 0xff);
245 if (err)
246 return err;
247
248 /* 01:c2:80:00:00:00:28-01:c2:80:00:00:00:2f are Management */
249 return mv88e6390_g1_monitor_write(
250 chip, GLOBAL_MONITOR_CONTROL_0180C280000002XHI, 0xff);
251}
252
Andrew Lunnde2273872016-11-21 23:27:01 +0100253/* Offset 0x1c: Global Control 2 */
254
255int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
256{
257 u16 val;
258 int err;
259
260 err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL_2, &val);
261 if (err)
262 return err;
263
264 val |= GLOBAL_CONTROL_2_HIST_RX_TX;
265
266 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, val);
267
268 return err;
269}
270
271/* Offset 0x1d: Statistics Operation 2 */
272
Andrew Lunn7f9ef3a2016-11-21 23:27:05 +0100273int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip)
Andrew Lunna605a0f2016-11-21 23:26:58 +0100274{
275 return mv88e6xxx_g1_wait(chip, GLOBAL_STATS_OP, GLOBAL_STATS_OP_BUSY);
276}
277
278int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
279{
280 int err;
281
282 /* Snapshot the hardware statistics counters for this port. */
283 err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
284 GLOBAL_STATS_OP_CAPTURE_PORT |
285 GLOBAL_STATS_OP_HIST_RX_TX | port);
286 if (err)
287 return err;
288
289 /* Wait for the snapshotting to complete. */
290 return mv88e6xxx_g1_stats_wait(chip);
291}
292
293int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
294{
295 port = (port + 1) << 5;
296
297 return mv88e6xxx_g1_stats_snapshot(chip, port);
298}
Andrew Lunn79523472016-11-21 23:27:00 +0100299
300int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
301{
302 int err;
303
304 port = (port + 1) << 5;
305
306 /* Snapshot the hardware statistics counters for this port. */
307 err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
308 GLOBAL_STATS_OP_CAPTURE_PORT | port);
309 if (err)
310 return err;
311
312 /* Wait for the snapshotting to complete. */
313 return mv88e6xxx_g1_stats_wait(chip);
314}
Andrew Lunn7f9ef3a2016-11-21 23:27:05 +0100315
316void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val)
317{
318 u32 value;
319 u16 reg;
320 int err;
321
322 *val = 0;
323
324 err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
325 GLOBAL_STATS_OP_READ_CAPTURED | stat);
326 if (err)
327 return;
328
329 err = mv88e6xxx_g1_stats_wait(chip);
330 if (err)
331 return;
332
333 err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_32, &reg);
334 if (err)
335 return;
336
337 value = reg << 16;
338
339 err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_01, &reg);
340 if (err)
341 return;
342
343 *val = value | reg;
344}