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 
105de227387SAndrew Lunn /* Offset 0x1c: Global Control 2 */
106de227387SAndrew Lunn 
107de227387SAndrew Lunn int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
108de227387SAndrew Lunn {
109de227387SAndrew Lunn 	u16 val;
110de227387SAndrew Lunn 	int err;
111de227387SAndrew Lunn 
112de227387SAndrew Lunn 	err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL_2, &val);
113de227387SAndrew Lunn 	if (err)
114de227387SAndrew Lunn 		return err;
115de227387SAndrew Lunn 
116de227387SAndrew Lunn 	val |= GLOBAL_CONTROL_2_HIST_RX_TX;
117de227387SAndrew Lunn 
118de227387SAndrew Lunn 	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, val);
119de227387SAndrew Lunn 
120de227387SAndrew Lunn 	return err;
121de227387SAndrew Lunn }
122de227387SAndrew Lunn 
123de227387SAndrew Lunn /* Offset 0x1d: Statistics Operation 2 */
124de227387SAndrew Lunn 
1257f9ef3afSAndrew Lunn int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip)
126a605a0feSAndrew Lunn {
127a605a0feSAndrew Lunn 	return mv88e6xxx_g1_wait(chip, GLOBAL_STATS_OP, GLOBAL_STATS_OP_BUSY);
128a605a0feSAndrew Lunn }
129a605a0feSAndrew Lunn 
130a605a0feSAndrew Lunn int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
131a605a0feSAndrew Lunn {
132a605a0feSAndrew Lunn 	int err;
133a605a0feSAndrew Lunn 
134a605a0feSAndrew Lunn 	/* Snapshot the hardware statistics counters for this port. */
135a605a0feSAndrew Lunn 	err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
136a605a0feSAndrew Lunn 				 GLOBAL_STATS_OP_CAPTURE_PORT |
137a605a0feSAndrew Lunn 				 GLOBAL_STATS_OP_HIST_RX_TX | port);
138a605a0feSAndrew Lunn 	if (err)
139a605a0feSAndrew Lunn 		return err;
140a605a0feSAndrew Lunn 
141a605a0feSAndrew Lunn 	/* Wait for the snapshotting to complete. */
142a605a0feSAndrew Lunn 	return mv88e6xxx_g1_stats_wait(chip);
143a605a0feSAndrew Lunn }
144a605a0feSAndrew Lunn 
145a605a0feSAndrew Lunn int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
146a605a0feSAndrew Lunn {
147a605a0feSAndrew Lunn 	port = (port + 1) << 5;
148a605a0feSAndrew Lunn 
149a605a0feSAndrew Lunn 	return mv88e6xxx_g1_stats_snapshot(chip, port);
150a605a0feSAndrew Lunn }
15179523473SAndrew Lunn 
15279523473SAndrew Lunn int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
15379523473SAndrew Lunn {
15479523473SAndrew Lunn 	int err;
15579523473SAndrew Lunn 
15679523473SAndrew Lunn 	port = (port + 1) << 5;
15779523473SAndrew Lunn 
15879523473SAndrew Lunn 	/* Snapshot the hardware statistics counters for this port. */
15979523473SAndrew Lunn 	err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
16079523473SAndrew Lunn 				 GLOBAL_STATS_OP_CAPTURE_PORT | port);
16179523473SAndrew Lunn 	if (err)
16279523473SAndrew Lunn 		return err;
16379523473SAndrew Lunn 
16479523473SAndrew Lunn 	/* Wait for the snapshotting to complete. */
16579523473SAndrew Lunn 	return mv88e6xxx_g1_stats_wait(chip);
16679523473SAndrew Lunn }
1677f9ef3afSAndrew Lunn 
1687f9ef3afSAndrew Lunn void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val)
1697f9ef3afSAndrew Lunn {
1707f9ef3afSAndrew Lunn 	u32 value;
1717f9ef3afSAndrew Lunn 	u16 reg;
1727f9ef3afSAndrew Lunn 	int err;
1737f9ef3afSAndrew Lunn 
1747f9ef3afSAndrew Lunn 	*val = 0;
1757f9ef3afSAndrew Lunn 
1767f9ef3afSAndrew Lunn 	err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
1777f9ef3afSAndrew Lunn 				 GLOBAL_STATS_OP_READ_CAPTURED | stat);
1787f9ef3afSAndrew Lunn 	if (err)
1797f9ef3afSAndrew Lunn 		return;
1807f9ef3afSAndrew Lunn 
1817f9ef3afSAndrew Lunn 	err = mv88e6xxx_g1_stats_wait(chip);
1827f9ef3afSAndrew Lunn 	if (err)
1837f9ef3afSAndrew Lunn 		return;
1847f9ef3afSAndrew Lunn 
1857f9ef3afSAndrew Lunn 	err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_32, &reg);
1867f9ef3afSAndrew Lunn 	if (err)
1877f9ef3afSAndrew Lunn 		return;
1887f9ef3afSAndrew Lunn 
1897f9ef3afSAndrew Lunn 	value = reg << 16;
1907f9ef3afSAndrew Lunn 
1917f9ef3afSAndrew Lunn 	err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_01, &reg);
1927f9ef3afSAndrew Lunn 	if (err)
1937f9ef3afSAndrew Lunn 		return;
1947f9ef3afSAndrew Lunn 
1957f9ef3afSAndrew Lunn 	*val = value | reg;
1967f9ef3afSAndrew Lunn }
197