1 /*
2  * Marvell 88E6xxx Switch Global (1) Registers support
3  *
4  * Copyright (c) 2008 Marvell Semiconductor
5  *
6  * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
7  *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
8  *
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 
18 int 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 
25 int 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 
32 int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
33 {
34 	return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask);
35 }
36 
37 /* Offset 0x00: Switch Global Status Register */
38 
39 static 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 
60 static 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 
81 static 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 
101 static 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 
130 int 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 
156 int 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 
179 int 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 
197 int 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 
215 /* Offset 0x1a: Monitor Control */
216 /* Offset 0x1a: Monitor & MGMT Control on some devices */
217 
218 int 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  */
240 int 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 
255 static 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 
265 int 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 
278 int 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 
284 int 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 
311 /* Offset 0x1c: Global Control 2 */
312 
313 int 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 
331 int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip)
332 {
333 	return mv88e6xxx_g1_wait(chip, GLOBAL_STATS_OP, GLOBAL_STATS_OP_BUSY);
334 }
335 
336 int 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 
351 int 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 }
357 
358 int 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 }
373 
374 void 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 }
403