12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2a935c052SVivien Didelot /*
3a935c052SVivien Didelot  * Marvell 88E6xxx Switch Global (1) Registers support
4a935c052SVivien Didelot  *
5a935c052SVivien Didelot  * Copyright (c) 2008 Marvell Semiconductor
6a935c052SVivien Didelot  *
74333d619SVivien Didelot  * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
84333d619SVivien Didelot  *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
9a935c052SVivien Didelot  */
10a935c052SVivien Didelot 
11101515c8SVivien Didelot #include <linux/bitfield.h>
12101515c8SVivien Didelot 
134d5f2ba7SVivien Didelot #include "chip.h"
14a935c052SVivien Didelot #include "global1.h"
15a935c052SVivien Didelot 
mv88e6xxx_g1_read(struct mv88e6xxx_chip * chip,int reg,u16 * val)16a935c052SVivien Didelot int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
17a935c052SVivien Didelot {
18a935c052SVivien Didelot 	int addr = chip->info->global1_addr;
19a935c052SVivien Didelot 
20a935c052SVivien Didelot 	return mv88e6xxx_read(chip, addr, reg, val);
21a935c052SVivien Didelot }
22a935c052SVivien Didelot 
mv88e6xxx_g1_write(struct mv88e6xxx_chip * chip,int reg,u16 val)23a935c052SVivien Didelot int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
24a935c052SVivien Didelot {
25a935c052SVivien Didelot 	int addr = chip->info->global1_addr;
26a935c052SVivien Didelot 
27a935c052SVivien Didelot 	return mv88e6xxx_write(chip, addr, reg, val);
28a935c052SVivien Didelot }
29a935c052SVivien Didelot 
mv88e6xxx_g1_wait_bit(struct mv88e6xxx_chip * chip,int reg,int bit,int val)3019fb7f69SVivien Didelot int mv88e6xxx_g1_wait_bit(struct mv88e6xxx_chip *chip, int reg, int
3119fb7f69SVivien Didelot 			  bit, int val)
3219fb7f69SVivien Didelot {
3319fb7f69SVivien Didelot 	return mv88e6xxx_wait_bit(chip, chip->info->global1_addr, reg,
3419fb7f69SVivien Didelot 				  bit, val);
3519fb7f69SVivien Didelot }
3619fb7f69SVivien Didelot 
mv88e6xxx_g1_wait_mask(struct mv88e6xxx_chip * chip,int reg,u16 mask,u16 val)37683f2244SVivien Didelot int mv88e6xxx_g1_wait_mask(struct mv88e6xxx_chip *chip, int reg,
38683f2244SVivien Didelot 			   u16 mask, u16 val)
39683f2244SVivien Didelot {
40683f2244SVivien Didelot 	return mv88e6xxx_wait_mask(chip, chip->info->global1_addr, reg,
41683f2244SVivien Didelot 				   mask, val);
42683f2244SVivien Didelot }
43683f2244SVivien Didelot 
4417e708baSVivien Didelot /* Offset 0x00: Switch Global Status Register */
4517e708baSVivien Didelot 
mv88e6185_g1_wait_ppu_disabled(struct mv88e6xxx_chip * chip)46a199d8b6SVivien Didelot static int mv88e6185_g1_wait_ppu_disabled(struct mv88e6xxx_chip *chip)
47a199d8b6SVivien Didelot {
48683f2244SVivien Didelot 	return mv88e6xxx_g1_wait_mask(chip, MV88E6XXX_G1_STS,
49683f2244SVivien Didelot 				      MV88E6185_G1_STS_PPU_STATE_MASK,
50683f2244SVivien Didelot 				      MV88E6185_G1_STS_PPU_STATE_DISABLED);
51a199d8b6SVivien Didelot }
52a199d8b6SVivien Didelot 
mv88e6185_g1_wait_ppu_polling(struct mv88e6xxx_chip * chip)5317e708baSVivien Didelot static int mv88e6185_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip)
5417e708baSVivien Didelot {
55683f2244SVivien Didelot 	return mv88e6xxx_g1_wait_mask(chip, MV88E6XXX_G1_STS,
56683f2244SVivien Didelot 				      MV88E6185_G1_STS_PPU_STATE_MASK,
57683f2244SVivien Didelot 				      MV88E6185_G1_STS_PPU_STATE_POLLING);
5817e708baSVivien Didelot }
5917e708baSVivien Didelot 
mv88e6352_g1_wait_ppu_polling(struct mv88e6xxx_chip * chip)6017e708baSVivien Didelot static int mv88e6352_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip)
6117e708baSVivien Didelot {
6219fb7f69SVivien Didelot 	int bit = __bf_shf(MV88E6352_G1_STS_PPU_STATE);
6317e708baSVivien Didelot 
6419fb7f69SVivien Didelot 	return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_STS, bit, 1);
6517e708baSVivien Didelot }
6617e708baSVivien Didelot 
mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip * chip)6717e708baSVivien Didelot static int mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip *chip)
6817e708baSVivien Didelot {
6919fb7f69SVivien Didelot 	int bit = __bf_shf(MV88E6XXX_G1_STS_INIT_READY);
7017e708baSVivien Didelot 
7117e708baSVivien Didelot 	/* Wait up to 1 second for the switch to be ready. The InitReady bit 11
7217e708baSVivien Didelot 	 * is set to a one when all units inside the device (ATU, VTU, etc.)
7317e708baSVivien Didelot 	 * have finished their initialization and are ready to accept frames.
7417e708baSVivien Didelot 	 */
7519fb7f69SVivien Didelot 	return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_STS, bit, 1);
7617e708baSVivien Didelot }
7717e708baSVivien Didelot 
mv88e6250_g1_eeprom_reload(struct mv88e6xxx_chip * chip)78a4702791SMatthias Schiffer static int mv88e6250_g1_eeprom_reload(struct mv88e6xxx_chip *chip)
79a4702791SMatthias Schiffer {
80a4702791SMatthias Schiffer 	/* MV88E6185_G1_CTL1_RELOAD_EEPROM is also valid for 88E6250 */
81a4702791SMatthias Schiffer 	int bit = __bf_shf(MV88E6185_G1_CTL1_RELOAD_EEPROM);
82a4702791SMatthias Schiffer 	u16 val;
83a4702791SMatthias Schiffer 	int err;
84a4702791SMatthias Schiffer 
85a4702791SMatthias Schiffer 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val);
86a4702791SMatthias Schiffer 	if (err)
87a4702791SMatthias Schiffer 		return err;
88a4702791SMatthias Schiffer 
89a4702791SMatthias Schiffer 	val |= MV88E6185_G1_CTL1_RELOAD_EEPROM;
90a4702791SMatthias Schiffer 
91a4702791SMatthias Schiffer 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val);
92a4702791SMatthias Schiffer 	if (err)
93a4702791SMatthias Schiffer 		return err;
94a4702791SMatthias Schiffer 
95a4702791SMatthias Schiffer 	return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_CTL1, bit, 0);
96a4702791SMatthias Schiffer }
97a4702791SMatthias Schiffer 
98a4702791SMatthias Schiffer /* Returns 0 when done, -EBUSY when waiting, other negative codes on error */
mv88e6xxx_g1_is_eeprom_done(struct mv88e6xxx_chip * chip)99a4702791SMatthias Schiffer static int mv88e6xxx_g1_is_eeprom_done(struct mv88e6xxx_chip *chip)
100a4702791SMatthias Schiffer {
101a4702791SMatthias Schiffer 	u16 val;
102a4702791SMatthias Schiffer 	int err;
103a4702791SMatthias Schiffer 
104a4702791SMatthias Schiffer 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &val);
105a4702791SMatthias Schiffer 	if (err < 0) {
106a4702791SMatthias Schiffer 		dev_err(chip->dev, "Error reading status");
107a4702791SMatthias Schiffer 		return err;
108a4702791SMatthias Schiffer 	}
109a4702791SMatthias Schiffer 
110a4702791SMatthias Schiffer 	/* If the switch is still resetting, it may not
111a4702791SMatthias Schiffer 	 * respond on the bus, and so MDIO read returns
112a4702791SMatthias Schiffer 	 * 0xffff. Differentiate between that, and waiting for
113a4702791SMatthias Schiffer 	 * the EEPROM to be done by bit 0 being set.
114a4702791SMatthias Schiffer 	 */
115a4702791SMatthias Schiffer 	if (val == 0xffff || !(val & BIT(MV88E6XXX_G1_STS_IRQ_EEPROM_DONE)))
116a4702791SMatthias Schiffer 		return -EBUSY;
117a4702791SMatthias Schiffer 
118a4702791SMatthias Schiffer 	return 0;
119a4702791SMatthias Schiffer }
120a4702791SMatthias Schiffer 
121a4702791SMatthias Schiffer /* As the EEInt (EEPROM done) flag clears on read if the status register, this
122a4702791SMatthias Schiffer  * function must be called directly after a hard reset or EEPROM ReLoad request,
123a4702791SMatthias Schiffer  * or the done condition may have been missed
124a4702791SMatthias Schiffer  */
mv88e6xxx_g1_wait_eeprom_done(struct mv88e6xxx_chip * chip)125a4702791SMatthias Schiffer int mv88e6xxx_g1_wait_eeprom_done(struct mv88e6xxx_chip *chip)
126a4702791SMatthias Schiffer {
127a4702791SMatthias Schiffer 	const unsigned long timeout = jiffies + 1 * HZ;
128a4702791SMatthias Schiffer 	int ret;
129a4702791SMatthias Schiffer 
130a4702791SMatthias Schiffer 	/* Wait up to 1 second for the switch to finish reading the
131a4702791SMatthias Schiffer 	 * EEPROM.
132a4702791SMatthias Schiffer 	 */
133a4702791SMatthias Schiffer 	while (time_before(jiffies, timeout)) {
134a4702791SMatthias Schiffer 		ret = mv88e6xxx_g1_is_eeprom_done(chip);
135a4702791SMatthias Schiffer 		if (ret != -EBUSY)
136a4702791SMatthias Schiffer 			return ret;
137a4702791SMatthias Schiffer 	}
138a4702791SMatthias Schiffer 
139a4702791SMatthias Schiffer 	dev_err(chip->dev, "Timeout waiting for EEPROM done");
140a4702791SMatthias Schiffer 	return -ETIMEDOUT;
141a4702791SMatthias Schiffer }
142a4702791SMatthias Schiffer 
mv88e6250_g1_wait_eeprom_done_prereset(struct mv88e6xxx_chip * chip)143a4702791SMatthias Schiffer int mv88e6250_g1_wait_eeprom_done_prereset(struct mv88e6xxx_chip *chip)
144a4702791SMatthias Schiffer {
145a4702791SMatthias Schiffer 	int ret;
146a4702791SMatthias Schiffer 
147a4702791SMatthias Schiffer 	ret = mv88e6xxx_g1_is_eeprom_done(chip);
148a4702791SMatthias Schiffer 	if (ret != -EBUSY)
149a4702791SMatthias Schiffer 		return ret;
150a4702791SMatthias Schiffer 
151a4702791SMatthias Schiffer 	/* Pre-reset, we don't know the state of the switch - when
152a4702791SMatthias Schiffer 	 * mv88e6xxx_g1_is_eeprom_done() returns -EBUSY, that may be because
153a4702791SMatthias Schiffer 	 * the switch is actually busy reading the EEPROM, or because
154a4702791SMatthias Schiffer 	 * MV88E6XXX_G1_STS_IRQ_EEPROM_DONE has been cleared by an unrelated
155a4702791SMatthias Schiffer 	 * status register read already.
156a4702791SMatthias Schiffer 	 *
157a4702791SMatthias Schiffer 	 * To account for the latter case, trigger another EEPROM reload for
158a4702791SMatthias Schiffer 	 * another chance at seeing the done flag.
159a4702791SMatthias Schiffer 	 */
160a4702791SMatthias Schiffer 	ret = mv88e6250_g1_eeprom_reload(chip);
161a4702791SMatthias Schiffer 	if (ret)
162a4702791SMatthias Schiffer 		return ret;
163a4702791SMatthias Schiffer 
164a4702791SMatthias Schiffer 	return mv88e6xxx_g1_wait_eeprom_done(chip);
165a4702791SMatthias Schiffer }
166a4702791SMatthias Schiffer 
1674b0c4817SVivien Didelot /* Offset 0x01: Switch MAC Address Register Bytes 0 & 1
1684b0c4817SVivien Didelot  * Offset 0x02: Switch MAC Address Register Bytes 2 & 3
1694b0c4817SVivien Didelot  * Offset 0x03: Switch MAC Address Register Bytes 4 & 5
1704b0c4817SVivien Didelot  */
mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip * chip,u8 * addr)1714b0c4817SVivien Didelot int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr)
1724b0c4817SVivien Didelot {
1734b0c4817SVivien Didelot 	u16 reg;
1744b0c4817SVivien Didelot 	int err;
1754b0c4817SVivien Didelot 
1764b0c4817SVivien Didelot 	reg = (addr[0] << 8) | addr[1];
1774b0c4817SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_MAC_01, reg);
1784b0c4817SVivien Didelot 	if (err)
1794b0c4817SVivien Didelot 		return err;
1804b0c4817SVivien Didelot 
1814b0c4817SVivien Didelot 	reg = (addr[2] << 8) | addr[3];
1824b0c4817SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_MAC_23, reg);
1834b0c4817SVivien Didelot 	if (err)
1844b0c4817SVivien Didelot 		return err;
1854b0c4817SVivien Didelot 
1864b0c4817SVivien Didelot 	reg = (addr[4] << 8) | addr[5];
1874b0c4817SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_MAC_45, reg);
1884b0c4817SVivien Didelot 	if (err)
1894b0c4817SVivien Didelot 		return err;
1904b0c4817SVivien Didelot 
1914b0c4817SVivien Didelot 	return 0;
1924b0c4817SVivien Didelot }
1934b0c4817SVivien Didelot 
19417e708baSVivien Didelot /* Offset 0x04: Switch Global Control Register */
19517e708baSVivien Didelot 
mv88e6185_g1_reset(struct mv88e6xxx_chip * chip)19617e708baSVivien Didelot int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip)
19717e708baSVivien Didelot {
19817e708baSVivien Didelot 	u16 val;
19917e708baSVivien Didelot 	int err;
20017e708baSVivien Didelot 
20117e708baSVivien Didelot 	/* Set the SWReset bit 15 along with the PPUEn bit 14, to also restart
20217e708baSVivien Didelot 	 * the PPU, including re-doing PHY detection and initialization
20317e708baSVivien Didelot 	 */
204d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val);
20517e708baSVivien Didelot 	if (err)
20617e708baSVivien Didelot 		return err;
20717e708baSVivien Didelot 
208d77f4321SVivien Didelot 	val |= MV88E6XXX_G1_CTL1_SW_RESET;
209d77f4321SVivien Didelot 	val |= MV88E6XXX_G1_CTL1_PPU_ENABLE;
21017e708baSVivien Didelot 
211d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val);
21217e708baSVivien Didelot 	if (err)
21317e708baSVivien Didelot 		return err;
21417e708baSVivien Didelot 
21517e708baSVivien Didelot 	err = mv88e6xxx_g1_wait_init_ready(chip);
21617e708baSVivien Didelot 	if (err)
21717e708baSVivien Didelot 		return err;
21817e708baSVivien Didelot 
21917e708baSVivien Didelot 	return mv88e6185_g1_wait_ppu_polling(chip);
22017e708baSVivien Didelot }
22117e708baSVivien Didelot 
mv88e6250_g1_reset(struct mv88e6xxx_chip * chip)2221f71836fSRasmus Villemoes int mv88e6250_g1_reset(struct mv88e6xxx_chip *chip)
2231f71836fSRasmus Villemoes {
2241f71836fSRasmus Villemoes 	u16 val;
2251f71836fSRasmus Villemoes 	int err;
2261f71836fSRasmus Villemoes 
2271f71836fSRasmus Villemoes 	/* Set the SWReset bit 15 */
2281f71836fSRasmus Villemoes 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val);
2291f71836fSRasmus Villemoes 	if (err)
2301f71836fSRasmus Villemoes 		return err;
2311f71836fSRasmus Villemoes 
2321f71836fSRasmus Villemoes 	val |= MV88E6XXX_G1_CTL1_SW_RESET;
2331f71836fSRasmus Villemoes 
2341f71836fSRasmus Villemoes 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val);
2351f71836fSRasmus Villemoes 	if (err)
2361f71836fSRasmus Villemoes 		return err;
2371f71836fSRasmus Villemoes 
2381f71836fSRasmus Villemoes 	return mv88e6xxx_g1_wait_init_ready(chip);
2391f71836fSRasmus Villemoes }
2401f71836fSRasmus Villemoes 
mv88e6352_g1_reset(struct mv88e6xxx_chip * chip)24117e708baSVivien Didelot int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip)
24217e708baSVivien Didelot {
24317e708baSVivien Didelot 	int err;
24417e708baSVivien Didelot 
2457358fd80SRasmus Villemoes 	err = mv88e6250_g1_reset(chip);
24617e708baSVivien Didelot 	if (err)
24717e708baSVivien Didelot 		return err;
24817e708baSVivien Didelot 
24917e708baSVivien Didelot 	return mv88e6352_g1_wait_ppu_polling(chip);
25017e708baSVivien Didelot }
25117e708baSVivien Didelot 
mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip * chip)252a199d8b6SVivien Didelot int mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip)
253a199d8b6SVivien Didelot {
254a199d8b6SVivien Didelot 	u16 val;
255a199d8b6SVivien Didelot 	int err;
256a199d8b6SVivien Didelot 
257d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val);
258a199d8b6SVivien Didelot 	if (err)
259a199d8b6SVivien Didelot 		return err;
260a199d8b6SVivien Didelot 
261d77f4321SVivien Didelot 	val |= MV88E6XXX_G1_CTL1_PPU_ENABLE;
262a199d8b6SVivien Didelot 
263d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val);
264a199d8b6SVivien Didelot 	if (err)
265a199d8b6SVivien Didelot 		return err;
266a199d8b6SVivien Didelot 
267a199d8b6SVivien Didelot 	return mv88e6185_g1_wait_ppu_polling(chip);
268a199d8b6SVivien Didelot }
269a199d8b6SVivien Didelot 
mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip * chip)270a199d8b6SVivien Didelot int mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip *chip)
271a199d8b6SVivien Didelot {
272a199d8b6SVivien Didelot 	u16 val;
273a199d8b6SVivien Didelot 	int err;
274a199d8b6SVivien Didelot 
275d77f4321SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val);
276a199d8b6SVivien Didelot 	if (err)
277a199d8b6SVivien Didelot 		return err;
278a199d8b6SVivien Didelot 
279d77f4321SVivien Didelot 	val &= ~MV88E6XXX_G1_CTL1_PPU_ENABLE;
280a199d8b6SVivien Didelot 
281d77f4321SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val);
282a199d8b6SVivien Didelot 	if (err)
283a199d8b6SVivien Didelot 		return err;
284a199d8b6SVivien Didelot 
285a199d8b6SVivien Didelot 	return mv88e6185_g1_wait_ppu_disabled(chip);
286a199d8b6SVivien Didelot }
287a199d8b6SVivien Didelot 
mv88e6185_g1_set_max_frame_size(struct mv88e6xxx_chip * chip,int mtu)2881baf0facSChris Packham int mv88e6185_g1_set_max_frame_size(struct mv88e6xxx_chip *chip, int mtu)
2891baf0facSChris Packham {
2901baf0facSChris Packham 	u16 val;
2911baf0facSChris Packham 	int err;
2921baf0facSChris Packham 
293b92ce2f5SAndrew Lunn 	mtu += ETH_HLEN + ETH_FCS_LEN;
294b92ce2f5SAndrew Lunn 
2951baf0facSChris Packham 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val);
2961baf0facSChris Packham 	if (err)
2971baf0facSChris Packham 		return err;
2981baf0facSChris Packham 
2991baf0facSChris Packham 	val &= ~MV88E6185_G1_CTL1_MAX_FRAME_1632;
3001baf0facSChris Packham 
3011baf0facSChris Packham 	if (mtu > 1518)
3021baf0facSChris Packham 		val |= MV88E6185_G1_CTL1_MAX_FRAME_1632;
3031baf0facSChris Packham 
3041baf0facSChris Packham 	return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val);
3051baf0facSChris Packham }
3061baf0facSChris Packham 
30793e18d61SVivien Didelot /* Offset 0x10: IP-PRI Mapping Register 0
30893e18d61SVivien Didelot  * Offset 0x11: IP-PRI Mapping Register 1
30993e18d61SVivien Didelot  * Offset 0x12: IP-PRI Mapping Register 2
31093e18d61SVivien Didelot  * Offset 0x13: IP-PRI Mapping Register 3
31193e18d61SVivien Didelot  * Offset 0x14: IP-PRI Mapping Register 4
31293e18d61SVivien Didelot  * Offset 0x15: IP-PRI Mapping Register 5
31393e18d61SVivien Didelot  * Offset 0x16: IP-PRI Mapping Register 6
31493e18d61SVivien Didelot  * Offset 0x17: IP-PRI Mapping Register 7
31593e18d61SVivien Didelot  */
31693e18d61SVivien Didelot 
mv88e6085_g1_ip_pri_map(struct mv88e6xxx_chip * chip)31793e18d61SVivien Didelot int mv88e6085_g1_ip_pri_map(struct mv88e6xxx_chip *chip)
31893e18d61SVivien Didelot {
31993e18d61SVivien Didelot 	int err;
32093e18d61SVivien Didelot 
32193e18d61SVivien Didelot 	/* Reset the IP TOS/DiffServ/Traffic priorities to defaults */
32293e18d61SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_0, 0x0000);
32393e18d61SVivien Didelot 	if (err)
32493e18d61SVivien Didelot 		return err;
32593e18d61SVivien Didelot 
32693e18d61SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_1, 0x0000);
32793e18d61SVivien Didelot 	if (err)
32893e18d61SVivien Didelot 		return err;
32993e18d61SVivien Didelot 
33093e18d61SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_2, 0x5555);
33193e18d61SVivien Didelot 	if (err)
33293e18d61SVivien Didelot 		return err;
33393e18d61SVivien Didelot 
33493e18d61SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_3, 0x5555);
33593e18d61SVivien Didelot 	if (err)
33693e18d61SVivien Didelot 		return err;
33793e18d61SVivien Didelot 
33893e18d61SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_4, 0xaaaa);
33993e18d61SVivien Didelot 	if (err)
34093e18d61SVivien Didelot 		return err;
34193e18d61SVivien Didelot 
34293e18d61SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_5, 0xaaaa);
34393e18d61SVivien Didelot 	if (err)
34493e18d61SVivien Didelot 		return err;
34593e18d61SVivien Didelot 
34693e18d61SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_6, 0xffff);
34793e18d61SVivien Didelot 	if (err)
34893e18d61SVivien Didelot 		return err;
34993e18d61SVivien Didelot 
35093e18d61SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_7, 0xffff);
35193e18d61SVivien Didelot 	if (err)
35293e18d61SVivien Didelot 		return err;
35393e18d61SVivien Didelot 
35493e18d61SVivien Didelot 	return 0;
35593e18d61SVivien Didelot }
35693e18d61SVivien Didelot 
35793e18d61SVivien Didelot /* Offset 0x18: IEEE-PRI Register */
35893e18d61SVivien Didelot 
mv88e6085_g1_ieee_pri_map(struct mv88e6xxx_chip * chip)35993e18d61SVivien Didelot int mv88e6085_g1_ieee_pri_map(struct mv88e6xxx_chip *chip)
36093e18d61SVivien Didelot {
36193e18d61SVivien Didelot 	/* Reset the IEEE Tag priorities to defaults */
36293e18d61SVivien Didelot 	return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IEEE_PRI, 0xfa41);
36393e18d61SVivien Didelot }
36493e18d61SVivien Didelot 
mv88e6250_g1_ieee_pri_map(struct mv88e6xxx_chip * chip)365df63b0d9SRasmus Villemoes int mv88e6250_g1_ieee_pri_map(struct mv88e6xxx_chip *chip)
366df63b0d9SRasmus Villemoes {
367df63b0d9SRasmus Villemoes 	/* Reset the IEEE Tag priorities to defaults */
368df63b0d9SRasmus Villemoes 	return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IEEE_PRI, 0xfa50);
369df63b0d9SRasmus Villemoes }
370df63b0d9SRasmus Villemoes 
37133641994SAndrew Lunn /* Offset 0x1a: Monitor Control */
37233641994SAndrew Lunn /* Offset 0x1a: Monitor & MGMT Control on some devices */
37333641994SAndrew Lunn 
mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip * chip,enum mv88e6xxx_egress_direction direction,int port)3745c74c54cSIwan R Timmer int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip,
3755c74c54cSIwan R Timmer 				 enum mv88e6xxx_egress_direction direction,
3765c74c54cSIwan R Timmer 				 int port)
37733641994SAndrew Lunn {
37833641994SAndrew Lunn 	u16 reg;
37933641994SAndrew Lunn 	int err;
38033641994SAndrew Lunn 
381101515c8SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6185_G1_MONITOR_CTL, &reg);
38233641994SAndrew Lunn 	if (err)
38333641994SAndrew Lunn 		return err;
38433641994SAndrew Lunn 
3855c74c54cSIwan R Timmer 	switch (direction) {
3865c74c54cSIwan R Timmer 	case MV88E6XXX_EGRESS_DIR_INGRESS:
3873ee339ebSAndrew Lunn 		reg &= ~MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK;
3885c74c54cSIwan R Timmer 		reg |= port <<
3895c74c54cSIwan R Timmer 		       __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK);
3905c74c54cSIwan R Timmer 		break;
3915c74c54cSIwan R Timmer 	case MV88E6XXX_EGRESS_DIR_EGRESS:
3923ee339ebSAndrew Lunn 		reg &= ~MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK;
3935c74c54cSIwan R Timmer 		reg |= port <<
3945c74c54cSIwan R Timmer 		       __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK);
3955c74c54cSIwan R Timmer 		break;
3965c74c54cSIwan R Timmer 	default:
3975c74c54cSIwan R Timmer 		return -EINVAL;
3985c74c54cSIwan R Timmer 	}
39933641994SAndrew Lunn 
4002fda45f0SMarek Behún 	return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg);
40133641994SAndrew Lunn }
40233641994SAndrew Lunn 
40333641994SAndrew Lunn /* Older generations also call this the ARP destination. It has been
40433641994SAndrew Lunn  * generalized in more modern devices such that more than ARP can
40533641994SAndrew Lunn  * egress it
40633641994SAndrew Lunn  */
mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip * chip,int port)40733641994SAndrew Lunn int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
40833641994SAndrew Lunn {
40933641994SAndrew Lunn 	u16 reg;
41033641994SAndrew Lunn 	int err;
41133641994SAndrew Lunn 
412101515c8SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6185_G1_MONITOR_CTL, &reg);
41333641994SAndrew Lunn 	if (err)
41433641994SAndrew Lunn 		return err;
41533641994SAndrew Lunn 
416101515c8SVivien Didelot 	reg &= ~MV88E6185_G1_MONITOR_CTL_ARP_DEST_MASK;
417101515c8SVivien Didelot 	reg |= port << __bf_shf(MV88E6185_G1_MONITOR_CTL_ARP_DEST_MASK);
41833641994SAndrew Lunn 
419101515c8SVivien Didelot 	return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg);
42033641994SAndrew Lunn }
42133641994SAndrew Lunn 
mv88e6390_g1_monitor_write(struct mv88e6xxx_chip * chip,u16 pointer,u8 data)42233641994SAndrew Lunn static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip,
42333641994SAndrew Lunn 				      u16 pointer, u8 data)
42433641994SAndrew Lunn {
42533641994SAndrew Lunn 	u16 reg;
42633641994SAndrew Lunn 
427101515c8SVivien Didelot 	reg = MV88E6390_G1_MONITOR_MGMT_CTL_UPDATE | pointer | data;
42833641994SAndrew Lunn 
429101515c8SVivien Didelot 	return mv88e6xxx_g1_write(chip, MV88E6390_G1_MONITOR_MGMT_CTL, reg);
43033641994SAndrew Lunn }
43133641994SAndrew Lunn 
mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip * chip,enum mv88e6xxx_egress_direction direction,int port)4325c74c54cSIwan R Timmer int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip,
4335c74c54cSIwan R Timmer 				 enum mv88e6xxx_egress_direction direction,
4345c74c54cSIwan R Timmer 				 int port)
43533641994SAndrew Lunn {
436101515c8SVivien Didelot 	u16 ptr;
43733641994SAndrew Lunn 
4385c74c54cSIwan R Timmer 	switch (direction) {
4395c74c54cSIwan R Timmer 	case MV88E6XXX_EGRESS_DIR_INGRESS:
440101515c8SVivien Didelot 		ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST;
4415c74c54cSIwan R Timmer 		break;
4425c74c54cSIwan R Timmer 	case MV88E6XXX_EGRESS_DIR_EGRESS:
443101515c8SVivien Didelot 		ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST;
4445c74c54cSIwan R Timmer 		break;
4455c74c54cSIwan R Timmer 	default:
4465c74c54cSIwan R Timmer 		return -EINVAL;
4475c74c54cSIwan R Timmer 	}
4485c74c54cSIwan R Timmer 
4492fda45f0SMarek Behún 	return mv88e6390_g1_monitor_write(chip, ptr, port);
45033641994SAndrew Lunn }
45133641994SAndrew Lunn 
mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip * chip,int port)45233641994SAndrew Lunn int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
45333641994SAndrew Lunn {
454101515c8SVivien Didelot 	u16 ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST;
455101515c8SVivien Didelot 
456d8dc2c96SAndrew Lunn 	/* Use the default high priority for management frames sent to
457d8dc2c96SAndrew Lunn 	 * the CPU.
458d8dc2c96SAndrew Lunn 	 */
459d8dc2c96SAndrew Lunn 	port |= MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST_MGMTPRI;
460d8dc2c96SAndrew Lunn 
461101515c8SVivien Didelot 	return mv88e6390_g1_monitor_write(chip, ptr, port);
46233641994SAndrew Lunn }
46333641994SAndrew Lunn 
mv88e6390_g1_set_ptp_cpu_port(struct mv88e6xxx_chip * chip,int port)4649627c981SKurt Kanzenbach int mv88e6390_g1_set_ptp_cpu_port(struct mv88e6xxx_chip *chip, int port)
4659627c981SKurt Kanzenbach {
4669627c981SKurt Kanzenbach 	u16 ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_PTP_CPU_DEST;
4679627c981SKurt Kanzenbach 
4689627c981SKurt Kanzenbach 	/* Use the default high priority for PTP frames sent to
4699627c981SKurt Kanzenbach 	 * the CPU.
4709627c981SKurt Kanzenbach 	 */
4719627c981SKurt Kanzenbach 	port |= MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST_MGMTPRI;
4729627c981SKurt Kanzenbach 
4739627c981SKurt Kanzenbach 	return mv88e6390_g1_monitor_write(chip, ptr, port);
4749627c981SKurt Kanzenbach }
4759627c981SKurt Kanzenbach 
mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip * chip)4766e55f698SAndrew Lunn int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
4776e55f698SAndrew Lunn {
478101515c8SVivien Didelot 	u16 ptr;
4796e55f698SAndrew Lunn 	int err;
4806e55f698SAndrew Lunn 
481989f405aSRasmus Villemoes 	/* 01:80:c2:00:00:00-01:80:c2:00:00:07 are Management */
482989f405aSRasmus Villemoes 	ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C200000XLO;
483101515c8SVivien Didelot 	err = mv88e6390_g1_monitor_write(chip, ptr, 0xff);
4846e55f698SAndrew Lunn 	if (err)
4856e55f698SAndrew Lunn 		return err;
4866e55f698SAndrew Lunn 
487989f405aSRasmus Villemoes 	/* 01:80:c2:00:00:08-01:80:c2:00:00:0f are Management */
488989f405aSRasmus Villemoes 	ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C200000XHI;
489101515c8SVivien Didelot 	err = mv88e6390_g1_monitor_write(chip, ptr, 0xff);
4906e55f698SAndrew Lunn 	if (err)
4916e55f698SAndrew Lunn 		return err;
4926e55f698SAndrew Lunn 
493989f405aSRasmus Villemoes 	/* 01:80:c2:00:00:20-01:80:c2:00:00:27 are Management */
494989f405aSRasmus Villemoes 	ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C200002XLO;
495101515c8SVivien Didelot 	err = mv88e6390_g1_monitor_write(chip, ptr, 0xff);
4966e55f698SAndrew Lunn 	if (err)
4976e55f698SAndrew Lunn 		return err;
4986e55f698SAndrew Lunn 
499989f405aSRasmus Villemoes 	/* 01:80:c2:00:00:28-01:80:c2:00:00:2f are Management */
500989f405aSRasmus Villemoes 	ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C200002XHI;
501101515c8SVivien Didelot 	err = mv88e6390_g1_monitor_write(chip, ptr, 0xff);
502101515c8SVivien Didelot 	if (err)
503101515c8SVivien Didelot 		return err;
504101515c8SVivien Didelot 
505101515c8SVivien Didelot 	return 0;
5066e55f698SAndrew Lunn }
5076e55f698SAndrew Lunn 
508de227387SAndrew Lunn /* Offset 0x1c: Global Control 2 */
509de227387SAndrew Lunn 
mv88e6xxx_g1_ctl2_mask(struct mv88e6xxx_chip * chip,u16 mask,u16 val)51002317e68SVivien Didelot static int mv88e6xxx_g1_ctl2_mask(struct mv88e6xxx_chip *chip, u16 mask,
51102317e68SVivien Didelot 				  u16 val)
51202317e68SVivien Didelot {
51302317e68SVivien Didelot 	u16 reg;
51402317e68SVivien Didelot 	int err;
51502317e68SVivien Didelot 
51602317e68SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL2, &reg);
51702317e68SVivien Didelot 	if (err)
51802317e68SVivien Didelot 		return err;
51902317e68SVivien Didelot 
52002317e68SVivien Didelot 	reg &= ~mask;
52102317e68SVivien Didelot 	reg |= val & mask;
52202317e68SVivien Didelot 
52302317e68SVivien Didelot 	return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL2, reg);
52402317e68SVivien Didelot }
52502317e68SVivien Didelot 
mv88e6185_g1_set_cascade_port(struct mv88e6xxx_chip * chip,int port)52602317e68SVivien Didelot int mv88e6185_g1_set_cascade_port(struct mv88e6xxx_chip *chip, int port)
52702317e68SVivien Didelot {
52802317e68SVivien Didelot 	const u16 mask = MV88E6185_G1_CTL2_CASCADE_PORT_MASK;
52902317e68SVivien Didelot 
53002317e68SVivien Didelot 	return mv88e6xxx_g1_ctl2_mask(chip, mask, port << __bf_shf(mask));
53102317e68SVivien Didelot }
53202317e68SVivien Didelot 
mv88e6085_g1_rmu_disable(struct mv88e6xxx_chip * chip)5339e5baf9bSVivien Didelot int mv88e6085_g1_rmu_disable(struct mv88e6xxx_chip *chip)
5349e5baf9bSVivien Didelot {
5359e5baf9bSVivien Didelot 	return mv88e6xxx_g1_ctl2_mask(chip, MV88E6085_G1_CTL2_P10RM |
5369e5baf9bSVivien Didelot 				      MV88E6085_G1_CTL2_RM_ENABLE, 0);
5379e5baf9bSVivien Didelot }
5389e5baf9bSVivien Didelot 
mv88e6352_g1_rmu_disable(struct mv88e6xxx_chip * chip)5399e5baf9bSVivien Didelot int mv88e6352_g1_rmu_disable(struct mv88e6xxx_chip *chip)
5409e5baf9bSVivien Didelot {
5419e5baf9bSVivien Didelot 	return mv88e6xxx_g1_ctl2_mask(chip, MV88E6352_G1_CTL2_RMU_MODE_MASK,
5429e5baf9bSVivien Didelot 				      MV88E6352_G1_CTL2_RMU_MODE_DISABLED);
5439e5baf9bSVivien Didelot }
5449e5baf9bSVivien Didelot 
mv88e6390_g1_rmu_disable(struct mv88e6xxx_chip * chip)5459e5baf9bSVivien Didelot int mv88e6390_g1_rmu_disable(struct mv88e6xxx_chip *chip)
5469e5baf9bSVivien Didelot {
5479e5baf9bSVivien Didelot 	return mv88e6xxx_g1_ctl2_mask(chip, MV88E6390_G1_CTL2_RMU_MODE_MASK,
5489e5baf9bSVivien Didelot 				      MV88E6390_G1_CTL2_RMU_MODE_DISABLED);
5499e5baf9bSVivien Didelot }
5509e5baf9bSVivien Didelot 
mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip * chip)551de227387SAndrew Lunn int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
552de227387SAndrew Lunn {
553408d2debSVivien Didelot 	return mv88e6xxx_g1_ctl2_mask(chip, MV88E6390_G1_CTL2_HIST_MODE_MASK,
554408d2debSVivien Didelot 				      MV88E6390_G1_CTL2_HIST_MODE_RX |
555408d2debSVivien Didelot 				      MV88E6390_G1_CTL2_HIST_MODE_TX);
556de227387SAndrew Lunn }
557de227387SAndrew Lunn 
mv88e6xxx_g1_set_device_number(struct mv88e6xxx_chip * chip,int index)55823c98919SVivien Didelot int mv88e6xxx_g1_set_device_number(struct mv88e6xxx_chip *chip, int index)
55923c98919SVivien Didelot {
56023c98919SVivien Didelot 	return mv88e6xxx_g1_ctl2_mask(chip,
56123c98919SVivien Didelot 				      MV88E6XXX_G1_CTL2_DEVICE_NUMBER_MASK,
56223c98919SVivien Didelot 				      index);
56323c98919SVivien Didelot }
56423c98919SVivien Didelot 
565de227387SAndrew Lunn /* Offset 0x1d: Statistics Operation 2 */
566de227387SAndrew Lunn 
mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip * chip)567cfd10888SRasmus Villemoes static int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip)
568a605a0feSAndrew Lunn {
56919fb7f69SVivien Didelot 	int bit = __bf_shf(MV88E6XXX_G1_STATS_OP_BUSY);
57019fb7f69SVivien Didelot 
57119fb7f69SVivien Didelot 	return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_STATS_OP, bit, 0);
572a605a0feSAndrew Lunn }
573a605a0feSAndrew Lunn 
mv88e6095_g1_stats_set_histogram(struct mv88e6xxx_chip * chip)57440cff8fcSAndrew Lunn int mv88e6095_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
57540cff8fcSAndrew Lunn {
57640cff8fcSAndrew Lunn 	u16 val;
57740cff8fcSAndrew Lunn 	int err;
57840cff8fcSAndrew Lunn 
57940cff8fcSAndrew Lunn 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STATS_OP, &val);
58040cff8fcSAndrew Lunn 	if (err)
58140cff8fcSAndrew Lunn 		return err;
58240cff8fcSAndrew Lunn 
58340cff8fcSAndrew Lunn 	val |= MV88E6XXX_G1_STATS_OP_HIST_RX_TX;
58440cff8fcSAndrew Lunn 
58540cff8fcSAndrew Lunn 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, val);
58640cff8fcSAndrew Lunn 
58740cff8fcSAndrew Lunn 	return err;
58840cff8fcSAndrew Lunn }
58940cff8fcSAndrew Lunn 
mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip * chip,int port)590a605a0feSAndrew Lunn int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
591a605a0feSAndrew Lunn {
592a605a0feSAndrew Lunn 	int err;
593a605a0feSAndrew Lunn 
594a605a0feSAndrew Lunn 	/* Snapshot the hardware statistics counters for this port. */
59557d1ef38SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP,
59657d1ef38SVivien Didelot 				 MV88E6XXX_G1_STATS_OP_BUSY |
59757d1ef38SVivien Didelot 				 MV88E6XXX_G1_STATS_OP_CAPTURE_PORT |
59857d1ef38SVivien Didelot 				 MV88E6XXX_G1_STATS_OP_HIST_RX_TX | port);
599a605a0feSAndrew Lunn 	if (err)
600a605a0feSAndrew Lunn 		return err;
601a605a0feSAndrew Lunn 
602a605a0feSAndrew Lunn 	/* Wait for the snapshotting to complete. */
603a605a0feSAndrew Lunn 	return mv88e6xxx_g1_stats_wait(chip);
604a605a0feSAndrew Lunn }
605a605a0feSAndrew Lunn 
mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip * chip,int port)606a605a0feSAndrew Lunn int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
607a605a0feSAndrew Lunn {
608a605a0feSAndrew Lunn 	port = (port + 1) << 5;
609a605a0feSAndrew Lunn 
610a605a0feSAndrew Lunn 	return mv88e6xxx_g1_stats_snapshot(chip, port);
611a605a0feSAndrew Lunn }
61279523473SAndrew Lunn 
mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip * chip,int port)61379523473SAndrew Lunn int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
61479523473SAndrew Lunn {
61579523473SAndrew Lunn 	int err;
61679523473SAndrew Lunn 
61779523473SAndrew Lunn 	port = (port + 1) << 5;
61879523473SAndrew Lunn 
61979523473SAndrew Lunn 	/* Snapshot the hardware statistics counters for this port. */
62057d1ef38SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP,
62157d1ef38SVivien Didelot 				 MV88E6XXX_G1_STATS_OP_BUSY |
62257d1ef38SVivien Didelot 				 MV88E6XXX_G1_STATS_OP_CAPTURE_PORT | port);
62379523473SAndrew Lunn 	if (err)
62479523473SAndrew Lunn 		return err;
62579523473SAndrew Lunn 
62679523473SAndrew Lunn 	/* Wait for the snapshotting to complete. */
62779523473SAndrew Lunn 	return mv88e6xxx_g1_stats_wait(chip);
62879523473SAndrew Lunn }
6297f9ef3afSAndrew Lunn 
mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip * chip,int stat,u32 * val)6307f9ef3afSAndrew Lunn void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val)
6317f9ef3afSAndrew Lunn {
6327f9ef3afSAndrew Lunn 	u32 value;
6337f9ef3afSAndrew Lunn 	u16 reg;
6347f9ef3afSAndrew Lunn 	int err;
6357f9ef3afSAndrew Lunn 
6367f9ef3afSAndrew Lunn 	*val = 0;
6377f9ef3afSAndrew Lunn 
63857d1ef38SVivien Didelot 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP,
63957d1ef38SVivien Didelot 				 MV88E6XXX_G1_STATS_OP_BUSY |
64057d1ef38SVivien Didelot 				 MV88E6XXX_G1_STATS_OP_READ_CAPTURED | stat);
6417f9ef3afSAndrew Lunn 	if (err)
6427f9ef3afSAndrew Lunn 		return;
6437f9ef3afSAndrew Lunn 
6447f9ef3afSAndrew Lunn 	err = mv88e6xxx_g1_stats_wait(chip);
6457f9ef3afSAndrew Lunn 	if (err)
6467f9ef3afSAndrew Lunn 		return;
6477f9ef3afSAndrew Lunn 
64857d1ef38SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STATS_COUNTER_32, &reg);
6497f9ef3afSAndrew Lunn 	if (err)
6507f9ef3afSAndrew Lunn 		return;
6517f9ef3afSAndrew Lunn 
6527f9ef3afSAndrew Lunn 	value = reg << 16;
6537f9ef3afSAndrew Lunn 
65457d1ef38SVivien Didelot 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STATS_COUNTER_01, &reg);
6557f9ef3afSAndrew Lunn 	if (err)
6567f9ef3afSAndrew Lunn 		return;
6577f9ef3afSAndrew Lunn 
6587f9ef3afSAndrew Lunn 	*val = value | reg;
6597f9ef3afSAndrew Lunn }
66040cff8fcSAndrew Lunn 
mv88e6xxx_g1_stats_clear(struct mv88e6xxx_chip * chip)66140cff8fcSAndrew Lunn int mv88e6xxx_g1_stats_clear(struct mv88e6xxx_chip *chip)
66240cff8fcSAndrew Lunn {
66340cff8fcSAndrew Lunn 	int err;
66440cff8fcSAndrew Lunn 	u16 val;
66540cff8fcSAndrew Lunn 
66640cff8fcSAndrew Lunn 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STATS_OP, &val);
66740cff8fcSAndrew Lunn 	if (err)
66840cff8fcSAndrew Lunn 		return err;
66940cff8fcSAndrew Lunn 
670a9049ff9SAndrew Lunn 	/* Keep the histogram mode bits */
671a9049ff9SAndrew Lunn 	val &= MV88E6XXX_G1_STATS_OP_HIST_RX_TX;
67240cff8fcSAndrew Lunn 	val |= MV88E6XXX_G1_STATS_OP_BUSY | MV88E6XXX_G1_STATS_OP_FLUSH_ALL;
67340cff8fcSAndrew Lunn 
67440cff8fcSAndrew Lunn 	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, val);
67540cff8fcSAndrew Lunn 	if (err)
67640cff8fcSAndrew Lunn 		return err;
67740cff8fcSAndrew Lunn 
67840cff8fcSAndrew Lunn 	/* Wait for the flush to complete. */
67940cff8fcSAndrew Lunn 	return mv88e6xxx_g1_stats_wait(chip);
68040cff8fcSAndrew Lunn }
681