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 
3617e708baSVivien Didelot /* Offset 0x00: Switch Global Status Register */
3717e708baSVivien Didelot 
38a199d8b6SVivien Didelot static int mv88e6185_g1_wait_ppu_disabled(struct mv88e6xxx_chip *chip)
39a199d8b6SVivien Didelot {
40a199d8b6SVivien Didelot 	u16 state;
41a199d8b6SVivien Didelot 	int i, err;
42a199d8b6SVivien Didelot 
43a199d8b6SVivien Didelot 	for (i = 0; i < 16; i++) {
44a199d8b6SVivien Didelot 		err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state);
45a199d8b6SVivien Didelot 		if (err)
46a199d8b6SVivien Didelot 			return err;
47a199d8b6SVivien Didelot 
48a199d8b6SVivien Didelot 		/* Check the value of the PPUState bits 15:14 */
49a199d8b6SVivien Didelot 		state &= GLOBAL_STATUS_PPU_STATE_MASK;
50a199d8b6SVivien Didelot 		if (state != GLOBAL_STATUS_PPU_STATE_POLLING)
51a199d8b6SVivien Didelot 			return 0;
52a199d8b6SVivien Didelot 
53a199d8b6SVivien Didelot 		usleep_range(1000, 2000);
54a199d8b6SVivien Didelot 	}
55a199d8b6SVivien Didelot 
56a199d8b6SVivien Didelot 	return -ETIMEDOUT;
57a199d8b6SVivien Didelot }
58a199d8b6SVivien Didelot 
5917e708baSVivien Didelot static int mv88e6185_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip)
6017e708baSVivien Didelot {
6117e708baSVivien Didelot 	u16 state;
6217e708baSVivien Didelot 	int i, err;
6317e708baSVivien Didelot 
6417e708baSVivien Didelot 	for (i = 0; i < 16; ++i) {
6517e708baSVivien Didelot 		err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state);
6617e708baSVivien Didelot 		if (err)
6717e708baSVivien Didelot 			return err;
6817e708baSVivien Didelot 
6917e708baSVivien Didelot 		/* Check the value of the PPUState bits 15:14 */
7017e708baSVivien Didelot 		state &= GLOBAL_STATUS_PPU_STATE_MASK;
7117e708baSVivien Didelot 		if (state == GLOBAL_STATUS_PPU_STATE_POLLING)
7217e708baSVivien Didelot 			return 0;
7317e708baSVivien Didelot 
7417e708baSVivien Didelot 		usleep_range(1000, 2000);
7517e708baSVivien Didelot 	}
7617e708baSVivien Didelot 
7717e708baSVivien Didelot 	return -ETIMEDOUT;
7817e708baSVivien Didelot }
7917e708baSVivien Didelot 
8017e708baSVivien Didelot static int mv88e6352_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip)
8117e708baSVivien Didelot {
8217e708baSVivien Didelot 	u16 state;
8317e708baSVivien Didelot 	int i, err;
8417e708baSVivien Didelot 
8517e708baSVivien Didelot 	for (i = 0; i < 16; ++i) {
8617e708baSVivien Didelot 		err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state);
8717e708baSVivien Didelot 		if (err)
8817e708baSVivien Didelot 			return err;
8917e708baSVivien Didelot 
9017e708baSVivien Didelot 		/* Check the value of the PPUState (or InitState) bit 15 */
9117e708baSVivien Didelot 		if (state & GLOBAL_STATUS_PPU_STATE)
9217e708baSVivien Didelot 			return 0;
9317e708baSVivien Didelot 
9417e708baSVivien Didelot 		usleep_range(1000, 2000);
9517e708baSVivien Didelot 	}
9617e708baSVivien Didelot 
9717e708baSVivien Didelot 	return -ETIMEDOUT;
9817e708baSVivien Didelot }
9917e708baSVivien Didelot 
10017e708baSVivien Didelot static int mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip *chip)
10117e708baSVivien Didelot {
10217e708baSVivien Didelot 	const unsigned long timeout = jiffies + 1 * HZ;
10317e708baSVivien Didelot 	u16 val;
10417e708baSVivien Didelot 	int err;
10517e708baSVivien Didelot 
10617e708baSVivien Didelot 	/* Wait up to 1 second for the switch to be ready. The InitReady bit 11
10717e708baSVivien Didelot 	 * is set to a one when all units inside the device (ATU, VTU, etc.)
10817e708baSVivien Didelot 	 * have finished their initialization and are ready to accept frames.
10917e708baSVivien Didelot 	 */
11017e708baSVivien Didelot 	while (time_before(jiffies, timeout)) {
11117e708baSVivien Didelot 		err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &val);
11217e708baSVivien Didelot 		if (err)
11317e708baSVivien Didelot 			return err;
11417e708baSVivien Didelot 
11517e708baSVivien Didelot 		if (val & GLOBAL_STATUS_INIT_READY)
11617e708baSVivien Didelot 			break;
11717e708baSVivien Didelot 
11817e708baSVivien Didelot 		usleep_range(1000, 2000);
11917e708baSVivien Didelot 	}
12017e708baSVivien Didelot 
12117e708baSVivien Didelot 	if (time_after(jiffies, timeout))
12217e708baSVivien Didelot 		return -ETIMEDOUT;
12317e708baSVivien Didelot 
12417e708baSVivien Didelot 	return 0;
12517e708baSVivien Didelot }
12617e708baSVivien Didelot 
12717e708baSVivien Didelot /* Offset 0x04: Switch Global Control Register */
12817e708baSVivien Didelot 
12917e708baSVivien Didelot int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip)
13017e708baSVivien Didelot {
13117e708baSVivien Didelot 	u16 val;
13217e708baSVivien Didelot 	int err;
13317e708baSVivien Didelot 
13417e708baSVivien Didelot 	/* Set the SWReset bit 15 along with the PPUEn bit 14, to also restart
13517e708baSVivien Didelot 	 * the PPU, including re-doing PHY detection and initialization
13617e708baSVivien Didelot 	 */
13717e708baSVivien Didelot 	err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
13817e708baSVivien Didelot 	if (err)
13917e708baSVivien Didelot 		return err;
14017e708baSVivien Didelot 
14117e708baSVivien Didelot 	val |= GLOBAL_CONTROL_SW_RESET;
14217e708baSVivien Didelot 	val |= GLOBAL_CONTROL_PPU_ENABLE;
14317e708baSVivien Didelot 
14417e708baSVivien Didelot 	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
14517e708baSVivien Didelot 	if (err)
14617e708baSVivien Didelot 		return err;
14717e708baSVivien Didelot 
14817e708baSVivien Didelot 	err = mv88e6xxx_g1_wait_init_ready(chip);
14917e708baSVivien Didelot 	if (err)
15017e708baSVivien Didelot 		return err;
15117e708baSVivien Didelot 
15217e708baSVivien Didelot 	return mv88e6185_g1_wait_ppu_polling(chip);
15317e708baSVivien Didelot }
15417e708baSVivien Didelot 
15517e708baSVivien Didelot int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip)
15617e708baSVivien Didelot {
15717e708baSVivien Didelot 	u16 val;
15817e708baSVivien Didelot 	int err;
15917e708baSVivien Didelot 
16017e708baSVivien Didelot 	/* Set the SWReset bit 15 */
16117e708baSVivien Didelot 	err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
16217e708baSVivien Didelot 	if (err)
16317e708baSVivien Didelot 		return err;
16417e708baSVivien Didelot 
16517e708baSVivien Didelot 	val |= GLOBAL_CONTROL_SW_RESET;
16617e708baSVivien Didelot 
16717e708baSVivien Didelot 	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
16817e708baSVivien Didelot 	if (err)
16917e708baSVivien Didelot 		return err;
17017e708baSVivien Didelot 
17117e708baSVivien Didelot 	err = mv88e6xxx_g1_wait_init_ready(chip);
17217e708baSVivien Didelot 	if (err)
17317e708baSVivien Didelot 		return err;
17417e708baSVivien Didelot 
17517e708baSVivien Didelot 	return mv88e6352_g1_wait_ppu_polling(chip);
17617e708baSVivien Didelot }
17717e708baSVivien Didelot 
178a199d8b6SVivien Didelot int mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip)
179a199d8b6SVivien Didelot {
180a199d8b6SVivien Didelot 	u16 val;
181a199d8b6SVivien Didelot 	int err;
182a199d8b6SVivien Didelot 
183a199d8b6SVivien Didelot 	err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
184a199d8b6SVivien Didelot 	if (err)
185a199d8b6SVivien Didelot 		return err;
186a199d8b6SVivien Didelot 
187a199d8b6SVivien Didelot 	val |= GLOBAL_CONTROL_PPU_ENABLE;
188a199d8b6SVivien Didelot 
189a199d8b6SVivien Didelot 	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
190a199d8b6SVivien Didelot 	if (err)
191a199d8b6SVivien Didelot 		return err;
192a199d8b6SVivien Didelot 
193a199d8b6SVivien Didelot 	return mv88e6185_g1_wait_ppu_polling(chip);
194a199d8b6SVivien Didelot }
195a199d8b6SVivien Didelot 
196a199d8b6SVivien Didelot int mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip *chip)
197a199d8b6SVivien Didelot {
198a199d8b6SVivien Didelot 	u16 val;
199a199d8b6SVivien Didelot 	int err;
200a199d8b6SVivien Didelot 
201a199d8b6SVivien Didelot 	err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
202a199d8b6SVivien Didelot 	if (err)
203a199d8b6SVivien Didelot 		return err;
204a199d8b6SVivien Didelot 
205a199d8b6SVivien Didelot 	val &= ~GLOBAL_CONTROL_PPU_ENABLE;
206a199d8b6SVivien Didelot 
207a199d8b6SVivien Didelot 	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
208a199d8b6SVivien Didelot 	if (err)
209a199d8b6SVivien Didelot 		return err;
210a199d8b6SVivien Didelot 
211a199d8b6SVivien Didelot 	return mv88e6185_g1_wait_ppu_disabled(chip);
212a199d8b6SVivien Didelot }
213a199d8b6SVivien Didelot 
21433641994SAndrew Lunn /* Offset 0x1a: Monitor Control */
21533641994SAndrew Lunn /* Offset 0x1a: Monitor & MGMT Control on some devices */
21633641994SAndrew Lunn 
21733641994SAndrew Lunn int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
21833641994SAndrew Lunn {
21933641994SAndrew Lunn 	u16 reg;
22033641994SAndrew Lunn 	int err;
22133641994SAndrew Lunn 
22233641994SAndrew Lunn 	err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, &reg);
22333641994SAndrew Lunn 	if (err)
22433641994SAndrew Lunn 		return err;
22533641994SAndrew Lunn 
22633641994SAndrew Lunn 	reg &= ~(GLOBAL_MONITOR_CONTROL_INGRESS_MASK |
22733641994SAndrew Lunn 		 GLOBAL_MONITOR_CONTROL_EGRESS_MASK);
22833641994SAndrew Lunn 
22933641994SAndrew Lunn 	reg |= port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
23033641994SAndrew Lunn 		port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT;
23133641994SAndrew Lunn 
23233641994SAndrew Lunn 	return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
23333641994SAndrew Lunn }
23433641994SAndrew Lunn 
23533641994SAndrew Lunn /* Older generations also call this the ARP destination. It has been
23633641994SAndrew Lunn  * generalized in more modern devices such that more than ARP can
23733641994SAndrew Lunn  * egress it
23833641994SAndrew Lunn  */
23933641994SAndrew Lunn int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
24033641994SAndrew Lunn {
24133641994SAndrew Lunn 	u16 reg;
24233641994SAndrew Lunn 	int err;
24333641994SAndrew Lunn 
24433641994SAndrew Lunn 	err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, &reg);
24533641994SAndrew Lunn 	if (err)
24633641994SAndrew Lunn 		return err;
24733641994SAndrew Lunn 
24833641994SAndrew Lunn 	reg &= ~GLOBAL_MONITOR_CONTROL_ARP_MASK;
24933641994SAndrew Lunn 	reg |= port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
25033641994SAndrew Lunn 
25133641994SAndrew Lunn 	return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
25233641994SAndrew Lunn }
25333641994SAndrew Lunn 
25433641994SAndrew Lunn static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip,
25533641994SAndrew Lunn 				      u16 pointer, u8 data)
25633641994SAndrew Lunn {
25733641994SAndrew Lunn 	u16 reg;
25833641994SAndrew Lunn 
25933641994SAndrew Lunn 	reg = GLOBAL_MONITOR_CONTROL_UPDATE | pointer | data;
26033641994SAndrew Lunn 
26133641994SAndrew Lunn 	return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
26233641994SAndrew Lunn }
26333641994SAndrew Lunn 
26433641994SAndrew Lunn int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
26533641994SAndrew Lunn {
26633641994SAndrew Lunn 	int err;
26733641994SAndrew Lunn 
26833641994SAndrew Lunn 	err = mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_INGRESS,
26933641994SAndrew Lunn 					 port);
27033641994SAndrew Lunn 	if (err)
27133641994SAndrew Lunn 		return err;
27233641994SAndrew Lunn 
27333641994SAndrew Lunn 	return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_EGRESS,
27433641994SAndrew Lunn 					  port);
27533641994SAndrew Lunn }
27633641994SAndrew Lunn 
27733641994SAndrew Lunn int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
27833641994SAndrew Lunn {
27933641994SAndrew Lunn 	return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_CPU_DEST,
28033641994SAndrew Lunn 					  port);
28133641994SAndrew Lunn }
28233641994SAndrew Lunn 
2836e55f698SAndrew Lunn int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
2846e55f698SAndrew Lunn {
2856e55f698SAndrew Lunn 	int err;
2866e55f698SAndrew Lunn 
2876e55f698SAndrew Lunn 	/* 01:c2:80:00:00:00:00-01:c2:80:00:00:00:07 are Management */
2886e55f698SAndrew Lunn 	err = mv88e6390_g1_monitor_write(
2896e55f698SAndrew Lunn 		chip, GLOBAL_MONITOR_CONTROL_0180C280000000XLO, 0xff);
2906e55f698SAndrew Lunn 	if (err)
2916e55f698SAndrew Lunn 		return err;
2926e55f698SAndrew Lunn 
2936e55f698SAndrew Lunn 	/* 01:c2:80:00:00:00:08-01:c2:80:00:00:00:0f are Management */
2946e55f698SAndrew Lunn 	err = mv88e6390_g1_monitor_write(
2956e55f698SAndrew Lunn 		chip, GLOBAL_MONITOR_CONTROL_0180C280000000XHI, 0xff);
2966e55f698SAndrew Lunn 	if (err)
2976e55f698SAndrew Lunn 		return err;
2986e55f698SAndrew Lunn 
2996e55f698SAndrew Lunn 	/* 01:c2:80:00:00:00:20-01:c2:80:00:00:00:27 are Management */
3006e55f698SAndrew Lunn 	err = mv88e6390_g1_monitor_write(
3016e55f698SAndrew Lunn 		chip, GLOBAL_MONITOR_CONTROL_0180C280000002XLO, 0xff);
3026e55f698SAndrew Lunn 	if (err)
3036e55f698SAndrew Lunn 		return err;
3046e55f698SAndrew Lunn 
3056e55f698SAndrew Lunn 	/* 01:c2:80:00:00:00:28-01:c2:80:00:00:00:2f are Management */
3066e55f698SAndrew Lunn 	return mv88e6390_g1_monitor_write(
3076e55f698SAndrew Lunn 		chip, GLOBAL_MONITOR_CONTROL_0180C280000002XHI, 0xff);
3086e55f698SAndrew Lunn }
3096e55f698SAndrew Lunn 
310de227387SAndrew Lunn /* Offset 0x1c: Global Control 2 */
311de227387SAndrew Lunn 
312de227387SAndrew Lunn int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
313de227387SAndrew Lunn {
314de227387SAndrew Lunn 	u16 val;
315de227387SAndrew Lunn 	int err;
316de227387SAndrew Lunn 
317de227387SAndrew Lunn 	err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL_2, &val);
318de227387SAndrew Lunn 	if (err)
319de227387SAndrew Lunn 		return err;
320de227387SAndrew Lunn 
321de227387SAndrew Lunn 	val |= GLOBAL_CONTROL_2_HIST_RX_TX;
322de227387SAndrew Lunn 
323de227387SAndrew Lunn 	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, val);
324de227387SAndrew Lunn 
325de227387SAndrew Lunn 	return err;
326de227387SAndrew Lunn }
327de227387SAndrew Lunn 
328de227387SAndrew Lunn /* Offset 0x1d: Statistics Operation 2 */
329de227387SAndrew Lunn 
3307f9ef3afSAndrew Lunn int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip)
331a605a0feSAndrew Lunn {
332a605a0feSAndrew Lunn 	return mv88e6xxx_g1_wait(chip, GLOBAL_STATS_OP, GLOBAL_STATS_OP_BUSY);
333a605a0feSAndrew Lunn }
334a605a0feSAndrew Lunn 
335a605a0feSAndrew Lunn int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
336a605a0feSAndrew Lunn {
337a605a0feSAndrew Lunn 	int err;
338a605a0feSAndrew Lunn 
339a605a0feSAndrew Lunn 	/* Snapshot the hardware statistics counters for this port. */
340a605a0feSAndrew Lunn 	err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
341a605a0feSAndrew Lunn 				 GLOBAL_STATS_OP_CAPTURE_PORT |
342a605a0feSAndrew Lunn 				 GLOBAL_STATS_OP_HIST_RX_TX | port);
343a605a0feSAndrew Lunn 	if (err)
344a605a0feSAndrew Lunn 		return err;
345a605a0feSAndrew Lunn 
346a605a0feSAndrew Lunn 	/* Wait for the snapshotting to complete. */
347a605a0feSAndrew Lunn 	return mv88e6xxx_g1_stats_wait(chip);
348a605a0feSAndrew Lunn }
349a605a0feSAndrew Lunn 
350a605a0feSAndrew Lunn int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
351a605a0feSAndrew Lunn {
352a605a0feSAndrew Lunn 	port = (port + 1) << 5;
353a605a0feSAndrew Lunn 
354a605a0feSAndrew Lunn 	return mv88e6xxx_g1_stats_snapshot(chip, port);
355a605a0feSAndrew Lunn }
35679523473SAndrew Lunn 
35779523473SAndrew Lunn int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
35879523473SAndrew Lunn {
35979523473SAndrew Lunn 	int err;
36079523473SAndrew Lunn 
36179523473SAndrew Lunn 	port = (port + 1) << 5;
36279523473SAndrew Lunn 
36379523473SAndrew Lunn 	/* Snapshot the hardware statistics counters for this port. */
36479523473SAndrew Lunn 	err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
36579523473SAndrew Lunn 				 GLOBAL_STATS_OP_CAPTURE_PORT | port);
36679523473SAndrew Lunn 	if (err)
36779523473SAndrew Lunn 		return err;
36879523473SAndrew Lunn 
36979523473SAndrew Lunn 	/* Wait for the snapshotting to complete. */
37079523473SAndrew Lunn 	return mv88e6xxx_g1_stats_wait(chip);
37179523473SAndrew Lunn }
3727f9ef3afSAndrew Lunn 
3737f9ef3afSAndrew Lunn void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val)
3747f9ef3afSAndrew Lunn {
3757f9ef3afSAndrew Lunn 	u32 value;
3767f9ef3afSAndrew Lunn 	u16 reg;
3777f9ef3afSAndrew Lunn 	int err;
3787f9ef3afSAndrew Lunn 
3797f9ef3afSAndrew Lunn 	*val = 0;
3807f9ef3afSAndrew Lunn 
3817f9ef3afSAndrew Lunn 	err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
3827f9ef3afSAndrew Lunn 				 GLOBAL_STATS_OP_READ_CAPTURED | stat);
3837f9ef3afSAndrew Lunn 	if (err)
3847f9ef3afSAndrew Lunn 		return;
3857f9ef3afSAndrew Lunn 
3867f9ef3afSAndrew Lunn 	err = mv88e6xxx_g1_stats_wait(chip);
3877f9ef3afSAndrew Lunn 	if (err)
3887f9ef3afSAndrew Lunn 		return;
3897f9ef3afSAndrew Lunn 
3907f9ef3afSAndrew Lunn 	err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_32, &reg);
3917f9ef3afSAndrew Lunn 	if (err)
3927f9ef3afSAndrew Lunn 		return;
3937f9ef3afSAndrew Lunn 
3947f9ef3afSAndrew Lunn 	value = reg << 16;
3957f9ef3afSAndrew Lunn 
3967f9ef3afSAndrew Lunn 	err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_01, &reg);
3977f9ef3afSAndrew Lunn 	if (err)
3987f9ef3afSAndrew Lunn 		return;
3997f9ef3afSAndrew Lunn 
4007f9ef3afSAndrew Lunn 	*val = value | reg;
4017f9ef3afSAndrew Lunn }
402