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 0x1a: Monitor Control */
37 /* Offset 0x1a: Monitor & MGMT Control on some devices */
38 
39 int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
40 {
41 	u16 reg;
42 	int err;
43 
44 	err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, &reg);
45 	if (err)
46 		return err;
47 
48 	reg &= ~(GLOBAL_MONITOR_CONTROL_INGRESS_MASK |
49 		 GLOBAL_MONITOR_CONTROL_EGRESS_MASK);
50 
51 	reg |= port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
52 		port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT;
53 
54 	return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
55 }
56 
57 /* Older generations also call this the ARP destination. It has been
58  * generalized in more modern devices such that more than ARP can
59  * egress it
60  */
61 int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
62 {
63 	u16 reg;
64 	int err;
65 
66 	err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, &reg);
67 	if (err)
68 		return err;
69 
70 	reg &= ~GLOBAL_MONITOR_CONTROL_ARP_MASK;
71 	reg |= port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
72 
73 	return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
74 }
75 
76 static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip,
77 				      u16 pointer, u8 data)
78 {
79 	u16 reg;
80 
81 	reg = GLOBAL_MONITOR_CONTROL_UPDATE | pointer | data;
82 
83 	return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
84 }
85 
86 int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
87 {
88 	int err;
89 
90 	err = mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_INGRESS,
91 					 port);
92 	if (err)
93 		return err;
94 
95 	return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_EGRESS,
96 					  port);
97 }
98 
99 int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
100 {
101 	return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_CPU_DEST,
102 					  port);
103 }
104 
105 int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
106 {
107 	int err;
108 
109 	/* 01:c2:80:00:00:00:00-01:c2:80:00:00:00:07 are Management */
110 	err = mv88e6390_g1_monitor_write(
111 		chip, GLOBAL_MONITOR_CONTROL_0180C280000000XLO, 0xff);
112 	if (err)
113 		return err;
114 
115 	/* 01:c2:80:00:00:00:08-01:c2:80:00:00:00:0f are Management */
116 	err = mv88e6390_g1_monitor_write(
117 		chip, GLOBAL_MONITOR_CONTROL_0180C280000000XHI, 0xff);
118 	if (err)
119 		return err;
120 
121 	/* 01:c2:80:00:00:00:20-01:c2:80:00:00:00:27 are Management */
122 	err = mv88e6390_g1_monitor_write(
123 		chip, GLOBAL_MONITOR_CONTROL_0180C280000002XLO, 0xff);
124 	if (err)
125 		return err;
126 
127 	/* 01:c2:80:00:00:00:28-01:c2:80:00:00:00:2f are Management */
128 	return mv88e6390_g1_monitor_write(
129 		chip, GLOBAL_MONITOR_CONTROL_0180C280000002XHI, 0xff);
130 }
131 
132 /* Offset 0x1c: Global Control 2 */
133 
134 int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
135 {
136 	u16 val;
137 	int err;
138 
139 	err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL_2, &val);
140 	if (err)
141 		return err;
142 
143 	val |= GLOBAL_CONTROL_2_HIST_RX_TX;
144 
145 	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, val);
146 
147 	return err;
148 }
149 
150 /* Offset 0x1d: Statistics Operation 2 */
151 
152 int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip)
153 {
154 	return mv88e6xxx_g1_wait(chip, GLOBAL_STATS_OP, GLOBAL_STATS_OP_BUSY);
155 }
156 
157 int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
158 {
159 	int err;
160 
161 	/* Snapshot the hardware statistics counters for this port. */
162 	err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
163 				 GLOBAL_STATS_OP_CAPTURE_PORT |
164 				 GLOBAL_STATS_OP_HIST_RX_TX | port);
165 	if (err)
166 		return err;
167 
168 	/* Wait for the snapshotting to complete. */
169 	return mv88e6xxx_g1_stats_wait(chip);
170 }
171 
172 int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
173 {
174 	port = (port + 1) << 5;
175 
176 	return mv88e6xxx_g1_stats_snapshot(chip, port);
177 }
178 
179 int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
180 {
181 	int err;
182 
183 	port = (port + 1) << 5;
184 
185 	/* Snapshot the hardware statistics counters for this port. */
186 	err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
187 				 GLOBAL_STATS_OP_CAPTURE_PORT | port);
188 	if (err)
189 		return err;
190 
191 	/* Wait for the snapshotting to complete. */
192 	return mv88e6xxx_g1_stats_wait(chip);
193 }
194 
195 void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val)
196 {
197 	u32 value;
198 	u16 reg;
199 	int err;
200 
201 	*val = 0;
202 
203 	err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
204 				 GLOBAL_STATS_OP_READ_CAPTURED | stat);
205 	if (err)
206 		return;
207 
208 	err = mv88e6xxx_g1_stats_wait(chip);
209 	if (err)
210 		return;
211 
212 	err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_32, &reg);
213 	if (err)
214 		return;
215 
216 	value = reg << 16;
217 
218 	err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_01, &reg);
219 	if (err)
220 		return;
221 
222 	*val = value | reg;
223 }
224