1a935c052SVivien Didelot /*
2a935c052SVivien Didelot  * Marvell 88E6xxx Switch Global (1) Registers support
3a935c052SVivien Didelot  *
4a935c052SVivien Didelot  * Copyright (c) 2008 Marvell Semiconductor
5a935c052SVivien Didelot  *
6a935c052SVivien Didelot  * Copyright (c) 2016 Vivien Didelot <vivien.didelot@savoirfairelinux.com>
7a935c052SVivien Didelot  *
8a935c052SVivien Didelot  * This program is free software; you can redistribute it and/or modify
9a935c052SVivien Didelot  * it under the terms of the GNU General Public License as published by
10a935c052SVivien Didelot  * the Free Software Foundation; either version 2 of the License, or
11a935c052SVivien Didelot  * (at your option) any later version.
12a935c052SVivien Didelot  */
13a935c052SVivien Didelot 
14a935c052SVivien Didelot #include "mv88e6xxx.h"
15a935c052SVivien Didelot #include "global1.h"
16a935c052SVivien Didelot 
17a935c052SVivien Didelot int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
18a935c052SVivien Didelot {
19a935c052SVivien Didelot 	int addr = chip->info->global1_addr;
20a935c052SVivien Didelot 
21a935c052SVivien Didelot 	return mv88e6xxx_read(chip, addr, reg, val);
22a935c052SVivien Didelot }
23a935c052SVivien Didelot 
24a935c052SVivien Didelot int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
25a935c052SVivien Didelot {
26a935c052SVivien Didelot 	int addr = chip->info->global1_addr;
27a935c052SVivien Didelot 
28a935c052SVivien Didelot 	return mv88e6xxx_write(chip, addr, reg, val);
29a935c052SVivien Didelot }
30a935c052SVivien Didelot 
31a935c052SVivien Didelot int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
32a935c052SVivien Didelot {
33a935c052SVivien Didelot 	return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask);
34a935c052SVivien Didelot }
35a605a0feSAndrew Lunn 
3633641994SAndrew Lunn /* Offset 0x1a: Monitor Control */
3733641994SAndrew Lunn /* Offset 0x1a: Monitor & MGMT Control on some devices */
3833641994SAndrew Lunn 
3933641994SAndrew Lunn int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
4033641994SAndrew Lunn {
4133641994SAndrew Lunn 	u16 reg;
4233641994SAndrew Lunn 	int err;
4333641994SAndrew Lunn 
4433641994SAndrew Lunn 	err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, &reg);
4533641994SAndrew Lunn 	if (err)
4633641994SAndrew Lunn 		return err;
4733641994SAndrew Lunn 
4833641994SAndrew Lunn 	reg &= ~(GLOBAL_MONITOR_CONTROL_INGRESS_MASK |
4933641994SAndrew Lunn 		 GLOBAL_MONITOR_CONTROL_EGRESS_MASK);
5033641994SAndrew Lunn 
5133641994SAndrew Lunn 	reg |= port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
5233641994SAndrew Lunn 		port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT;
5333641994SAndrew Lunn 
5433641994SAndrew Lunn 	return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
5533641994SAndrew Lunn }
5633641994SAndrew Lunn 
5733641994SAndrew Lunn /* Older generations also call this the ARP destination. It has been
5833641994SAndrew Lunn  * generalized in more modern devices such that more than ARP can
5933641994SAndrew Lunn  * egress it
6033641994SAndrew Lunn  */
6133641994SAndrew Lunn int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
6233641994SAndrew Lunn {
6333641994SAndrew Lunn 	u16 reg;
6433641994SAndrew Lunn 	int err;
6533641994SAndrew Lunn 
6633641994SAndrew Lunn 	err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, &reg);
6733641994SAndrew Lunn 	if (err)
6833641994SAndrew Lunn 		return err;
6933641994SAndrew Lunn 
7033641994SAndrew Lunn 	reg &= ~GLOBAL_MONITOR_CONTROL_ARP_MASK;
7133641994SAndrew Lunn 	reg |= port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
7233641994SAndrew Lunn 
7333641994SAndrew Lunn 	return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
7433641994SAndrew Lunn }
7533641994SAndrew Lunn 
7633641994SAndrew Lunn static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip,
7733641994SAndrew Lunn 				      u16 pointer, u8 data)
7833641994SAndrew Lunn {
7933641994SAndrew Lunn 	u16 reg;
8033641994SAndrew Lunn 
8133641994SAndrew Lunn 	reg = GLOBAL_MONITOR_CONTROL_UPDATE | pointer | data;
8233641994SAndrew Lunn 
8333641994SAndrew Lunn 	return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
8433641994SAndrew Lunn }
8533641994SAndrew Lunn 
8633641994SAndrew Lunn int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
8733641994SAndrew Lunn {
8833641994SAndrew Lunn 	int err;
8933641994SAndrew Lunn 
9033641994SAndrew Lunn 	err = mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_INGRESS,
9133641994SAndrew Lunn 					 port);
9233641994SAndrew Lunn 	if (err)
9333641994SAndrew Lunn 		return err;
9433641994SAndrew Lunn 
9533641994SAndrew Lunn 	return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_EGRESS,
9633641994SAndrew Lunn 					  port);
9733641994SAndrew Lunn }
9833641994SAndrew Lunn 
9933641994SAndrew Lunn int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
10033641994SAndrew Lunn {
10133641994SAndrew Lunn 	return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_CPU_DEST,
10233641994SAndrew Lunn 					  port);
10333641994SAndrew Lunn }
10433641994SAndrew Lunn 
1056e55f698SAndrew Lunn int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
1066e55f698SAndrew Lunn {
1076e55f698SAndrew Lunn 	int err;
1086e55f698SAndrew Lunn 
1096e55f698SAndrew Lunn 	/* 01:c2:80:00:00:00:00-01:c2:80:00:00:00:07 are Management */
1106e55f698SAndrew Lunn 	err = mv88e6390_g1_monitor_write(
1116e55f698SAndrew Lunn 		chip, GLOBAL_MONITOR_CONTROL_0180C280000000XLO, 0xff);
1126e55f698SAndrew Lunn 	if (err)
1136e55f698SAndrew Lunn 		return err;
1146e55f698SAndrew Lunn 
1156e55f698SAndrew Lunn 	/* 01:c2:80:00:00:00:08-01:c2:80:00:00:00:0f are Management */
1166e55f698SAndrew Lunn 	err = mv88e6390_g1_monitor_write(
1176e55f698SAndrew Lunn 		chip, GLOBAL_MONITOR_CONTROL_0180C280000000XHI, 0xff);
1186e55f698SAndrew Lunn 	if (err)
1196e55f698SAndrew Lunn 		return err;
1206e55f698SAndrew Lunn 
1216e55f698SAndrew Lunn 	/* 01:c2:80:00:00:00:20-01:c2:80:00:00:00:27 are Management */
1226e55f698SAndrew Lunn 	err = mv88e6390_g1_monitor_write(
1236e55f698SAndrew Lunn 		chip, GLOBAL_MONITOR_CONTROL_0180C280000002XLO, 0xff);
1246e55f698SAndrew Lunn 	if (err)
1256e55f698SAndrew Lunn 		return err;
1266e55f698SAndrew Lunn 
1276e55f698SAndrew Lunn 	/* 01:c2:80:00:00:00:28-01:c2:80:00:00:00:2f are Management */
1286e55f698SAndrew Lunn 	return mv88e6390_g1_monitor_write(
1296e55f698SAndrew Lunn 		chip, GLOBAL_MONITOR_CONTROL_0180C280000002XHI, 0xff);
1306e55f698SAndrew Lunn }
1316e55f698SAndrew Lunn 
132de227387SAndrew Lunn /* Offset 0x1c: Global Control 2 */
133de227387SAndrew Lunn 
134de227387SAndrew Lunn int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
135de227387SAndrew Lunn {
136de227387SAndrew Lunn 	u16 val;
137de227387SAndrew Lunn 	int err;
138de227387SAndrew Lunn 
139de227387SAndrew Lunn 	err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL_2, &val);
140de227387SAndrew Lunn 	if (err)
141de227387SAndrew Lunn 		return err;
142de227387SAndrew Lunn 
143de227387SAndrew Lunn 	val |= GLOBAL_CONTROL_2_HIST_RX_TX;
144de227387SAndrew Lunn 
145de227387SAndrew Lunn 	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, val);
146de227387SAndrew Lunn 
147de227387SAndrew Lunn 	return err;
148de227387SAndrew Lunn }
149de227387SAndrew Lunn 
150de227387SAndrew Lunn /* Offset 0x1d: Statistics Operation 2 */
151de227387SAndrew Lunn 
1527f9ef3afSAndrew Lunn int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip)
153a605a0feSAndrew Lunn {
154a605a0feSAndrew Lunn 	return mv88e6xxx_g1_wait(chip, GLOBAL_STATS_OP, GLOBAL_STATS_OP_BUSY);
155a605a0feSAndrew Lunn }
156a605a0feSAndrew Lunn 
157a605a0feSAndrew Lunn int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
158a605a0feSAndrew Lunn {
159a605a0feSAndrew Lunn 	int err;
160a605a0feSAndrew Lunn 
161a605a0feSAndrew Lunn 	/* Snapshot the hardware statistics counters for this port. */
162a605a0feSAndrew Lunn 	err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
163a605a0feSAndrew Lunn 				 GLOBAL_STATS_OP_CAPTURE_PORT |
164a605a0feSAndrew Lunn 				 GLOBAL_STATS_OP_HIST_RX_TX | port);
165a605a0feSAndrew Lunn 	if (err)
166a605a0feSAndrew Lunn 		return err;
167a605a0feSAndrew Lunn 
168a605a0feSAndrew Lunn 	/* Wait for the snapshotting to complete. */
169a605a0feSAndrew Lunn 	return mv88e6xxx_g1_stats_wait(chip);
170a605a0feSAndrew Lunn }
171a605a0feSAndrew Lunn 
172a605a0feSAndrew Lunn int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
173a605a0feSAndrew Lunn {
174a605a0feSAndrew Lunn 	port = (port + 1) << 5;
175a605a0feSAndrew Lunn 
176a605a0feSAndrew Lunn 	return mv88e6xxx_g1_stats_snapshot(chip, port);
177a605a0feSAndrew Lunn }
17879523473SAndrew Lunn 
17979523473SAndrew Lunn int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
18079523473SAndrew Lunn {
18179523473SAndrew Lunn 	int err;
18279523473SAndrew Lunn 
18379523473SAndrew Lunn 	port = (port + 1) << 5;
18479523473SAndrew Lunn 
18579523473SAndrew Lunn 	/* Snapshot the hardware statistics counters for this port. */
18679523473SAndrew Lunn 	err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
18779523473SAndrew Lunn 				 GLOBAL_STATS_OP_CAPTURE_PORT | port);
18879523473SAndrew Lunn 	if (err)
18979523473SAndrew Lunn 		return err;
19079523473SAndrew Lunn 
19179523473SAndrew Lunn 	/* Wait for the snapshotting to complete. */
19279523473SAndrew Lunn 	return mv88e6xxx_g1_stats_wait(chip);
19379523473SAndrew Lunn }
1947f9ef3afSAndrew Lunn 
1957f9ef3afSAndrew Lunn void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val)
1967f9ef3afSAndrew Lunn {
1977f9ef3afSAndrew Lunn 	u32 value;
1987f9ef3afSAndrew Lunn 	u16 reg;
1997f9ef3afSAndrew Lunn 	int err;
2007f9ef3afSAndrew Lunn 
2017f9ef3afSAndrew Lunn 	*val = 0;
2027f9ef3afSAndrew Lunn 
2037f9ef3afSAndrew Lunn 	err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
2047f9ef3afSAndrew Lunn 				 GLOBAL_STATS_OP_READ_CAPTURED | stat);
2057f9ef3afSAndrew Lunn 	if (err)
2067f9ef3afSAndrew Lunn 		return;
2077f9ef3afSAndrew Lunn 
2087f9ef3afSAndrew Lunn 	err = mv88e6xxx_g1_stats_wait(chip);
2097f9ef3afSAndrew Lunn 	if (err)
2107f9ef3afSAndrew Lunn 		return;
2117f9ef3afSAndrew Lunn 
2127f9ef3afSAndrew Lunn 	err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_32, &reg);
2137f9ef3afSAndrew Lunn 	if (err)
2147f9ef3afSAndrew Lunn 		return;
2157f9ef3afSAndrew Lunn 
2167f9ef3afSAndrew Lunn 	value = reg << 16;
2177f9ef3afSAndrew Lunn 
2187f9ef3afSAndrew Lunn 	err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_01, &reg);
2197f9ef3afSAndrew Lunn 	if (err)
2207f9ef3afSAndrew Lunn 		return;
2217f9ef3afSAndrew Lunn 
2227f9ef3afSAndrew Lunn 	*val = value | reg;
2237f9ef3afSAndrew Lunn }
224