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